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:
Jonny007-MKD 2014-08-29 14:55:20 +00:00
parent c181aa857b
commit eb6d28c71b
7 changed files with 228 additions and 223 deletions

View file

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

View file

@ -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,123 +312,126 @@ void GenSysvars()
PutString(" </namespace>\n"); PutString(" </namespace>\n");
PutString(" </namespace>\n"); PutString(" </namespace>\n");
for (long net : gIpNets) PutString(" <namespace name=\"Ethernet\" comment=\"\">\n");
for (long ipN : gIpsSorted)
{ {
byte nett; if ((ipN >> 16) & 0xFF != net) // This IP does not belong to the current net
nett = net; continue;
PutString(" <namespace name=\"Ethernet"); DeviceInit(gIpsSorted[ipN].Vendor);
PutString(nett);
PutString("\" comment=\"Subnet: 192.168.");
PutString(nett);
PutString(".\">\n");
for (long ipN : gIpsSorted) PutString(" <namespace name=\"Client_");
{ switch (NodeNameStyle) // Add the IP bytes depending on the style. Don't break anywhere.
if (((ipN >> 16) & 0xFF) != net) {
continue; case WholeIp:
DeviceInit(gIpsSorted[ipN].Vendor); PutString(gIpsSorted[ipN].Ip1);
PutString(" <namespace name=\"Client_");
if (useThirdIpByteForNames)
{
PutString(gIpsSorted[ipN].IpNet);
PutString("_"); PutString("_");
} case ThreeLastBytes:
PutString(gIpsSorted[ipN].IpLsb); PutString(gIpsSorted[ipN].Ip2);
PutString("\" comment=\"Server with ip address '"); PutString("_");
PutString(gIpsSorted[ipN].Ip); case TwoLastBytes:
PutString("'\">\n"); 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("\" comment=\"Server with ip address '");
PutString(gIpsSorted[ipN].Ip);
PutString("'\">\n");
// Namespace Config // Namespace Config
PutString(" <namespace name=\"Config\" comment=\"Configuration section for this server\">\n"); PutString(" <namespace name=\"Config\" comment=\"Configuration section for this server\">\n");
// IP // 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(" <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(gIpsSorted[ipN].Ip);
PutString("\" />\n"); PutString("\" />\n");
// Intveral // 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(" <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"); PutString(" </namespace>\n");
//Namespace Info //Namespace Info
PutString(" <namespace name=\"Info\" comment=\"Some information about the device\">\n"); PutString(" <namespace name=\"Info\" comment=\"Some information about the device\">\n");
// Vendor // 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(" <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((byte)gIpsSorted[ipN].Vendor);
PutString("\">\n"); PutString("\">\n");
PutString(" <valuetable definesMinMax=\"true\">\n"); PutString(" <valuetable definesMinMax=\"true\">\n");
PutString(" <valuetableentry value=\"2\" description=\"BuR\" />\n"); PutString(" <valuetableentry value=\"2\" description=\"BuR\" />\n");
PutString(" <valuetableentry value=\"23\" description=\"Wago\" />\n"); PutString(" <valuetableentry value=\"23\" description=\"Wago\" />\n");
PutString(" </valuetable>\n"); PutString(" </valuetable>\n");
PutString(" </variable>\n"); PutString(" </variable>\n");
// SerialCode // 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(" <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(gIpsSorted[ipN].SerialCode);
PutString("\" minValue=\"1\" minValuePhys=\"1\" maxValue=\"10000\" maxValuePhys=\"10000\" />\n"); PutString("\" minValue=\"1\" minValuePhys=\"1\" maxValue=\"10000\" maxValuePhys=\"10000\" />\n");
// DeviceCode // 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(" <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(gIpsSorted[ipN].DeviceCode);
PutString("\" minValue=\"1\" minValuePhys=\"1\" maxValue=\"10000\" maxValuePhys=\"10000\" />\n"); PutString("\" minValue=\"1\" minValuePhys=\"1\" maxValue=\"10000\" maxValuePhys=\"10000\" />\n");
// Modules // 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(" <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(gIpsSorted[ipN].DeviceIOs.Modules);
PutString("\" />\n"); PutString("\" />\n");
// InputRegisters // 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(" <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(gIpsSorted[ipN].DeviceIOs.InputRegisters);
PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\""); PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\"");
PutString((word)thisDev.MaxRegisterCount); PutString((word)thisDev.MaxRegisterCount);
PutString("\" maxValuePhys=\""); PutString("\" maxValuePhys=\"");
PutString((word)thisDev.MaxRegisterCount); PutString((word)thisDev.MaxRegisterCount);
PutString("\" />\n"); PutString("\" />\n");
// InputBits // 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(" <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(gIpsSorted[ipN].DeviceIOs.InputBits);
PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\""); PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\"");
PutString((word)thisDev.MaxBitCount); PutString((word)thisDev.MaxBitCount);
PutString("\" maxValuePhys=\""); PutString("\" maxValuePhys=\"");
PutString((word)thisDev.MaxBitCount); PutString((word)thisDev.MaxBitCount);
PutString("\" />\n"); PutString("\" />\n");
// OutputRegisters // 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(" <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(gIpsSorted[ipN].DeviceIOs.OutputRegisters);
PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\""); PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\"");
PutString((word)thisDev.MaxRegisterCount); PutString((word)thisDev.MaxRegisterCount);
PutString("\" maxValuePhys=\""); PutString("\" maxValuePhys=\"");
PutString((word)thisDev.MaxRegisterCount); PutString((word)thisDev.MaxRegisterCount);
PutString("\" />\n"); PutString("\" />\n");
// OutputBits // 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(" <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(gIpsSorted[ipN].DeviceIOs.OutputBits);
PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\""); PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\"");
PutString((word)thisDev.MaxBitCount); PutString((word)thisDev.MaxBitCount);
PutString("\" maxValuePhys=\""); PutString("\" maxValuePhys=\"");
PutString((word)thisDev.MaxBitCount); PutString((word)thisDev.MaxBitCount);
PutString("\" />\n"); PutString("\" />\n");
PutString(" </namespace>\n"); PutString(" </namespace>\n");
// Namespace Data // Namespace Data
PutString(" <namespace name=\"Data\" comment=\"The actual process image\">\n"); PutString(" <namespace name=\"Data\" comment=\"The actual process image\">\n");
// InputRegisters // InputRegisters
PutString(" <variable anlyzLocal=\"2\" readOnly=\"false\" valueSequence=\"false\" unit=\"\" name=\"InputRegisters\" comment=\"The values of the input registers\" bitcount=\"17\" isSigned=\"true\" encoding=\"65001\" type=\"intarray\" arrayLength=\""); PutString(" <variable anlyzLocal=\"2\" readOnly=\"false\" valueSequence=\"false\" unit=\"\" name=\"InputRegisters\" comment=\"The values of the input registers\" bitcount=\"17\" isSigned=\"true\" encoding=\"65001\" type=\"intarray\" arrayLength=\"");
PutString(gIpsSorted[ipN].DeviceIOs.InputRegisters); PutString(gIpsSorted[ipN].DeviceIOs.InputRegisters);
PutString("\" />\n"); PutString("\" />\n");
// InputBits // 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(" <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(gIpsSorted[ipN].DeviceIOs.InputBits);
PutString("\" />\n"); PutString("\" />\n");
// OutputRegisters // 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=\"17\" isSigned=\"true\" encoding=\"65001\" type=\"intarray\" arrayLength=\""); 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=\"17\" isSigned=\"true\" encoding=\"65001\" type=\"intarray\" arrayLength=\"");
PutString(gIpsSorted[ipN].DeviceIOs.OutputRegisters); PutString(gIpsSorted[ipN].DeviceIOs.OutputRegisters);
PutString("\" />\n"); PutString("\" />\n");
// OutputBits // 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(" <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(gIpsSorted[ipN].DeviceIOs.OutputBits);
PutString("\" />\n"); PutString("\" />\n");
PutString(" </namespace>\n"); PutString(" </namespace>\n");
PutString(" </namespace>\n"); PutString(" </namespace>\n");
}
PutString(" </namespace>\n");
} }
PutString(" </namespace>\n"); PutString(" </namespace>\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("_"); PutString(gIpsSorted[ipN].Ip1);
} PutString("_");
PutString(gIpsSorted[ipN].IpLsb); 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("\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();
} }

View file

@ -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();

View file

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