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*/
includes
{
}
variables
{
}
on sysvar sysvar::Airbus::ESS_DC1
{
if (@this)

View File

@ -8,25 +8,25 @@ includes
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 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 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
char fnSysvar[100]; // Filename of Sysvars
char fnDbc[100]; // Filename of DBC
dword ips[50]; // detected IPs. We need this array for enumeration with integers (assoc. arrays cannot be enumerated 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"
dword gScanCurr, gScanLast; // The first and last IP address as dword
word ADi, ADn, ADl; // Some variables for AnalyzeDevices() (event driven, so global)
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
byte ggMaxTransmissionCount; // temp var for gMaxTransmissionCount
enum eNodeName {WholeIP, LastByte, TwoLastBytes, ThreeLastBytes}
enum eNodeName NodeNameStyle; // The style of the node name
}
on preStart
@ -35,25 +35,23 @@ on preStart
// 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.1.255", elCount(gScanLastIp));
// Whether the third byte of the IP address shall be used in the node name
useThirdIpByteForNames = 0;
// How the Node name shall be formatted
// 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
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));
strncpy(fnSysvar, "include/SysVars/Modbus.vsysvar", elCount(fnSysvar));
strncpy(fnDbc, "include/DBC/Modbus.dbc", elCount(fnDbc));
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);
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 :)
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
ModbusReadBits(0, 1); // Start device detection
}
@ -107,46 +105,43 @@ void DetectDevices()
/// <Step1>
void DetectDevicesNext()
{
gScanFirst = swapDWord(gScanFirst);
gScanFirst++;
if (skip255 && (gScanFirst & 0xFF) == 0xFF) // skip .255
gScanCurr = swapDWord(gScanCurr); // Swap to increment
gScanCurr++; // Increment
if ((gScanCurr & 0xFF) == 0xFF) // If .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 (skip255) // If we shall skip .255
gScanCurr++;
writeLineEx(0, 0, "%d.%d.%d.%d ", gScanCurr >> 24, (gScanCurr >> 16) & 0xFF, (gScanCurr >> 8) & 0xFF, gScanCurr & 0xFF);
}
if (gScanFirst > gScanLast)
if (gScanCurr > gScanLast) // If we are beyond the last ip address
{
@sysvar::Config::Modbus::MaxTransmissionCount = ggMaxTransmissionCount;
MakeIpNets();
@sysvar::Config::Modbus::MaxTransmissionCount = ggMaxTransmissionCount; // reset
MakeIpNets(); // Continue with Step 2
return;
}
gScanFirst = swapDWord(gScanFirst);
gScanCurr = swapDWord(gScanCurr); // Swap back
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
}
/// <Step1>
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>
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
}
// 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>
void MakeIpNets()
{
@ -159,16 +154,17 @@ void MakeIpNets()
return;
}
for (long i : gIps) // Go through all devices
for (long i : gIps) // Iterate 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
ltoa((ipNum ) & 0xFF, gIpsSorted[ipNum].Ip1, 10); // set .Ip1
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);
}
@ -182,7 +178,7 @@ void MakeIpNets()
void AnalyzeDevices()
{
// Init counters
ADn = 1; // expect 10 responses
ADn = 1; // expect 1 response
ADi = 0; // First IP address
ADl = gIpsSorted.Size();
@ -203,17 +199,19 @@ void AnalyzeDevices()
/// <Step3>
void AnalyzeDevicesNext()
{
if (strlen(gIpsSorted[ips[ADi]].DeviceIOs.Modules) > 0)
gIpsSorted[ips[ADi]].DeviceIOs.Modules[strlen(gIpsSorted[ips[ADi]].DeviceIOs.Modules)-1] = 0;
// clean up the string of the previous devices
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);
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
return;
}
ADn = 1; // expect 10 responses
ADn = 1; // expect 1 response again
gRemoteIP = ips[ADi]; // Next IP address
writeLineEx(0, 1, "Analyzing %s", gIpsSorted[ips[ADi]].Ip);
// request something special to get the vendor
@ -226,12 +224,10 @@ void OnModbusReadRegistersFailed(enum ModbusRequestError error, enum ModbusExcep
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
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;
// 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);
break;
case Timeout:
return; // Timeout is unimportant, it means the request will be resent
case FinalTimeout:
writeLineEx(0, 3, "Error while analyzing %s! The device did not respond! Ignoring...", gIpsSorted[ips[ADi]].IP);
break;
@ -261,7 +259,7 @@ void OnModbusReadRegistersFailed(enum ModbusRequestError error, enum ModbusExcep
/// <Step3>
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;
@ -270,10 +268,11 @@ void OnModbusReadRegistersSuccess(struct ModbusResReceiveRegisters mbres, struct
return;
}
// else parse the received data
_DeviceParseRegister(gIpsSorted[ips[ADi]], mbreq.Address, mbres.Data, mbreq.Count);
if (--ADn == 0) // If we received all registers
AnalyzeDevicesNext();
if (--ADn == 0) // If we received all registers
AnalyzeDevicesNext(); // Continue with the next device
}
// Step 4: Create the files with the queried data
@ -313,123 +312,126 @@ void GenSysvars()
PutString(" </namespace>\n");
PutString(" </namespace>\n");
for (long net : gIpNets)
PutString(" <namespace name=\"Ethernet\" comment=\"\">\n");
for (long ipN : gIpsSorted)
{
byte nett;
nett = net;
PutString(" <namespace name=\"Ethernet");
PutString(nett);
PutString("\" comment=\"Subnet: 192.168.");
PutString(nett);
PutString(".\">\n");
if ((ipN >> 16) & 0xFF != net) // This IP does not belong to the current net
continue;
DeviceInit(gIpsSorted[ipN].Vendor);
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(" <namespace name=\"Client_");
switch (NodeNameStyle) // Add the IP bytes depending on the style. Don't break anywhere.
{
case WholeIp:
PutString(gIpsSorted[ipN].Ip1);
PutString("_");
}
PutString(gIpsSorted[ipN].IpLsb);
PutString("\" comment=\"Server with ip address '");
PutString(gIpsSorted[ipN].Ip);
PutString("'\">\n");
case ThreeLastBytes:
PutString(gIpsSorted[ipN].Ip2);
PutString("_");
case TwoLastBytes:
PutString(gIpsSorted[ipN].Ip3);
PutString("_");
case LastByte:
PutString(gIpsSorted[ipN].Ip4);
return;
default:
writeDbg(MbError, "The NodeNameStyle %d is unknown, please use a value of the enum!", NodeNameStyle);
runError(1001, 0);
break;
}
PutString("\" 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 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 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=\"17\" 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=\"17\" 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");
// 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=\"17\" 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=\"17\" 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(" </namespace>\n");
}
PutString(" </namespace>\n");
@ -482,12 +484,25 @@ void GenDbc()
for (long ipN : gIpsSorted)
{
PutString(" Client_");
if (useThirdIpByteForNames)
{
PutString(gIpsSorted[ipN].IpNet);
PutString("_");
}
PutString(gIpsSorted[ipN].IpLsb);
switch (NodeNameStyle) // Add the IP bytes depending on the style. Don't break anywhere.
{
case WholeIp:
PutString(gIpsSorted[ipN].Ip1);
PutString("_");
case ThreeLastBytes:
PutString(gIpsSorted[ipN].Ip2);
PutString("_");
case TwoLastBytes:
PutString(gIpsSorted[ipN].Ip3);
PutString("_");
case LastByte:
PutString(gIpsSorted[ipN].Ip4);
break;
default:
writeDbg(MbError, "The NodeNameStyle %d is unknown, please use a value of the enum!", NodeNameStyle);
runError(1001, 0);
return;
}
}
PutString("\n\n\n\n");
PutString("BA_DEF_ BU_ \"NodeLayerModules\" STRING ;\n");
@ -497,9 +512,7 @@ void GenDbc()
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");
PutString("BA_ \"DBName\" \"Modbus\";\n");
f.Close();
}

