/*@!Encoding:1252*/ includes { #include "include/ModbusUdpClientCommon.cin" #include "include/ModbusFunctions.cin" } variables { struct device { char Ip[16]; char IpLsb[4]; char IpNet[4]; word SerialCode; word DeviceCode; struct deviceIOs DeviceIOs; }; char[16] gIps[long]; char gScanFirstIp[16]; char gScanLastIp[16]; word gScanPort = 502; char fnSysvar[20]; // Filename of Sysvars char fnDbc[20]; // Filename of DBC char name[20]; // Name of project dword ips[50]; // detected IPs file f; byte gIpNets[long]; struct device gIpsSorted[long]; dword gScanFirst, gScanLast; word ADi, ADn, ADl; } on preStart {/* strncpy(gIps[0], "192.168.1.3", 16); strncpy(gIps[2], "192.168.1.4", 16); strncpy(gIps[3], "192.168.1.8", 16);*/ strncpy(gScanFirstIp, "192.168.1.1", 16); strncpy(gScanLastIp, "192.168.1.100", 16); strncpy(name, "Modbus", elCount(name)); strncpy(fnSysvar, "generated.vsysvar", elCount(fnSysvar)); strncpy(fnDbc, "generated.dbc", elCount(fnDbc)); } on start { if (gIps.Size() == 0) DetectDevices(); else MakeIpNets(); } void PutString(file f, char str[]) { f.PutString(str, strlen(str)); } void PutString(file f, word d) { char str[6]; ltoa(d, str, 10); f.PutString(str, strlen(str)); } void PutString(file f, byte d) { char str[4]; ltoa(d, str, 10); f.PutString(str, strlen(str)); } // Step 1: Detect active devices and collect IP addresses /// void DetectDevices() { write("Scanning from %s to %s with timeout of %d ms", gScanFirstIp, gScanLastIp, @sysvar::Config::Modbus::RequestTimeout); gScanFirst = ipGetAddressAsNumber(gScanFirstIp); gScanLast = ipGetAddressAsNumber(gScanLastIp); ModbusConnectTo(gScanFirst, 502); ModbusReadBits(0, 1); } /// void DetectDevicesNext() { // next IP // 0xFE...... --> Skip xxx.xxx.xxx.255 which is broadcast address in 192.168.xxx.0 nets if ((gScanFirst & 0xFFFFFF00) == 0xFEFFFF00) { gScanFirst &= 0x000000FF; gScanFirst += 0x00000001; } else if ((gScanFirst & 0xFFFF0000) == 0xFEFF0000) { gScanFirst &= 0x0000FFF; gScanFirst += 0x00000100; } else if ((gScanFirst & 0xFF000000) == 0xFE000000) { gScanFirst &= 0x00FFFFFF; gScanFirst += 0x00010000; } else { gScanFirst += 0x01000000; } if (gScanFirst == gScanLast) { MakeIpNets(); return; } gRemoteIP = gScanFirst; // Don't open new socket, it takes too much time. ModbusReadBits(0, 1); } /// void OnModbusReadBitsFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap) { DetectDevicesNext(); } /// void OnModbusReadBitsSuccess(struct ModbusResReceiveBits mbr, byte bitStatus[], word numBits) { ipGetAddressAsString(gScanFirst, gIps[gScanFirst], 16); DetectDevicesNext(); } // Step 2: Sort into subnets // Sort the IPs from gIps to gIpsSorted and add their subnet to gIpNets /// void MakeIpNets() { long ipNum; if (gIps.Size() == 0) { stop(); return; } for (long i : gIps) { ipNum = ipGetAddressAsNumber(gIps[i]); // convert IP to dword gIpNets[(ipNum >> 16) & 0xFF] = 1; // add subnet ips[gIpsSorted.size()] = ipNum; // add ip to array strncpy(gIpsSorted[ipNum].IP, gIps[i], 16); // copy to new array ltoa((ipNum >> 16) & 0xFF, gIpsSorted[ipNum].IpNet, 10); // add .IpNet ltoa((ipNum >> 24) & 0xFF, gIpsSorted[ipNum].IpLsb, 10); // add .IpLsb gIps.Remove(i); } AnalyzeDevices(); } // Step 3: Retreive configuration of devices /// void AnalyzeDevices() { ADn = 0; ADi = 0; ADl = gIpsSorted.Size(); write("Analyzing %s...", gIpsSorted[ips[ADi]].Ip); if (gRemoteIP != INVALID_IP) gRemoteIP = ips[ADi]; else ModbusConnectTo(ips[ADi], gRemotePort); ModbusReadRegisters(0x2011, 1); ModbusReadRegisters(0x2012, 1); ModbusReadRegisters(0x2030, 65); ModbusReadRegisters(0x2031, 64); ModbusReadRegisters(0x2032, 64); ModbusReadRegisters(0x2033, 63); } /// void AnalyzeDevicesNext() { if (++ADi >= ADl) // we have analyzed all devices { MakeFiles(); return; } ADn = 0; gRemoteIP = ips[ADi]; write("Analyzing %s...", gIpsSorted[ips[ADi]].Ip); ModbusReadRegisters(0x2011, 1); ModbusReadRegisters(0x2012, 1); ModbusReadRegisters(0x2030, 65); ModbusReadRegisters(0x2031, 64); ModbusReadRegisters(0x2032, 64); ModbusReadRegisters(0x2033, 63); } /// void OnModbusReadRegistersFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap) { switch (error) { case FinalTimeout: writeLineEx(0, 3, "Error while analyzing %s! The device did not respond! Ignoring...", gIpsSorted[ips[ADi]].IP); gQueueAck.Clear(); gQueuePending.Clear(); gQueueSent.Clear(); gIpsSorted.Remove(ips[ADi]); AnalyzeDevicesNext(); break; case Exception: writeLineEx(0, 3, "Error while analyzing %s! The device respond with exception code %d! Ignoring...", gIpsSorted[ips[ADi]].IP, ex); gQueueAck.Clear(); gQueuePending.Clear(); gQueueSent.Clear(); gIpsSorted.Remove(ips[ADi]); AnalyzeDevicesNext(); break; } } /// void OnModbusReadRegistersSuccess(struct ModbusResReceiveRegisters mbr, word numRegs) { byte i; struct ModbusReqRead mbrq; if (!gQueueAck.ContainsKey(mbr.Header.TxID)) return; memcpy_n2h(mbrq, gQueueAck[mbr.Header.TxID].Buffer); switch (mbrq.Address) { case 0x2011: gIpsSorted[ips[ADi]].serialCode = mbr.Data[0]; break; case 0x2012: gIpsSorted[ips[ADi]].deviceCode = mbr.Data[0]; break; case 0x2030: case 0x2031: case 0x2032: case 0x2033: for (i = 0; i < 65; i++) { if (mbr.Data[i] == 0x0000) break; ParseDeviceCode(mbr.Data[i], gIpsSorted[ips[ADi]].DeviceIOs); } break; } if (++ADn == 6) AnalyzeDevicesNext(); } // Step 4: Create the files with the queried data /// void MakeFiles() { GenSysvars(); GenDbc(); stop(); } // Generate the SysVars XML /// void GenSysvars() { write("GenSysvars() -> %s", fnSysvar); f.Open(fnSysvar, 0, 0); // rewrite file in ASCII PutString(f, "\n"); PutString(f, "\n"); PutString(f, " \n"); PutString(f, " \n"); PutString(f, " \n"); PutString(f, " \n"); PutString(f, " \n"); PutString(f, " \n"); PutString(f, " \n"); PutString(f, " \n"); PutString(f, " \n"); PutString(f, " \n"); PutString(f, " \n"); for (long net : gIpNets) { byte nett; nett = net; PutString(f, " \n"); for (long ipN : gIpsSorted) { if (((ipN >> 16) & 0xFF) != net) continue; write("GenSysvars: %s", gIpsSorted[ipN].Ip); PutString(f, " \n"); // Namespace Config PutString(f, " \n"); // IP PutString(f, " \n"); // Intveral PutString(f, " \n"); PutString(f, " \n"); //Namespace Info PutString(f, " \n"); // SerialCode PutString(f, " \n"); // DeviceCode PutString(f, " \n"); // Modules gIpsSorted[ipN].DeviceIOs.Modules[strlen(gIpsSorted[ipN].DeviceIOs.Modules)] = 0; PutString(f, " \n"); // InputRegisters PutString(f, " \n"); // InputBits PutString(f, " \n"); // OutputRegisters PutString(f, " \n"); // OutputBits PutString(f, " \n"); PutString(f, " \n"); // Namespace Data PutString(f, " \n"); // InputRegisters PutString(f, " \n"); // InputBits PutString(f, " \n"); // OutputRegisters PutString(f, " \n"); // OutputBits PutString(f, " \n"); PutString(f, " \n"); PutString(f, " \n"); } PutString(f, " \n"); } PutString(f, " \n"); PutString(f, "\n"); f.Close(); } // Generate the Database /// void GenDbc() { write("GenDbc() -> %s", fnDbc); f.Open(fnDbc, 0, 0); // rewrite file in ASCII PutString(f, "VERSION \"\"\n\n\n"); PutString(f, "NS_ :\n"); PutString(f, " NS_DESC_\n"); PutString(f, " CM_\n"); PutString(f, " BA_DEF_\n"); PutString(f, " BA_\n"); PutString(f, " VAL_\n"); PutString(f, " CAT_DEF_\n"); PutString(f, " CAT_\n"); PutString(f, " FILTER\n"); PutString(f, " BA_DEF_DEF_\n"); PutString(f, " EV_DATA_\n"); PutString(f, " ENVVAR_DATA_\n"); PutString(f, " SGTYPE_\n"); PutString(f, " SGTYPE_VAL_\n"); PutString(f, " BA_DEF_SGTYPE_\n"); PutString(f, " BA_SGTYPE_\n"); PutString(f, " SIG_TYPE_REF_\n"); PutString(f, " VAL_TABLE_\n"); PutString(f, " SIG_GROUP_\n"); PutString(f, " SIG_VALTYPE_\n"); PutString(f, " SIGTYPE_VALTYPE_\n"); PutString(f, " BO_TX_BU_\n"); PutString(f, " BA_DEF_REL_\n"); PutString(f, " BA_REL_\n"); PutString(f, " BA_DEF_DEF_REL_\n"); PutString(f, " BU_SG_REL_\n"); PutString(f, " BU_EV_REL_\n"); PutString(f, " BU_BO_REL_\n"); PutString(f, " SG_MUL_VAL_\n"); PutString(f, "\n"); PutString(f, "BS_:\n"); PutString(f, "\nBU_:"); for (long ipN : gIpsSorted) { write("GenDbc: %s", gIpsSorted[ipN].Ip); PutString(f, " Client_"); //PutString(f, gIpsSorted[ipN].IpNet); //PutString(f, "_"); PutString(f, gIpsSorted[ipN].IpLsb); } PutString(f, "\n\n\n\n"); PutString(f, "BA_DEF_ BU_ \"NodeLayerModules\" STRING ;\n"); PutString(f, "BA_DEF_ \"DBName\" STRING ;\n"); PutString(f, "BA_DEF_ \"BusType\" STRING ;\n"); PutString(f, "BA_DEF_DEF_ \"NodeLayerModules\" \"Ethernet_IL.DLL\";\n"); PutString(f, "BA_DEF_DEF_ \"DBName\" \"\";\n"); PutString(f, "BA_DEF_DEF_ \"BusType\" \"Ethernet\";\n"); PutString(f, "BA_ \"BusType\" \"Ethernet\";\n"); PutString(f, "BA_ \"DBName\" \""); PutString(f, name); PutString(f, "\";\n"); f.Close(); } void OnModbusWriteBitFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){} void OnModbusWriteRegisterFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){} void OnModbusWriteMasksFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){} void OnModbusReadWriteRegistersFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){} void OnModbusWriteBitsFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){} void OnModbusWriteRegistersFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){} void OnModbusWriteBitSuccess(struct ModbusResConfirmSingle mbc){} void OnModbusWriteRegisterSuccess(struct ModbusResConfirmSingle mbc){} void OnModbusWriteBitsSuccess(struct ModbusResConfirmMultiple mbc){} void OnModbusWriteRegistersSuccess(struct ModbusResConfirmMultiple mbc){} void OnModbusWriteMasksSuccess(struct ModbusResConfirmMasks mbc){}