From 93dd56469d78f5754482a44bcfc2d85b088dcc3c Mon Sep 17 00:00:00 2001 From: Jonny007-MKD Date: Tue, 17 Jun 2014 14:21:45 +0000 Subject: [PATCH] ModbusClientCommon.cin Introduced loops to automatically split requests that are too large for Modbus ModbusClient.can Modified Modbus events so that the split requests (see above) will be written at the correct position in sys vars ModbusFunctions.cin DeviceInformation.cin Introduced new file that will handle most device specific things ModbusStructs.cin Introduced new constants with maximum Modbus values MakeConfig.can Increment IP address with swapDWord Moved detection stuff to DeviceInformation.cin --- Modbus-CAPL/MakeConfig.cfg | 45 +-- Modbus-CAPL/ModbusNet.cfg | 68 +++-- Modbus-CAPL/include/CAPL/MakeConfig.can | 232 +++----------- Modbus-CAPL/include/CAPL/ModbusClient.can | 102 +++---- .../CAPL/include/DeviceInformation.cin | 285 ++++++++++++++++++ .../CAPL/include/ModbusClientCommon.cin | 279 ++++++++++------- .../include/CAPL/include/ModbusFunctions.cin | 72 ----- .../include/CAPL/include/ModbusStructs.cin | 24 +- Modbus-CAPL/include/DBC/MakeConfig.ini | 2 +- Modbus-CAPL/include/SysVars/generated.vsysvar | 70 ++--- 10 files changed, 648 insertions(+), 531 deletions(-) create mode 100644 Modbus-CAPL/include/CAPL/include/DeviceInformation.cin delete mode 100644 Modbus-CAPL/include/CAPL/include/ModbusFunctions.cin diff --git a/Modbus-CAPL/MakeConfig.cfg b/Modbus-CAPL/MakeConfig.cfg index c3ea76a..859bc73 100644 --- a/Modbus-CAPL/MakeConfig.cfg +++ b/Modbus-CAPL/MakeConfig.cfg @@ -1,4 +1,4 @@ -;CANoe Version |4|7|1|35745 MakeConfig +;CANoe Version |4|7|1|52148 MakeConfig Version: 8.2.40 Build 40 32 PRO 5 @@ -13,10 +13,10 @@ VGlobalParameters 2 Begin_Of_Object 20 0 3,100,200,500 -1000000 1.000000 1 1000 1 1 0 0 1 1 1 0 0 0 1 0 0 0 +1000000 1.000000 0 1000 1 1 0 0 1 1 1 0 0 0 1 0 0 0 1 0 -0 1 +0 0 ResetSignalsOnMeasurementStart=1 VDatabaseContainerStreamer 3 Begin_Of_Object 5 @@ -642,7 +642,7 @@ Begin_Of_Multi_Line_String Copyright (c) 2001-2006 Actipro Software LLC. All rights reserved. http://www.ActiproSoftware.com/Products/DotNet/ ---> +--> End_Of_Serialized_Data 3 End_Of_Object VDesktop 3 0 @@ -659,7 +659,7 @@ VUniqueBox 4 Begin_Of_Object VBoxRoot 5 Begin_Of_Object 1 3 -0 2 0 1 -1 -1 -1 -1 22 22 1522 983 +0 2 0 1 -1 -1 -1 -1 -227 39 1073 1000 1 @@ -678,7 +678,7 @@ END_OF_DOCK_INFO 1582 856 END_OF_DESKTOP_DATA 6 -0 1 -1 -1 -1 -1 22 22 1522 983 +0 1 -1 -1 -1 -1 -227 39 1073 1000 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 -1 32767 0 0 0 0 0 0 0 0 0 0 -1 -1 0 0 0 0 0 0 END_OF_DOCK_INFO 0 @@ -686,7 +686,7 @@ END_OF_DOCK_INFO 0 0 1 -999 592 +1188 696 END_OF_DESKTOP_DATA END_OF_DESKTOP_DATA_COLLECTION 0 @@ -2516,7 +2516,7 @@ VUniqueBox 16 Begin_Of_Object VBoxRoot 17 Begin_Of_Object 1 1 -1 1 0 1 -1 -1 -1 -1 0 339 1188 688 +1 1 0 1 -1 -1 -1 -1 0 285 1188 634 1 @@ -2535,7 +2535,7 @@ END_OF_DOCK_INFO 999 591 END_OF_DESKTOP_DATA 6 -0 1 -1 -1 -1 -1 0 339 1188 688 +0 1 -1 -1 -1 -1 0 285 1188 634 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 -1 32767 0 0 0 0 0 0 0 0 0 0 -1 -1 0 0 0 0 0 0 END_OF_DOCK_INFO 1 @@ -2543,7 +2543,7 @@ END_OF_DOCK_INFO 0 0 1 -1188 696 +1188 634 END_OF_DESKTOP_DATA END_OF_DESKTOP_DATA_COLLECTION 0 @@ -2894,7 +2894,7 @@ VUniqueBox 4 Begin_Of_Object VBoxRoot 5 Begin_Of_Object 1 3 -0 0 0 1 -1 -1 -1 -1 0 0 1188 338 +0 0 0 1 -1 -1 -1 -1 0 0 1188 284 1 @@ -2913,7 +2913,7 @@ END_OF_DOCK_INFO 803 901 END_OF_DESKTOP_DATA 6 -0 1 -1 -1 -1 -1 0 0 1188 338 +0 1 -1 -1 -1 -1 0 0 1188 284 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 -1 32767 0 0 0 0 0 0 0 0 0 0 -1 -1 0 0 0 0 0 0 END_OF_DOCK_INFO 1 @@ -2921,7 +2921,7 @@ END_OF_DOCK_INFO 0 0 1 -1188 696 +1188 634 END_OF_DESKTOP_DATA END_OF_DESKTOP_DATA_COLLECTION 0 @@ -2961,7 +2961,7 @@ End_Of_Object VGrMnBox 3 VDOLocalInfoStruct 3 Begin_Of_Object 3 1 -83 +92 VDAOBus 4 Begin_Of_Object 1 1 @@ -3024,7 +3024,7 @@ EOF_ASSEMBLYDATA 1 "include\CAPL\MakeConfig.cbf" VIPBStackSetting 8 Begin_Of_Object 3 -0 +1 1 VIPBAdapterSetting 9 Begin_Of_Object 4 @@ -3075,7 +3075,7 @@ End_Of_Serialized_Data 7 End_Of_Object VProgrammedNode 7 0 0 -Startdelay 0 0 0 +Startdelay 1 0 10 Jitter 0 0 1 0 0 0 0 1 1 ETHERNET_IL.DLL @@ -3091,7 +3091,7 @@ VSimulinkModelViewerConfiguration 7 Begin_Of_Object End_Of_Object VSimulinkModelViewerConfiguration 7 1 0 -3530245935 +2517525802 0 NodeSignalPanelBustypeCount 0 End_Of_Object VSimulationNode 6 @@ -3129,7 +3129,7 @@ NULL End_Of_Object VDOLocalInfoStruct 3 0.000000 0 0 -1 1 0 59420 1 233 1 2882400001 98 331 309 611 2882400002 0 0 0 0 0 0 1 2882400001 1270 1270 311 311 2882400002 0 0 0 1664573080 0 0 3 +1 1 0 59420 1 233 1 2882400001 98 331 371 619 2882400002 0 0 0 0 0 0 1 2882400001 1270 1270 373 373 2882400002 0 0 0 339969840 0 409869284 3 SS_BEGIN_COMMON_INFO 1 0 @@ -3141,7 +3141,7 @@ Ethernet 11 1 1 -7573328 1 0 1 0 0 1 0 0 0 2000 1 +340356552 1 0 1 0 0 1 0 0 71 2000 1 SS_BEGIN_COMMON_INFO 1 3 @@ -3190,7 +3190,7 @@ END_OF_DOCK_INFO END_OF_DESKTOP_DATA 6 0 1 -1 -1 0 0 0 700 662 1043 -6 1 1010 180 0 0 300 180 300 180 0 61440 1 12180 1904 0 0 0 0 260 0 0 0 -1 -1 32767 0 59422 0 0 0 0 0 0 0 1 10 0 0 1 201 0 59419 1 +6 1 1010 180 0 0 300 180 300 180 0 61440 1 12180 1904 0 0 0 0 260 0 0 0 -1 -1 32767 0 59422 0 0 0 0 0 0 0 1 10 0 0 1 263 0 59419 1 END_OF_DOCK_INFO 1 1 @@ -3564,6 +3564,9 @@ End FiltersEnd 0 0 + + + END_OF_WORKSPACE_MEMBER_DATA END_OF_WORKSPACE_MEMBER 1 @@ -3684,7 +3687,7 @@ VIPBGlobalSettings 2 Begin_Of_Object 1 VIPBStackSetting 3 Begin_Of_Object 3 -0 +1 1 VIPBAdapterSetting 4 Begin_Of_Object 4 diff --git a/Modbus-CAPL/ModbusNet.cfg b/Modbus-CAPL/ModbusNet.cfg index 5be2b34..4e806df 100644 --- a/Modbus-CAPL/ModbusNet.cfg +++ b/Modbus-CAPL/ModbusNet.cfg @@ -1,4 +1,4 @@ -;CANoe Version |4|7|1|55201 ModbusNet +;CANoe Version |4|7|1|38816 ModbusNet Version: 8.2.40 Build 40 32 PRO 10 @@ -67,6 +67,7 @@ DialogBegin 1 285 569 816 1103 SymbolExplorerDialogBegin + 1 HistoryBegin 1 0 @@ -745,9 +746,11 @@ Begin_Of_Multi_Line_String kPersistNoLineBreak ey="{28077F35-C142-4ACC-B040-1BF0AB026C11}" Guid="ac9be154-bd12-4ff9-b255-03e05277dbe2" DockedSize="201, 281" FloatingLocation="111, 442" FloatingSize="1192, 514" HasOptions="False" ImageIndex="-1" Text="Trace" TitleBarText="Trace"> +Window Key="{49714911-9568-49CC-A9CE-3B0905658C4A}" Guid="db27ffca-d17e-40f0-a70b-be70fe5eb4ec" State="DockableInsideHost" DockedSize="381, 0" FloatingLocation="1151, 79" FloatingSize="300, 180"> End_Of_Serialized_Data 3 End_Of_Object VDesktop 3 VDesktop 3 Begin_Of_Object @@ -1192,7 +1195,7 @@ End_Of_Serialized_Data 15 End_Of_Object VPredefinedSignalObject 15 [MeasurementObject] Eth 1::Rx Bus load -"%" 1 800080 0. 100. -100. 100. 10 -5 0 0 36000000 0 1 0 0 +"%" 1 800080 0. 100. -100. 100. 10 -5 0 0 36000000 1 1 0 0 VPredefinedSignalObject 15 Begin_Of_Object 1 VHostSignal 16 Begin_Of_Object @@ -1243,7 +1246,7 @@ End_Of_Serialized_Data 15 End_Of_Object VPredefinedSignalObject 15 [MeasurementObject] Eth 1::Tx Bus load -"%" 1 80 0. 100. -100. 100. 10 -5 0 0 36000000 0 1 0 0 +"%" 1 80 0. 100. -100. 100. 10 -5 0 0 36000000 1 1 0 0 VPredefinedSignalObject 15 Begin_Of_Object 1 VHostSignal 16 Begin_Of_Object @@ -1379,7 +1382,7 @@ End_Of_Serialized_Data 15 End_Of_Object VSysVarObject 15 [MeasurementObject] Client_2::InputBits_[0] -"" 223 b86b8 -1. 1. -100. 100. 1 0 0 0 36000000 1 1 0 0 +"" 223 b86b8 -1. 1. -100. 100. 1 0 0 0 36000000 0 1 0 0 VSysVarObject 15 Begin_Of_Object 1 VHostSignal 16 Begin_Of_Object @@ -1413,7 +1416,7 @@ End_Of_Serialized_Data 15 End_Of_Object VSysVarObject 15 [MeasurementObject] Client_2::InputBits_[1] -"" 223 d7ff -1. 1. -100. 100. 1 0 0 0 36000000 1 1 0 0 +"" 223 d7ff -1. 1. -100. 100. 1 0 0 0 36000000 0 1 0 0 VSysVarObject 15 Begin_Of_Object 1 VHostSignal 16 Begin_Of_Object @@ -1447,7 +1450,7 @@ End_Of_Serialized_Data 15 End_Of_Object VSysVarObject 15 [MeasurementObject] Client_3::InputBits_[5] -"" 223 9314ff 0. 1. -100. 100. 1 0 0 0 36000000 1 1 0 0 +"" 223 9314ff 0. 1. -100. 100. 1 0 0 0 36000000 0 1 0 0 VSysVarObject 15 Begin_Of_Object 1 VHostSignal 16 Begin_Of_Object @@ -1481,7 +1484,7 @@ End_Of_Serialized_Data 15 End_Of_Object VSysVarObject 15 [MeasurementObject] Client_2::InputRegisters_[0] -"" 223 ff00 2746. 6071. -100. 100. 500 0 0 0 36000000 1 1 0 0 +"" 223 ff00 2746. 6071. -100. 100. 500 0 0 0 36000000 0 1 0 0 VSysVarObject 15 Begin_Of_Object 1 VHostSignal 16 Begin_Of_Object @@ -1515,9 +1518,9 @@ End_Of_Serialized_Data 15 End_Of_Object VSysVarObject 15 [MeasurementObject] Client_3::InputRegisters_[3] -"" 223 228b22 8987. 19894. -100. 100. 1000 0 0 0 36000000 1 1 0 0 +"" 223 228b22 8987. 19894. -100. 100. 1000 0 0 0 36000000 0 1 0 0 [GraphWindow:x_x_x_x_x_x_WindowBk_Grid_AxisBk_XAxisFr_YAxisFr_x_x_x_x_x_x] -5210346.6428800002 5634098.14585 240215.71337000001 200000 36000000 1 ffffff b2b2b2 ffffff 0 0 0 0 1 1 1 0 +0 423751.50296999997 423751.50296999997 200000 36000000 1 ffffff b2b2b2 ffffff 0 0 0 0 1 1 1 0 0 30 5000 0 0 100 @@ -1528,7 +1531,7 @@ Client_3::InputRegisters_[3] 0 1 41943040 -8 +1 1416 25200245 Grafik-Fenster 1 "" @@ -1773,7 +1776,7 @@ End_Of_Object VTraceAnalysisSingleFilter 17 1 End_Of_Object VTraceAnalysisFilterGroup 16 End_Of_Object VTraceFilterCfg 15 -1 +0 1 0 0 @@ -1796,7 +1799,7 @@ End_Of_Serialized_Data 14 6 1 14 -ver=2: FT TF TF FF FT FF;F T Config;F T Ethernet1;F T GLLogger;T F _Statistics +ver=2: FT TF TF FT FT FT;F T Config;F T Ethernet1;F T GLLogger;T F _Statistics End_Of_Serialized_Data 14 7 0 @@ -1837,29 +1840,29 @@ End_Of_Serialized_Data 14 22 1 14 -ver=2: FF +ver=2: FT End_Of_Serialized_Data 14 23 1 14 -ver=2: FF +ver=2: FT End_Of_Serialized_Data 14 24 1 14 -ver=2: FF +ver=2: FT End_Of_Serialized_Data 14 25 0 26 1 14 -ver=2: FF +ver=2: FT End_Of_Serialized_Data 14 27 1 14 -ver=2: FF +ver=2: FT End_Of_Serialized_Data 14 0 2 @@ -3734,7 +3737,7 @@ End_Of_Serialized_Data 14 0 0 290 -1 +0 160 1 "" End_Of_Object VTraceControlCfg 14 @@ -4471,7 +4474,7 @@ End_Of_Serialized_Data 14 End_Of_Object VSysVarObject 14 [Begin_of_Item] 2 18 -1 1 10 0 0 16777215 +1 1 3 0 0 16777215 0 1000 0 0 [End_of_Item] VSysVarObject 14 Begin_Of_Object @@ -4543,7 +4546,7 @@ End_Of_Serialized_Data 14 End_Of_Object VSysVarObject 14 [Begin_of_Item] 2 17 -1 1 2 0 0 16777215 +1 1 3 0 0 16777215 0 1000 0 0 [End_of_Item] VSysVarObject 14 Begin_Of_Object @@ -4879,7 +4882,7 @@ END_OF_DOCK_INFO 0 0 1 -0 1 -32088 -32000 -1 -1 147 402 1041 893 +0 1 -1 -1 -1 -1 -117 402 777 893 0 1 776 389 @@ -4933,7 +4936,7 @@ End_Of_Object VGrMnBox 3 VDOLocalInfoStruct 3 Begin_Of_Object 3 1 -218 +228 VDAOBus 4 Begin_Of_Object 1 1 @@ -5045,7 +5048,7 @@ End_Of_Object VIPBStackSetting 8 NDebugger::VDebuggerHost 8 Begin_Of_Object 2 0 -26 +27 NDebugger::VFile 9 Begin_Of_Object 1 1 "ModbusTcpCommon.cin" @@ -5176,6 +5179,11 @@ NDebugger::VFile 9 Begin_Of_Object 1 "include\CAPL\include\ModbusStructs.cin" 42 End_Of_Object NDebugger::VFile 9 +NDebugger::VFile 9 Begin_Of_Object +1 + 1 "include\CAPL\include\DeviceInformation.cin" +43 +End_Of_Object NDebugger::VFile 9 VNETStandaloneComponent 9 Begin_Of_Object 1 VNETControlBox 10 Begin_Of_Object @@ -5409,7 +5417,7 @@ VSimulinkModelViewerConfiguration 7 Begin_Of_Object End_Of_Object VSimulinkModelViewerConfiguration 7 1 0 -3569770309 +2097296340 0 NodeSignalPanelBustypeCount 0 End_Of_Object VSimulationNode 6 @@ -5544,7 +5552,7 @@ VSimulinkModelViewerConfiguration 7 Begin_Of_Object End_Of_Object VSimulinkModelViewerConfiguration 7 1 0 -3569770309 +2097296340 0 NodeSignalPanelBustypeCount 0 End_Of_Object VSimulationNode 6 @@ -5803,7 +5811,7 @@ NULL End_Of_Object VDOLocalInfoStruct 3 0.000000 0 0 -1 1 0 59420 1 176 1 2882400001 243 443 430 885 2882400002 0 0 0 0 0 20 1 2882400001 1121 1321 432 632 2882400002 0 0 0 0 0 0 3 +1 1 0 59420 1 176 1 2882400001 -21 179 430 885 2882400002 0 0 0 0 0 20 1 2882400001 857 1057 432 632 2882400002 0 0 0 0 0 0 3 SS_BEGIN_COMMON_INFO 1 0 @@ -6217,14 +6225,14 @@ SymbSelHeaderMgrBegin SymbSelHeaderMgrEnd End Begin -3 0 -1 +3 8 16 3 Modbus modbus Systemvariablen - ( 3 ( 0 ) 0 ) + ( 3 ( 1 ( 3 ( 0 ) 0 ) 0 ) 0 ) SymbSelHeaderMgrBegin 1 4 0 1 200 0 0 diff --git a/Modbus-CAPL/include/CAPL/MakeConfig.can b/Modbus-CAPL/include/CAPL/MakeConfig.can index 5987596..de2422b 100644 --- a/Modbus-CAPL/include/CAPL/MakeConfig.can +++ b/Modbus-CAPL/include/CAPL/MakeConfig.can @@ -1,23 +1,12 @@ /*@!Encoding:1252*/ includes { + #include "include/DeviceInformation.cin" #include "include/ModbusUdpClientCommon.cin" - #include "include/ModbusFunctions.cin" } variables { - struct device // A structure that contains information about an Modbus device - { - 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 - enum Vendor Vendor; // The Vendor (Wago / B&R) - word SerialCode; // Serial Code - word DeviceCode; // Device Code - struct deviceIOs DeviceIOs; // A structure with more information about IOs - }; - 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. @@ -46,10 +35,10 @@ on preStart strncpy(gIps[3], "192.168.1.8", 16); */ - // Scan a range of IPs for devices. Start and Stop go here - // Please note: Currently .255 will be skipped! Don't use it for devices and as stop address + // 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 it for devices strncpy(gScanFirstIp, "192.168.1.2", 16); - strncpy(gScanLastIp, "192.168.1.10", 16); + strncpy(gScanLastIp, "192.168.1.20", 16); // Name of the project strncpy(name, "Modbus", elCount(name)); @@ -58,7 +47,7 @@ on preStart strncpy(fnSysvar, "include/SysVars/generated.vsysvar", elCount(fnSysvar)); strncpy(fnDbc, "include/DBC/generated.dbc", elCount(fnDbc)); - OutputDebugLevel = Mute; + OutputDebugLevel = Error; } on start @@ -99,10 +88,10 @@ 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); + gScanFirst = ipGetAddressAsNumber(gScanFirstIp); // We have to use big endian here + gScanLast = swapDWord(ipGetAddressAsNumber(gScanLastIp)); // But not here :) - write("%d.%d.%d.%d ", gScanFirst & 0xFF, (gScanFirst >> 8) & 0xFF, (gScanFirst >> 16) & 0xFF, gScanFirst >> 24); + writeLineEx(0, 0, "%d.%d.%d.%d ", gScanFirst & 0xFF, (gScanFirst >> 8) & 0xFF, (gScanFirst >> 16) & 0xFF, gScanFirst >> 24); ModbusConnectTo(gScanFirst, @sysvar::Config::Modbus::Port); // Open socket and set variables ModbusReadBits(0, 1); // Start device detection } @@ -110,52 +99,36 @@ void DetectDevices() /// void DetectDevicesNext() { - // next IP - // Note: IP address is stored as big endian, comments are notated as little endian :) - // 0xFE...... --> Skip xxx.xxx.xxx.255 which is broadcast address in 192.168.xxx.0 nets - - // If first three bytes are full (123.255.255.255), set those to 0 and increment the first byte (124.0.0.0) - if ((gScanFirst & 0xFFFFFF00) == 0xFEFFFF00) + gScanFirst = swapDWord(gScanFirst); + gScanFirst++; + if ((gScanFirst & 0xFF) == 0xFF) // .255 { - gScanFirst &= 0x000000FF; - gScanFirst += 0x00000001; - write("%d.%d.%d.%d ", gScanFirst & 0xFF, (gScanFirst >> 8) & 0xFF, (gScanFirst >> 16) & 0xFF, gScanFirst >> 24); - } - // If first two bytes are full (124.111.255.255), set those to 0 and increment the second byte (124.112.0.0) - else if ((gScanFirst & 0xFFFF0000) == 0xFEFF0000) - { - gScanFirst &= 0x0000FFF; - gScanFirst += 0x00000100; - write("%d.%d.%d.%d ", gScanFirst & 0xFF, (gScanFirst >> 8) & 0xFF, (gScanFirst >> 16) & 0xFF, gScanFirst >> 24); - } - // If first last byte is full (124.112.222.255), set it to 0 and increment the third byte (124.112.223.0) - else if ((gScanFirst & 0xFF000000) == 0xFE000000) - { - gScanFirst &= 0x00FFFFFF; - gScanFirst += 0x00010000; - write("%d.%d.%d.%d ", gScanFirst & 0xFF, (gScanFirst >> 8) & 0xFF, (gScanFirst >> 16) & 0xFF, gScanFirst >> 24); - } - // Else simply increment the LSB - else - { - gScanFirst += 0x01000000; + gScanFirst++; + writeLineEx(0, 0, "%d.%d.%d.%d ", gScanFirst >> 24, (gScanFirst >> 16) & 0xFF, (gScanFirst >> 8) & 0xFF, gScanFirst & 0xFF); } - if (gScanFirst == gScanLast) // If this is the last address we stop the detection + if (gScanFirst > gScanLast) { @sysvar::Config::Modbus::MaxTransmissionCount = gMaxTransmissionCount; MakeIpNets(); return; } - writeEx(1, 1, "."); // Write something so the user knows something is happening + gScanFirst = swapDWord(gScanFirst); + + writeEx(0, 0, "."); // Write something so the user knows something is happening gRemoteIP = gScanFirst; // Don't open new socket, it takes too much time. This means we should use UDP here! ModbusReadBits(0, 1); // Scan the next device } /// void OnModbusReadBitsFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap) { - DetectDevicesNext(); // Timeout! We will go to the next device + switch (error) + { + case FinalTimeout: + case Exception: + DetectDevicesNext(); // Timeout! We will go to the next device + } } /// void OnModbusReadBitsSuccess(struct ModbusResReceiveBits mbres, byte bitStatus[], struct ModbusReqRead mbreq) @@ -250,21 +223,11 @@ void OnModbusReadRegistersFailed(enum ModbusRequestError error, enum ModbusExcep 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 + if (mbreq.Address == 0x1000 && ex == IllegalDataAddress) // We requested Wago SerialCode and it didn't work --> Not Wago --> B&R. Not future proof { gIpsSorted[ips[ADi]].Vendor = Wago; // request information - ADn = 10; - ModbusReadRegisters(0x2011, 1); // Serial Code - ModbusReadRegisters(0x2012, 1); // Device Code - ModbusReadRegisters(0x1022, 1); // Number of AOs (= size in bits) - ModbusReadRegisters(0x1023, 1); // Number of AIs (= size in bits) - ModbusReadRegisters(0x1024, 1); // Number of DOs - ModbusReadRegisters(0x1025, 1); // Number of DIs - ModbusReadRegisters(0x2030, 65); // Connected IO 1 - ModbusReadRegisters(0x2031, 64); // Connected IO 2 - ModbusReadRegisters(0x2032, 64); // Connected IO 3 - ModbusReadRegisters(0x2033, 63); // Connected IO 4 + ADn = DeviceGetInformation(Wago); return; } @@ -283,83 +246,16 @@ void OnModbusReadRegistersFailed(enum ModbusRequestError error, enum ModbusExcep /// void OnModbusReadRegistersSuccess(struct ModbusResReceiveRegisters mbres, struct ModbusReqRead mbreq) { - byte i; - if (mbreq.Address == 0x1000) // We detected a B&R device { gIpsSorted[ips[ADi]].Vendor = BuR; // request further information - ADn = 5; - ModbusReadRegisters(0x1083, 1); // Product Code - ModbusReadRegisters(0x1101, 1); // Number of AIs - ModbusReadRegisters(0x1103, 1); // Number of AOs - ModbusReadRegisters(0x1105, 1); // Number of DIs - ModbusReadRegisters(0x1107, 1); // Number of DOs + ADn = DeviceGetInformation(BuR); return; } - switch (gIpsSorted[ips[ADi]].Vendor) - { - case Wago: - // Parse the received data - switch (mbreq.Address) - { - case 0x2011: - gIpsSorted[ips[ADi]].serialCode = mbres.Data[0]; - break; - case 0x2012: - gIpsSorted[ips[ADi]].deviceCode = mbres.Data[0]; - break; - case 0x1022: - gIpsSorted[ips[ADi]].DeviceIOs.OutputRegisters = mbres.Data[0] / 16; - break; - case 0x1023: - gIpsSorted[ips[ADi]].DeviceIOs.InputRegisters = mbres.Data[0] / 16; - break; - case 0x1024: - gIpsSorted[ips[ADi]].DeviceIOs.OutputBits = mbres.Data[0]; - break; - case 0x1025: - gIpsSorted[ips[ADi]].DeviceIOs.InputBits = mbres.Data[0]; - break; - case 0x2030: - case 0x2031: - case 0x2032: - case 0x2033: - for (i = 0; i < mbreq.Count; i++) - { - if (mbres.Data[i] == 0x0000) // No more devices --> end - break; - ParseDeviceCode(mbres.Data[i], gIpsSorted[ips[ADi]].Vendor, gIpsSorted[ips[ADi]].DeviceIOs); - } - break; - } - break; - case BuR: - // Parse the received data - switch (mbreq.Address) - { - case 0x1083: - gIpsSorted[ips[ADi]].serialCode = mbres.Data[0]; - break; - case 0x1101: - gIpsSorted[ips[ADi]].DeviceIOs.InputRegisters = mbres.Data[0] - 3; // X20BC0087 has 3 AIs when no module is connected... hö? - break; - case 0x1103: - gIpsSorted[ips[ADi]].DeviceIOs.OutputRegisters = mbres.Data[0]; - break; - case 0x1105: - gIpsSorted[ips[ADi]].DeviceIOs.InputBits = mbres.Data[0] * 8; // Unfortunately this is quite imprecise: - // in the process image one module will always fill a whole number of bytes. - // So 4 12DI modules not allocate not 4*12 bit = 6 byte, but 4*16 bit = 64 bit = 8 byte - break; - case 0x1107: - gIpsSorted[ips[ADi]].DeviceIOs.OutputBits = mbres.Data[0] * 8; - break; - } - break; - } + DeviceParseRegister(gIpsSorted[ips[ADi]], mbreq.Address, mbres.Data, mbreq.Count); if (--ADn == 0) // If we received all registers AnalyzeDevicesNext(); @@ -414,9 +310,9 @@ void GenSysvars() for (long ipN : gIpsSorted) { - if (((ipN >> 16) & 0xFF) != net) continue; + DeviceInit(gIpsSorted[ipN].Vendor); PutString(" \n"); - } - else - { - PutString((word)2048); - PutString("\" maxValuePhys=\""); - PutString((word)2048); - PutString("\" />\n"); - } + PutString((word)gDevRegMaxCount); + PutString("\" maxValuePhys=\""); + PutString((word)gDevRegMaxCount); + PutString("\" />\n"); // InputBits PutString(" \n"); - } - else - { - PutString((word)16384); - PutString("\" maxValuePhys=\""); - PutString((word)16384); - PutString("\" />\n"); - } + PutString((word)gDevBitMaxCount); + PutString("\" maxValuePhys=\""); + PutString((word)gDevBitMaxCount); + PutString("\" />\n"); // OutputRegisters PutString(" \n"); - } - else - { - PutString((word)2048); - PutString("\" maxValuePhys=\""); - PutString((word)2048); - PutString("\" />\n"); - } + PutString((word)gDevRegMaxCount); + PutString("\" maxValuePhys=\""); + PutString((word)gDevRegMaxCount); + PutString("\" />\n"); // OutputBits PutString(" \n"); - } - else - { - PutString((word)16384); - PutString("\" maxValuePhys=\""); - PutString((word)16384); - PutString("\" />\n"); - } + PutString((word)gDevBitMaxCount); + PutString("\" maxValuePhys=\""); + PutString((word)gDevBitMaxCount); + PutString("\" />\n"); PutString(" \n"); // Namespace Data diff --git a/Modbus-CAPL/include/CAPL/ModbusClient.can b/Modbus-CAPL/include/CAPL/ModbusClient.can index 881e738..078d912 100644 --- a/Modbus-CAPL/include/CAPL/ModbusClient.can +++ b/Modbus-CAPL/include/CAPL/ModbusClient.can @@ -3,6 +3,7 @@ includes { #include "include\ModbusUdpClientCommon.cin" + #include "include\DeviceInformation.cin" } variables @@ -10,51 +11,20 @@ variables msTimer gtRead; } -// Get information of local network interface such like ip address - on preStart { writeClear(0); setStartdelay(10); - OutputDebugLevel = Warning; + OutputDebugLevel = MbDebug; } on start { - word outputBits, outputRegs, outputBitAddr, outputRegAddr; - - outputBits = @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::OutputBits; - outputRegs = @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::OutputRegisters; - - switch ((enum Vendor)@sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::Vendor) - { - case Wago: - outputBitAddr = 0x200; - outputRegAddr = 0x200; - break; - case BuR: - outputBitAddr = 0x000; - outputRegAddr = 0x800; - break; - } - + DeviceInit(@sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::Vendor); ModbusInit(); - while (outputBits > 0) - { - ModbusReadOutBits(outputBitAddr, 2000); - outputBits -= 2000; - } - if (outputBits > 0) - ModbusReadOutBits(outputBitAddr, outputBits); - - while (outputRegs > 0) - { - ModbusReadRegisters(outputRegAddr, 123); - outputRegs -= 123; - } - if (outputRegs > 0) - ModbusReadRegisters(outputRegAddr, outputRegs); + ModbusReadOutBits(gDevOutputBitAddr, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::OutputBits); + ModbusReadOutRegisters(gDevOutputRegAddr, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::OutputRegisters); setTimerCyclic(gtRead, 1, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Config::Interval); } @@ -121,20 +91,28 @@ void OnModbusWriteRegistersFailed(enum ModbusRequestError error, enum ModbusExce void OnModbusReadBitsSuccess(struct ModbusResReceiveBits mbres, byte bitStatus[], struct ModbusReqRead mbreq) { - word i; + word i, offset; - switch(mbreq.Address) + switch (mbres.Header.FuncCode) // We assume that we separate between 0x01 and 0x02 even though the address space may be the same { - case 0x200: // set output bits + case 0x01: // Read output bits sysBeginVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "OutputBits"); - for (i = 0; i < @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::OutputBits; i++) - @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::OutputBits[i] = bitStatus[i]; + + offset = mbreq.Address - gDevOutputBitAddr; // 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]; + sysEndVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "OutputBits"); break; - default: // set input bits + + + case 0x02: // Read input bits 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] = bitStatus[i]; + + offset = mbreq.Address - gDevInputBitAddr; // 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]; + sysEndVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "InputBits"); break; } @@ -142,29 +120,30 @@ void OnModbusReadBitsSuccess(struct ModbusResReceiveBits mbres, byte bitStatus[] void OnModbusReadRegistersSuccess(struct ModbusResReceiveRegisters mbres, struct ModbusReqRead mbreq) { - char str[20*5]; - long fehler; - byte i; + word i, offset; - switch (mbreq.Address) + switch (mbres.Header.FuncCode) // We assume that we separate between 0x03 and 0x04 even though the address space may be the same { - case 0x200: // set output registers + case 0x03: // Read output registers sysBeginVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "OutputRegisters"); - for (i = 0; i < @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::OutputRegisters; i++) - @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::OutputRegisters[i] = mbres.Data[i]; + + offset = mbreq.Address - gDevOutputRegAddr; // 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]; + sysEndVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "OutputRegisters"); break; - case 0x000: // set input registers + + + case 0x04: // Read input registers 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] = mbres.Data[i]; + + offset = mbreq.Address - gDevInputRegAddr; // 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]; + sysEndVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "InputRegisters"); break; - default: - // Not recognized - dbin_to_strhex(mbres.Data, str); - writeLineEx(0, 1, "<%NODE_NAME%> OnModbusReceiveRegisters: Received %d bytes at 0x%04X: %s", mbres.ByteCount, mbreq.Address, str); - break; } } @@ -204,10 +183,9 @@ void OnModbusClientPanics(enum FatalErrors reason) // Key events ------------------------------------------------------------------------- on timer gtRead { - if (@sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::InputRegisters > 0) - ModbusReadRegisters(0x0000, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::InputRegisters); - if (@sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::InputBits > 0) - ModbusReadBits(0x0000, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::InputBits); + ModbusReadRegisters(0x0000, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::InputRegisters); + ModbusReadBits(0x0000, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::InputBits); + this.Cancel(); } on sysvar %BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::OutputBits diff --git a/Modbus-CAPL/include/CAPL/include/DeviceInformation.cin b/Modbus-CAPL/include/CAPL/include/DeviceInformation.cin new file mode 100644 index 0000000..019694e --- /dev/null +++ b/Modbus-CAPL/include/CAPL/include/DeviceInformation.cin @@ -0,0 +1,285 @@ +/*@!Encoding:1252*/ +variables +{ + word gDevOutputBitAddr, gDevOutputRegAddr; + word gDevInputBitAddr, gDevInputRegAddr; + word gDevBitMaxCount, gDevRegMaxCount; + word gDevReceiveWindow; + + enum Vendor + { + Wago = 23, + BuR = 2 + }; + struct deviceIOs + { + byte InputRegisters; + word InputBits; + byte OutputRegisters; + word OutputBits; + char Modules[1024]; + }; + struct device // A structure that contains information about an Modbus device + { + 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 + enum Vendor Vendor; // The Vendor (Wago / B&R) + word SerialCode; // Serial Code + word DeviceCode; // Device Code + struct deviceIOs DeviceIOs; // A structure with more information about IOs + }; +} + +// This is for the normal client and for making the sysvars +/// +void DeviceInit(byte vendor) +{ + switch ((enum Vendor) vendor) + { + case Wago: + gDevInputBitAddr = 0x0000; // Wago inputs start at 0x000 + gDevInputRegAddr = 0x0000; + gDevOutputBitAddr = 0x0200; // Wago outputs start at 0x200 + gDevOutputRegAddr = 0x0200; + gDevBitMaxCount = 0x0100; // Wago allows up to 256 inputs + gDevRegMaxCount = 0x0100; + gDevReceiveWindow = 5; // Wago can handle 5 requests simultaneously + break; + case BuR: + gDevInputBitAddr = 0x0000; // B&R inputs start at 0x000 + gDevInputRegAddr = 0x0000; + gDevOutputBitAddr = 0x0000; // B&R digital outputs start at 0x000 + gDevOutputRegAddr = 0x0800; // B&R analog outputs start at 0x800 + gDevBitMaxCount = 0x4000; // B&R allows up to 16348 digital inputs + gDevRegMaxCount = 0x0800; // B&R allows up to 2048 analog inputs + gDevReceiveWindow = 1; // B&R can only handle 1 request at a time + break; + } +} + + + +// This is for making the sysvars (MakeConfig) +/// +void DeviceParseCode(word dev, enum Vendor vendor, struct deviceIOs dios) +{ + byte input; + byte numChannels; + char module[10]; + + switch(vendor) + { + case Wago: // if this is a Wago device + if (dev & 0x8000) // Digital Module + { + numChannels = (dev >> 8) & 0x007F; + + if (dev & 0x0001) // Input Module + { + input = 1; + strncpy(module, "DI%d,", elCount(module)); + } + else if (dev & 0x0002) // Output Module + { + input = 0; + strncpy(module, "DO%d,", elCount(module)); + } + else // mhm. What is it? + { + writeDbg(AlgoError, "ParseDeviceCode: Device code 0x%X cannot be decoded", dev); + OnModbusClientPanics(DeviceCodeUnknown); + } + } + else + { + // http://www.wago.com/wagoweb/documentation/navigate/nm0dx__d.htm + // http://www.wago.com/wagoweb/documentation/navigate/nm0dy__d.htm + switch (dev) + { + case 881: // devices that have no inputs/outputs + return; + case 491: // devices that have 1 inputs + input = 1; + numChannels = 1; + break; + case 452: // devices that have 2 inputs + case 465: + case 470: + case 472: + case 480: + case 454: + case 473: + case 474: + case 466: + case 484: + case 485: + case 492: + case 482: + case 475: + case 467: + case 477: + case 478: + case 456: + case 479: + case 476: + case 483: + case 461: + case 481: + case 462: + case 469: + case 487: + input = 1; + numChannels = 2; + break; + case 493: // devices that have 3 inputs + case 494: + case 495: + input = 1; + numChannels = 3; + break; + case 459: // devices that have 4 inputs + case 453: + case 455: + case 468: + case 457: + case 464: + case 460: + case 463: + input = 1; + numChannels = 4; + break; + case 552: // devices that have 2 inputs + case 585: + case 563: + case 554: + case 550: + case 560: + case 562: + case 556: + input = 0; + numChannels = 2; + case 555: // devices that have 4 inputs + case 553: + case 557: + case 559: + input = 0; + numChannels = 4; + default: // unknown device. Ouch! + writeDbg(AlgoInfo, "Connected device: 750-%d", dev); + return; + } + if (input) + strncpy(module, "AI%d,", elCount(module)); + else + strncpy(module, "AO%d,", elCount(module)); + } + break; // switch(vendor) + default: + writeDbg(AlgoError, "ParseDeviceCode: Unknown vendor id: %d", vendor); + OnModbusClientPanics(VendorIdUnknown); + return; + } + + snprintf(module, elCount(module), module, numChannels); + strncat(dios.Modules, module, elCount(dios.Modules)); +} + +// This function requests more information from the device and return the number of expected results +/// +byte DeviceGetInformation(enum Vendor vendor) +{ + switch (vendor) + { + case Wago: + ModbusReadRegisters(0x2011, 1); // Serial Code + ModbusReadRegisters(0x2012, 1); // Device Code + ModbusReadRegisters(0x1022, 1); // Number of AOs (= size in bits) + ModbusReadRegisters(0x1023, 1); // Number of AIs (= size in bits) + ModbusReadRegisters(0x1024, 1); // Number of DOs + ModbusReadRegisters(0x1025, 1); // Number of DIs + ModbusReadRegisters(0x2030, 65); // Connected IO 1 + ModbusReadRegisters(0x2031, 64); // Connected IO 2 + ModbusReadRegisters(0x2032, 64); // Connected IO 3 + ModbusReadRegisters(0x2033, 63); // Connected IO 4 + return 10; + case BuR: + ModbusReadRegisters(0x1083, 1); // Product Code + ModbusReadRegisters(0x1101, 1); // Number of AIs + ModbusReadRegisters(0x1103, 1); // Number of AOs + ModbusReadRegisters(0x1105, 1); // Number of DIs + ModbusReadRegisters(0x1107, 1); // Number of DOs + return 5; + } + return 0; +} + +// This function parses the received registers +/// +void DeviceParseRegister(struct device device, word address, word data[], word count) +{ + byte i; + + switch (device.Vendor) + { + case Wago: + // Parse the received data + switch (address) + { + case 0x2011: + device.serialCode = data[0]; + break; + case 0x2012: + device.deviceCode = data[0]; + break; + case 0x1022: + device.DeviceIOs.OutputRegisters = data[0] / 16; // Wago returns the size in bits allocated by the module + break; + case 0x1023: + device.DeviceIOs.InputRegisters = data[0] / 16; + break; + case 0x1024: + device.DeviceIOs.OutputBits = data[0]; + break; + case 0x1025: + device.DeviceIOs.InputBits = data[0]; + break; + case 0x2030: + case 0x2031: + case 0x2032: + case 0x2033: + for (i = 0; i < count; i++) + { + if (data[i] == 0x0000) // No more devices --> end + break; + DeviceParseCode(data[i], device.Vendor, device.DeviceIOs); + } + break; + } + break; + case BuR: + // Parse the received data + switch (address) + { + case 0x1083: + device.serialCode = data[0]; + break; + case 0x1101: + device.DeviceIOs.InputRegisters = data[0]; + break; + case 0x1103: + device.DeviceIOs.OutputRegisters = data[0]; + break; + case 0x1105: + device.DeviceIOs.InputBits = data[0] * 8; // Unfortunately this is quite imprecise: + // in the process image one module will always fill a whole number of bytes. + // So 4 12DI modules not allocate not 4*12 bit = 6 byte, but 4*16 bit = 64 bit = 8 byte + // See Modbus X20BC0087 documentation v1.11 p. 22 + break; + case 0x1107: + device.DeviceIOs.OutputBits = data[0] * 8; + break; + } + break; + } +} \ No newline at end of file diff --git a/Modbus-CAPL/include/CAPL/include/ModbusClientCommon.cin b/Modbus-CAPL/include/CAPL/include/ModbusClientCommon.cin index 7189d5b..af2d93d 100644 --- a/Modbus-CAPL/include/CAPL/include/ModbusClientCommon.cin +++ b/Modbus-CAPL/include/CAPL/include/ModbusClientCommon.cin @@ -7,8 +7,6 @@ includes variables { - const word gMaxPacketLength = __size_of(struct ModbusReqWriteRegisters); - msTimer gtRobin; // Timer that sends the packets and watches for timeouts word gTxID = 0x0000; // Transaction Identifier for Modbus. Used as index for gQueue @@ -18,7 +16,7 @@ variables word TimeoutTicks; byte Timeouts; word Length; - byte Buffer[gMaxPacketLength]; + byte Buffer[gModbusMaxTelegramSize]; }; struct QueueElement gQueuePending[long, 2]; struct QueueElement gQueueSent[long, 2]; @@ -48,49 +46,58 @@ void ModbusInit() ModbusConnectTo(ip, @sysvar::Config::Modbus::Port); } -void ModbusMakeHeader(struct ModbusApHeader mbap, word length) +void ModbusMakeHeader(struct ModbusApHeader mbap, word length, byte funcCode) { mbap.TxID = gTxID++; // [2] Transaction ID mbap.Protocol = 0x0000; // [2] Protocol ID = 0 = Modbus mbap.Length = length - __offset_of(struct ModbusApHeader, UnitID); // [2] Length; Number of bytes following mbap.UnitID = 0xFF; // [1] Unit identifier; not relevant + mbap.FuncCode = funcCode; // [1] Function Code } // REGION: ModbusReadBits ------------------------------------------------------------- /// -void ModbusReadInBits(word address, word count) +void ModbusReadInBits(word address, long count) { ModbusReadBits(0x02, address, count); } /// -void ModbusReadBits(word address, word count) +void ModbusReadBits(word address, long count) { ModbusReadBits(0x02, address, count); } /// -void ModbusReadOutBits(word address, word count) +void ModbusReadOutBits(word address, long count) { ModbusReadBits(0x01, address, count); } /// -void ModbusReadBits(byte funcCode, word address, word count) +void ModbusReadBits(byte funcCode, word address, long count) { const byte length = __size_of(struct ModbusReqRead); byte buffer[length]; - struct ModbusReqRead mbr; + word curCount; + struct ModbusReqRead mbreq; - ModbusMakeHeader(mbr.Header, length); - // Payload - mbr.Header.FuncCode = funcCode; // [1] Function Code; 1: Read Coils (DI), 2: Read Discret Inputs (DIO), seems to be the same for WAGO 750-881 - mbr.Address = address; // [2] Start address - mbr.Count = count; // [2] Number of items; 1:max 2000=0x7D0 + // FC1: Read Coils (DO), FC2: Read Discret Inputs (DI) + while (count > 0) + { + curCount = count > gMaxBitsPerRead ? gMaxBitsPerRead : count; + ModbusMakeHeader(mbreq.Header, length, funcCode); - writeDbg(MbDebug, "Sending 'Read Bits' (0x01) command. Addr: 0x%04X, Count: %d", address, count); - - memcpy_h2n(buffer, mbr); - ModbusSend(buffer, length, mbr.Header.TxID); + mbreq.Address = address; // [2] Start address + mbreq.Count = curCount; // [2] Number of items; 1:max 2000=0x7D0 + + writeDbg(MbDebug, "Sending 'Read Bits' (0x01) command. TxID: 0x%04X, Addr: 0x%04X, Count: %d", mbreq.Header.TxID, address, curCount); + + memcpy_h2n(buffer, mbreq); + ModbusSend(buffer, length, mbreq.Header.TxID); + + count -= gMaxBitsPerRead; + address += gMaxBitsPerRead; + } } /// @@ -98,7 +105,7 @@ void OnModbusReceiveBits(byte buffer[]) { struct ModbusResReceiveBits mbres; struct ModbusReqRead mbreq; - byte bitStatus[1968]; + byte bitStatus[gMaxBitsPerRead]; word numBits; byte i, j; @@ -106,7 +113,6 @@ void OnModbusReceiveBits(byte buffer[]) memcpy_n2h(mbreq, gQueueAck[mbres.Header.TxID].Buffer); writeDbg(MbInfo, "Received %d bits from 0x%04X", mbreq.Count, mbreq.Address); - for (i = 0; i < mbres.ByteCount; i++) { for (j = 0; j < 8; j++) @@ -131,23 +137,45 @@ void OnModbusReceiveBitsException(struct ModbusApHeader mbap, enum ModbusExcepti // REGION: ModbusReadRegisters ------------------------------------------------------- /// -void ModbusReadRegisters(word address, word count) // 16 bit +void ModbusReadInRegisters(word address, long count) +{ + ModbusReadRegisters(0x04, address, count); +} +/// +void ModbusReadRegisters(word address, long count) +{ + ModbusReadRegisters(0x04, address, count); +} +/// +void ModbusReadOutRegisters(word address, long count) +{ + ModbusReadRegisters(0x03, address, count); +} +/// +void ModbusReadRegisters(byte funcCode, word address, long count) { const byte length = __size_of(struct ModbusReqRead); - const byte funcCode = 0x03; byte buffer[length]; - struct ModbusReqRead mbr; - - ModbusMakeHeader(mbr.Header, length); - // Payload - mbr.Header.FuncCode = funcCode; // [1] Function Code; 3: Read Holding Registers (AI), 4: Read Input Registers (AIO), seems to be the same for WAGO 750-881 - mbr.Address = address; // [2] Start address - mbr.Count = count; // [2] Number of items; 1:max 125=0x7D + word curCount; + struct ModbusReqRead mbreq; - writeDbg(MbDebug, "Sending 'Read Registers' (0x03) command. Addr: 0x%04X, Count: %d", address, count); + // FC3: Read Holding Registers (AO), FC4: Read Input Registers (AI) + while (count > 0) + { + curCount = count > gMaxRegsPerRead ? gMaxRegsPerRead : count; + ModbusMakeHeader(mbreq.Header, length, funcCode); - memcpy_h2n(buffer, mbr); - ModbusSend(buffer, length, mbr.Header.TxID); + mbreq.Address = address; // [2] Start address + mbreq.Count = curCount; // [2] Number of items; 1:max 125=0x7D + + writeDbg(MbDebug, "Sending 'Read Registers' (0x03) command. TxID: 0x%04X, Addr: 0x%04X, Count: %d", mbreq.Header.TxID, address, curCount); + + memcpy_h2n(buffer, mbreq); + ModbusSend(buffer, length, mbreq.Header.TxID); + + count -= gMaxRegsPerRead; + address += gMaxRegsPerRead; + } } /// @@ -182,21 +210,21 @@ void ModbusWriteBit(word address, byte value) const byte length = __size_of(struct ModbusReqWriteSingle); const byte funcCode = 0x05; // B&R does not support 0x06 byte buffer[length]; - struct ModbusReqWriteSingle mbw; + struct ModbusReqWriteSingle mbreq; if (value >= 1) value = 0xFF; - ModbusMakeHeader(mbw.Header, length); - // Payload - mbw.Header.FuncCode = funcCode; // [1] Function Code; 5: Write Single Coil (DO) - mbw.Address = address; // [2] Output address - mbw.Value = value << 8; // [2] Output value (0x0000: Off, 0xFF00: On) + // FC5: Write Single Coil (DO) + ModbusMakeHeader(mbreq.Header, length, funcCode); - writeDbg(Debug, "Sending 'Write Bit' (0x05) command. Addr: 0x%04X, Value: 0x%02X", address, value); + mbreq.Address = address; // [2] Output address + mbreq.Value = value << 8; // [2] Output value (0x0000: Off, 0xFF00: On) + + writeDbg(Debug, "Sending 'Write Bit' (0x05) command. TxID: 0x%04X, Addr: 0x%04X, Value: %d", mbreq.Header.TxID, address, value); - memcpy_h2n(buffer, mbw); - ModbusSend(buffer, length, mbw.Header.TxID); + memcpy_h2n(buffer, mbreq); + ModbusSend(buffer, length, mbreq.Header.TxID); } /// @@ -224,23 +252,23 @@ void OnModbusConfirmBitException(struct ModbusApHeader mbap, enum ModbusExceptio // REGION: ModbusWriteRegister ------------------------------------------------------ /// -void ModbusWriteRegister(word address, int value) +void ModbusWriteRegister(word address, word value) { const byte length = __size_of(struct ModbusReqWriteSingle); const byte funcCode = 0x06; byte buffer[length]; - struct ModbusReqWriteSingle mbw; + struct ModbusReqWriteSingle mbreq; - ModbusMakeHeader(mbw.Header, length); - // Payload - mbw.Header.FuncCode = funcCode; // [1] Function Code; 5: Write Single Register (AO) - mbw.Address = address; // [2] Output address - mbw.Value = value; // [2] Output value + // 5: Write Single Register (AO) + ModbusMakeHeader(mbreq.Header, length, funcCode); - writeDbg(MbDebug, "Sending 'Write Register' (0x06) command. Addr: 0x%04X, Value: 0x%02X", address, value); + mbreq.Address = address; // [2] Output address + mbreq.Value = value; // [2] Output value - memcpy_h2n(buffer, mbw); - ModbusSend(buffer, length, mbw.Header.TxID); + writeDbg(MbDebug, "Sending 'Write Register' (0x06) command. TxID: 0x%04X, Addr: 0x%04X, Value: %d", mbreq.Header.TxID, address, value); + + memcpy_h2n(buffer, mbreq); + ModbusSend(buffer, length, mbreq.Header.TxID); } /// @@ -270,34 +298,42 @@ void OnModbusConfirmRegisterException(struct ModbusApHeader mbap, enum ModbusExc // REGION: ModbusWriteBits ---------------------------------------------------------- /// -void ModbusWriteBits(word address, word count, byte values[]) +void ModbusWriteBits(word address, long count, byte values[]) { const word maxLength = __size_of(struct ModbusReqWriteBits); const byte funcCode = 0x0F; byte buffer[maxLength]; - struct ModbusReqWriteBits mbw; + struct ModbusReqWriteBits mbreq; + word curCount; byte dataLength; byte overallLength; word i; - dataLength = _ceil(count / 8.0); - overallLength = maxLength - 1968/8 + dataLength; - ModbusMakeHeader(mbw.Header, overallLength); - // Payload - mbw.Header.FuncCode = funcCode; // [1] Function Code; 15: Write Multiple Bits (DOs) - mbw.Address = address; // [2] Output address - mbw.Count = count; // [2] Number of items; 1:max 1968=0x7B0 - mbw.ByteCount = dataLength; // [1] Number of bytes; = ceil(count/8) - memcpy(mbw.Data, values, dataLength); // this is 1 memcpy too much -.- + // FC15: Write Multiple Bits (DOs) + while (count > 0) + { + curCount = count > gMaxBitsPerWrite ? gMaxBitsPerWrite : count; + dataLength = _ceil(curCount / 8.0); + overallLength = maxLength - gMaxBitsPerWrite/8 + dataLength; + ModbusMakeHeader(mbreq.Header, overallLength, funcCode); - writeDbg(MbDebug, "Sending 'Write Bits' (0x0F) command. Addr: 0x%04X, Count: %d", address, count); + mbreq.Address = address; // [2] Output address + mbreq.Count = curCount; // [2] Number of items; 1:max 1968=0x7B0 + mbreq.ByteCount = dataLength; // [1] Number of bytes; = ceil(count/8) + memcpy(mbreq.Data, values, dataLength); // [246] Data; this is 1 unneccessary memcpy :( Well, readability... - memcpy_h2n(buffer, mbw); - ModbusSend(buffer, overallLength, mbw.Header.TxID); + writeDbg(MbDebug, "Sending 'Write Bits' (0x0F) command. Addr: 0x%04X, Count: %d", address, curCount); + + memcpy_h2n(buffer, mbreq); + ModbusSend(buffer, overallLength, mbreq.Header.TxID); + + count -= gMaxBitsPerWrite; + address += gMaxBitsPerWrite; + } } /// -void ModbusWriteBitsB(word address, word count, byte values[]) +void ModbusWriteBitsB(word address, long count, byte values[]) { byte buffer[2]; // length word length; @@ -361,31 +397,38 @@ void OnModbusConfirmBitsException(struct ModbusApHeader mbap, enum ModbusExcepti // REGION: ModbusWriteRegisters ------------------------------------------------------- /// -void ModbusWriteRegisters(word address, word count, word values[]) +void ModbusWriteRegisters(word address, long count, word values[]) { const word maxLength = __size_of(struct ModbusReqWriteRegisters); const byte funcCode = 0x10; byte buffer[maxLength]; - struct ModbusReqWriteRegisters mbw; + struct ModbusReqWriteRegisters mbreq; + word curCount; byte dataLength; word overallLength; word i; - dataLength = 2 * count; - overallLength = maxLength - 2*123 + dataLength; + // FC16: Write Multiple Registers (AOs) + while (count > 0) + { + curCount = count > gMaxRegsPerWrite ? gMaxRegsPerWrite : count; + dataLength = 2 * curCount; + overallLength = maxLength - 2*gMaxRegsPerWrite + dataLength; - ModbusMakeHeader(mbw.Header, overallLength); - // Payload - mbw.Header.FuncCode = funcCode; // [1] Function Code; 16: Write Multiple Registers (AOs) - mbw.Address = address; // [2] Output address - mbw.Count = count; // [2] Number of items; 1:max 123=0x7B - mbw.ByteCount = dataLength; // [1] Number of bytes; = 2 * count + ModbusMakeHeader(mbreq.Header, overallLength, funcCode); - for (i = 0; i < dataLength; i++) - mbw.Data[i] = values[i]; + mbreq.Address = address; // [2] Output address + mbreq.Count = curCount; // [2] Number of items; 1:max 123=0x7B + mbreq.ByteCount = dataLength; // [1] Number of bytes; = 2 * count - memcpy_h2n(buffer, mbw); - ModbusSend(buffer, overallLength, mbw.Header.TxID); + for (i = 0; i < curCount; i++) + mbreq.Data[i] = values[i]; + for ( ; i < gMaxRegsPerWrite; i++) // do we need this? + mbreq.Data[i] = 0; + + memcpy_h2n(buffer, mbreq); + ModbusSend(buffer, overallLength, mbreq.Header.TxID); + } } /// @@ -419,17 +462,17 @@ void ModbusWriteMasks(word address, word and, word or) const word length = __size_of(struct ModbusReqWriteMasks); const byte funcCode = 0x16; byte buffer[length]; - struct ModbusReqWriteMasks mbw; + struct ModbusReqWriteMasks mbreq; - ModbusMakeHeader(mbw.Header, length); - // Payload - mbw.Header.FuncCode = funcCode; // [1] Function Code; 22: Mask Write Registers (AO) - mbw.Address = address; // [2] Output address - mbw.And = and; // [2] AND mask - mbw.Or = or; // [2] OR mask + // FC22: Mask Write Registers (AO) + ModbusMakeHeader(mbreq.Header, length, funcCode); - memcpy_h2n(buffer, mbw); - ModbusSend(buffer, length, mbw.Header.TxID); + mbreq.Address = address; // [2] Output address + mbreq.And = and; // [2] AND mask + mbreq.Or = or; // [2] OR mask + + memcpy_h2n(buffer, mbreq); + ModbusSend(buffer, length, mbreq.Header.TxID); } /// @@ -457,33 +500,48 @@ void OnModbusConfirmMasksException(struct ModbusApHeader mbap, enum ModbusExcept // REGION: ModbusReadWriteRegisters ------------------------------------------------------- /// -void ModbusReadWriteRegisters(word readAddress, word readCount, word writeAddress, word writeCount, int values[]) +void ModbusReadWriteRegisters(word readAddress, long readCount, word writeAddress, long writeCount, word values[]) { const word maxLength = __size_of(struct ModbusReqReadWriteRegisters); const byte funcCode = 0x17; byte buffer[maxLength]; - struct ModbusReqReadWriteRegisters mbw; + struct ModbusReqReadWriteRegisters mbreq; byte dataLength; word overallLength; - word i; + word i, offset; + + offset = 0; + if (readCount > gMaxRegsPerRead - 2) // if we have to split the read request. count = n*max + y + { + ModbusReadRegisters(readAddress, readCount - readCount % gMaxRegsPerRead); // let this function read the main part: n*max + readAddress += readCount - readCount % gMaxRegsPerRead; // increment address by n*max + readCount %= gMaxRegsPerRead; // only read y elements in this function + } + if (writeCount > gMaxRegsPerWrite - 2) // if we have to split the write request. count = n*max + y + { + ModbusWriteRegisters(writeAddress, writeCount - writeCount % gMaxRegsPerWrite, values); // let this function read the main part: n*max + offset = writeCount - writeCount % gMaxRegsPerWrite; // start reading values at n*max + writeAddress += offset; // increment address by n*max + writeCount %= gMaxRegsPerWrite; // only read y elements in this function + } dataLength = 2 * writeCount; - overallLength = maxLength - 2*121 + dataLength; + overallLength = maxLength - 2*(gMaxRegsPerWrite-2) + dataLength; - ModbusMakeHeader(mbw.Header, overallLength); - // Payload - mbw.Header.FuncCode = funcCode; // [1] Function Code; 16: Write Multiple Registers (AOs) - mbw.ReadAddress = readAddress; // [2] Input address - mbw.ReadCount = readCount; // [2] Number of items; 1:max 125=0x7D - mbw.WriteAddress = writeAddress;// [2] Output address - mbw.WriteCount = writeCount; // [2] Number of items; 1:max 121=0x79 - mbw.ByteCount = dataLength; // [1] Number of bytes; = 2 * count + // FC16: Write Multiple Registers (AOs) + ModbusMakeHeader(mbreq.Header, overallLength, funcCode); - for (i = 0; i < dataLength; i++) - mbw.Data[i] = values[i]; + mbreq.ReadAddress = readAddress; // [2] Input address + mbreq.ReadCount = readCount; // [2] Number of items; 1:max 125=0x7D + mbreq.WriteAddress = writeAddress; // [2] Output address + mbreq.WriteCount = writeCount; // [2] Number of items; 1:max 121=0x79 + mbreq.ByteCount = dataLength; // [1] Number of bytes; = 2 * count - memcpy_h2n(buffer, mbw); - ModbusSend(buffer, overallLength, mbw.Header.TxID); + for (i = 0; i < writeCount; i++) + mbreq.Data[i] = values[i + offset]; + + memcpy_h2n(buffer, mbreq); + ModbusSend(buffer, overallLength, mbreq.Header.TxID); } /// @@ -545,7 +603,7 @@ void OnModbusReceive(dword socket, long result, dword address, dword port, byte void OnModbusReceive2(byte buffer[], dword size) { struct ModbusApHeader mbap; - int offset; + long offset; char str[3*20]; if (size < 8) // No complete Modbus Application Header @@ -579,7 +637,7 @@ void OnModbusReceive2OnePacket(byte buffer[], int offset, struct ModbusApHeader // Test unit/device identifier? word i; // counter word length; // length of current packet - byte mbuffer[__size_of(struct ModbusResReceiveRegisters)]; // second buffer where we copy the message. This way the user won't overwrite other packages. + byte mbuffer[gModbusMaxTelegramSize]; // second buffer where we copy the message. This way the user won't overwrite other packages. length = __offset_of(struct ModbusApHeader, UnitID) + mbap.Length; // We cannot check this properly anymore. We have to trust the TCP/UDP stack and the sender... *sigh* @@ -597,7 +655,7 @@ void OnModbusReceive2OnePacket(byte buffer[], int offset, struct ModbusApHeader } // MBAP Header is OK :) Go on - if (!gQueueSent.ContainsKey(mbap.TxID)) // We don't wait for this message! + if (!gQueueSent.ContainsKey(mbap.TxID)) // We don't wait for this message!? return; //write("Received TxID: %d", mbap.TxID); @@ -613,7 +671,6 @@ void OnModbusReceive2OnePacket(byte buffer[], int offset, struct ModbusApHeader return; } - // Copy the message memcpy_off(mbuffer, 0, buffer, offset, length); @@ -780,8 +837,8 @@ on timer gtRobin // Second: send new packets for (long TxID : gQueuePending) { - if (gQueueSent.Size() > 4) // Wago 750-881 cannot handle more than 5 messages at a time :( - continue; + if (gQueueSent.Size() >= gDevReceiveWindow) // Device cannot handle many messages at a time + break; // if packet was sent or the socket is not currently being opened if (ModbusSnd(gQueuePending[TxID].Buffer, gQueuePending[TxID].Length) == 0 || gSocketState != NULL) diff --git a/Modbus-CAPL/include/CAPL/include/ModbusFunctions.cin b/Modbus-CAPL/include/CAPL/include/ModbusFunctions.cin deleted file mode 100644 index fc4a429..0000000 --- a/Modbus-CAPL/include/CAPL/include/ModbusFunctions.cin +++ /dev/null @@ -1,72 +0,0 @@ -/*@!Encoding:1252*/ -variables -{ - struct deviceIOs - { - byte InputRegisters; - word InputBits; - byte OutputRegisters; - word OutputBits; - char Modules[1024]; - }; -} - -void ParseDeviceCode(word dev, enum Vendor vendor, struct deviceIOs dios) -{ - byte input; - byte numChannels; - char module[10]; - - switch(vendor) - { - case Wago: // if this is a Wago device - - if (dev & 0x8000) // Digital Module - { - numChannels = (dev >> 8) & 0x007F; - - if (dev & 0x0001) // Input Module - { - input = 1; - strncpy(module, "DI%d,", elCount(module)); - } - else if (dev & 0x0002) // Output Module - { - input = 0; - strncpy(module, "DO%d,", elCount(module)); - } - else // blööd - { - writeDbg(AlgoError, "ParseDeviceCode: Device code 0x%X cannot be decoded", dev); - OnModbusClientPanics(DeviceCodeUnknown); - } - } - else - { - switch (dev) - { - case 881: // devices that have no inputs/outputs - return; - case 477: // devices that have 2 inputs - input = 1; - numChannels = 2; - break; - default: // unknown device. Ouch! - writeDbg(AlgoInfo, "Connected device: 750-%d", dev); - return; - } - if (input) - strncpy(module, "AI%d,", elCount(module)); - else - strncpy(module, "AO%d,", elCount(module)); - } - break; // switch(vendor) - default: - writeDbg(AlgoError, "ParseDeviceCode: Unknown vendor id: %d", vendor); - OnModbusClientPanics(VendorIdUnknown); - return; - } - - snprintf(module, elCount(module), module, numChannels); - strncat(dios.Modules, module, elCount(dios.Modules)); -} \ No newline at end of file diff --git a/Modbus-CAPL/include/CAPL/include/ModbusStructs.cin b/Modbus-CAPL/include/CAPL/include/ModbusStructs.cin index 5aaa6c1..ef17756 100644 --- a/Modbus-CAPL/include/CAPL/include/ModbusStructs.cin +++ b/Modbus-CAPL/include/CAPL/include/ModbusStructs.cin @@ -1,6 +1,12 @@ /*@!Encoding:1252*/ variables { + // according to Modbus Specification v1.1 + const word gMaxBitsPerRead = 2000; + const word gMaxRegsPerRead = 125; + const word gMaxBitsPerWrite = 1968; + const word gMaxRegsPerWrite = 123; + // A normal Modbus Application Header. Every Modbus Packet begins with these 7 (+FuncCode) Bytes _align(1) struct ModbusApHeader { @@ -31,7 +37,7 @@ variables word Address; word Count; byte ByteCount; - byte Data[246]; // Max length: 1968 bits + byte Data[gMaxBitsPerWrite/8]; // Max length: 1968 bits }; // Write several values to bits starting with Address _align(1) struct ModbusReqWriteRegisters @@ -40,7 +46,7 @@ variables word Address; word Count; byte ByteCount; - word Data[123]; // Max length: 123 registers + word Data[gMaxRegsPerWrite]; // Max length: 123 registers }; // Write AND and OR masks to a holding register _align(1) struct ModbusReqWriteMasks @@ -59,7 +65,7 @@ variables word WriteAddress; word WriteCount; byte ByteCount; - word Data[121]; // Max length: 123-2 registers + word Data[gMaxRegsPerWrite-2]; // Max length: 123-2 registers }; @@ -68,14 +74,14 @@ variables { struct ModbusApHeader Header; byte ByteCount; - byte Data[250]; // Max length: 2000 bits + byte Data[gMaxBitsPerRead/8]; // Max length: 2000 bits }; // Receive several register values _align(1) struct ModbusResReceiveRegisters { struct ModbusApHeader Header; byte ByteCount; - word Data[125]; // Max length: 125 registers + word Data[gMaxRegsPerRead]; // Max length: 125 registers }; // Confirm the write of a single bit/register _align(1) struct ModbusResConfirmSingle @@ -100,6 +106,7 @@ variables word Or; }; + const word gModbusMaxTelegramSize = __size_of(struct ModbusResReceiveRegisters); enum ModbusRequestError @@ -107,7 +114,7 @@ variables Exception, Timeout, FinalTimeout - }; + }; enum ModbusException { None = 0x00, @@ -143,9 +150,4 @@ variables VendorIdUnknown = 0x03, ConnectionError = 0x04 }; - enum Vendor - { - Wago = 23, - BuR = 2 - }; } \ No newline at end of file diff --git a/Modbus-CAPL/include/DBC/MakeConfig.ini b/Modbus-CAPL/include/DBC/MakeConfig.ini index e7255ca..5a90901 100644 --- a/Modbus-CAPL/include/DBC/MakeConfig.ini +++ b/Modbus-CAPL/include/DBC/MakeConfig.ini @@ -52,7 +52,7 @@ COLUMNWIDTHS=125,100,100,150,100,100, HIDDEN= ORDER=0,1,2,3,4, DEFINITIONS=1, -COLUMNWIDTHS=125,125,100,150,100, +COLUMNWIDTHS=125,125,100,150,123, [View_NetworkTxMessages] HIDDEN= ORDER=0,1,2,3,4,5,6,7,8, diff --git a/Modbus-CAPL/include/SysVars/generated.vsysvar b/Modbus-CAPL/include/SysVars/generated.vsysvar index 61a9c19..03feb1f 100644 --- a/Modbus-CAPL/include/SysVars/generated.vsysvar +++ b/Modbus-CAPL/include/SysVars/generated.vsysvar @@ -1,16 +1,6 @@ - - - - - - - - - - @@ -18,25 +8,25 @@ - + - - - - - - - + + + + + + + - - - - + + + + @@ -45,27 +35,37 @@ - + - - - - - - - + + + + + + + - - - - + + + + + + + + + + + + + + - + \ No newline at end of file