View File

@ -1,7 +1,7 @@
/*@!Encoding:1252*/
// 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.
includes
@ -27,9 +27,9 @@ on preStart
on start
{
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);
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
return;
ModbusReadOutBits(thisDev.Addr.Read.OutputBits, @sysvar::%BUS_TYPE%%CHANNEL%::%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
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%::%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
setTimerCyclic(gtRead, 1, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Config::Interval);
if (@sysvar::%BUS_TYPE%::%NODE_NAME%::Config::Interval > 0) // Start the polling timer
setTimerCyclic(gtRead, 1, @sysvar::%BUS_TYPE%::%NODE_NAME%::Config::Interval);
}
// Stop all transactions and close connection
@ -72,10 +72,10 @@ void OnModbusReadBitsFailed(enum ModbusRequestError error, enum ModbusException
case NotSent:
break;
case FinalTimeout:
sysBeginVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "InputBits");
for (i = 0; i < @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::InputBits; i++)
@sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::InputBits[i] = -1;
sysEndVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "InputBits");
sysBeginVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "InputBits");
for (i = 0; i < @sysvar::%BUS_TYPE%::%NODE_NAME%::Info::InputBits; i++)
@sysvar::%BUS_TYPE%::%NODE_NAME%::Data::InputBits[i] = -1;
sysEndVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "InputBits");
break;
default:
writeDbg(MbError, "OnModbusReadBitsFailed: Unkown error: %d", error);
@ -96,10 +96,10 @@ void OnModbusReadRegistersFailed(enum ModbusRequestError error, enum ModbusExcep
case NotSent:
break;
case FinalTimeout:
sysBeginVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "InputRegisters");
for (i = 0; i < @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::InputRegisters; i++)
@sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::InputRegisters[i] = -1;
sysEndVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "InputRegisters");
sysBeginVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "InputRegisters");
for (i = 0; i < @sysvar::%BUS_TYPE%::%NODE_NAME%::Info::InputRegisters; i++)
@sysvar::%BUS_TYPE%::%NODE_NAME%::Data::InputRegisters[i] = -1;
sysEndVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "InputRegisters");
break;
default:
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
{
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
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;
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
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;
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
{
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
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;
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
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;
default:
@ -250,38 +250,38 @@ void OnModbusClientPanics(enum FatalErrors reason)
// The timer will continuously poll the input registers and intput bits
on timer gtRead
{
ModbusReadRegisters(thisDev.Addr.Read.InputRegisters, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::InputRegisters);
ModbusReadBits(thisDev.Addr.Read.InputBits, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::InputBits);
ModbusReadRegisters(thisDev.Addr.Read.InputRegisters, @sysvar::%BUS_TYPE%::%NODE_NAME%::Info::InputRegisters);
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
on sysvar %BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::OutputBits
on sysvar %BUS_TYPE%::%NODE_NAME%::Data::OutputBits
{
word count, i;
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[]
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
}
// 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 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[]
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
}
// 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)
gtRead.Cancel();

View File

@ -53,8 +53,10 @@ variables
struct device // A structure that contains information about an Modbus device. Used in MakeConfig.
{
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 IpNet[4]; // String: The second last byte of the IP. Used as index of net
char Ip4[4]; // String: The last byte of the IP address.
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)
word SerialCode; // Serial Code
word DeviceCode; // Device Code