├── .cdtproject
├── .cproject
├── .gitignore
├── .project
├── .settings
└── org.eclipse.cdt.core.prefs
├── CompactLogix.txt
├── INSTALL
├── LICENSE
├── Makefile
├── Manual.md
├── README.md
├── changes.txt
├── configure
├── CONFIG
├── CONFIG_SITE
├── CONFIG_SITE.local
├── CONFIG_SITE.local.darwin-aarch64
├── CONFIG_SITE.local.darwin-x86
├── CONFIG_SITE.local.linux-x86_64
├── Makefile
├── RELEASE
├── RULES
├── RULES.ioc
├── RULES_DIRS
└── RULES_TOP
├── ether_ipApp
├── Makefile
├── doc
│ ├── CIP_sniff.txt
│ ├── bool.txt
│ ├── readme.txt
│ └── stats.txt
└── src
│ ├── Makefile
│ ├── devEtherIP.c
│ ├── dl_list.c
│ ├── dl_list.h
│ ├── drvEtherIP.c
│ ├── drvEtherIP.h
│ ├── drvEtherIPRegister.cpp
│ ├── eip_bool.h
│ ├── ether_ip-3-14.dbd
│ ├── ether_ip-lint.dbd
│ ├── ether_ip-lsio.dbd
│ ├── ether_ip.c
│ ├── ether_ip.h
│ ├── ether_ip.rc
│ └── ether_ip_test.c
├── iocBoot
├── Makefile
├── iocether_ip
│ ├── Makefile
│ ├── README
│ ├── run_iocLogServer.sh
│ ├── st.cmd
│ ├── st.cmd.3_14
│ ├── st.cmd.host
│ └── string.db
└── nfsCommands
└── testether_ipApp
├── Db
├── Makefile
├── ai.db
├── ana.db
├── ao.db
├── bi.db
├── bin.db
├── bo.db
├── brad.db
├── brad2.db
├── eip_stat.db
├── lint.db
├── mbbi.db
├── mbbo.db
├── mkana.pl
├── mkbin.pl
├── mod.db
├── ramp.db
└── test.db
├── Makefile
├── RSLogix
└── test.L5K
├── edm
└── test_db.edl
├── opi
└── EtherIPStats.bob
└── src
├── Makefile
└── eipIocMain.cpp
/.cdtproject:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | -
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 | make
60 |
61 |
62 | true
63 | true
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/.cproject:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | make
69 |
70 | true
71 | true
72 | true
73 |
74 |
75 | make
76 |
77 | distclean
78 | false
79 | true
80 | true
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## generated from EPICS build
2 | configure/RELEASE.local
3 | bin/
4 | db/
5 | dbd/
6 | include/
7 | lib/
8 | O.*
9 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | ether_ip
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.cdt.make.core.makeBuilder
10 | clean,full,incremental,
11 |
12 |
13 | org.eclipse.cdt.core.errorOutputParser
14 | org.eclipse.cdt.core.MakeErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GASErrorParser;org.eclipse.cdt.core.GLDErrorParser;org.eclipse.cdt.core.VCErrorParser;
15 |
16 |
17 | org.eclipse.cdt.make.core.append_environment
18 | true
19 |
20 |
21 | org.eclipse.cdt.make.core.build.arguments
22 |
23 |
24 |
25 | org.eclipse.cdt.make.core.build.command
26 | make
27 |
28 |
29 | org.eclipse.cdt.make.core.build.location
30 |
31 |
32 |
33 | org.eclipse.cdt.make.core.build.target.auto
34 | all
35 |
36 |
37 | org.eclipse.cdt.make.core.build.target.clean
38 | clean
39 |
40 |
41 | org.eclipse.cdt.make.core.build.target.inc
42 | all
43 |
44 |
45 | org.eclipse.cdt.make.core.enableAutoBuild
46 | false
47 |
48 |
49 | org.eclipse.cdt.make.core.enableCleanBuild
50 | true
51 |
52 |
53 | org.eclipse.cdt.make.core.enableFullBuild
54 | true
55 |
56 |
57 | org.eclipse.cdt.make.core.enabledIncrementalBuild
58 | true
59 |
60 |
61 | org.eclipse.cdt.make.core.environment
62 |
63 |
64 |
65 | org.eclipse.cdt.make.core.stopOnError
66 | false
67 |
68 |
69 | org.eclipse.cdt.make.core.useDefaultBuildCmd
70 | true
71 |
72 |
73 |
74 |
75 | org.eclipse.cdt.make.core.ScannerConfigBuilder
76 |
77 |
78 |
79 |
80 |
81 | org.eclipse.cdt.core.cnature
82 | org.eclipse.cdt.make.core.makeNature
83 | org.eclipse.cdt.make.core.ScannerConfigNature
84 | org.eclipse.cdt.core.ccnature
85 |
86 |
87 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.cdt.core.prefs:
--------------------------------------------------------------------------------
1 | #Tue Dec 12 15:15:08 EST 2006
2 | eclipse.preferences.version=1
3 | indexerId=org.eclipse.cdt.core.nullindexer
4 |
--------------------------------------------------------------------------------
/CompactLogix.txt:
--------------------------------------------------------------------------------
1 | This driver was written for ControlLogix,
2 | but also seems to work with CompactLogix,
3 | as reported by Mike Forster :
4 |
5 | We saw that when a record scan list became long (too many records with the same scan rate),
6 | all the elements in that scan list would stop responding.
7 | Eventually we traced this down to the EIP_buffer_limit which was the default 500.
8 | This limit at 500 allows data to be sent that is 554 bytes long. After some trial and
9 | error we found that the PLC responded correctly if the data sent was 548 bytes long or less.
10 | When we set EIP_buffer_limit to 494 our problems went away.
11 |
--------------------------------------------------------------------------------
/INSTALL:
--------------------------------------------------------------------------------
1 | -*- outline -*- (use EMACS to see this in outline-mode)
2 |
3 | This readme is about compiling the driver & examples.
4 | See /ether_ipApp/doc for info on how to use the driver.
5 |
6 | * Intro
7 | The sources for this driver are on SourceForge,
8 | see http://sourceforge.net/apps/trac/epics/wiki/EtherIP
9 |
10 | Read-only Mercurial access:
11 | hg clone http://epics.hg.sourceforge.net:8000/hgroot/epics/ether_ip
12 |
13 | Read/write Mercurial access:
14 | hg clone ssh://USERNAME@epics.hg.sourceforge.net/hgroot/epics/ether_ip
15 |
16 | Tag: ether_ip-
17 |
18 | What you have to do is
19 | - compile the ether_ip driver/device sources
20 | - somehow load them in the IOC
21 | - include the DBD descriptions of the new device support
22 | so that EPICS knows about them
23 | - create EPICS records that use the new driver
24 |
25 | The directory structure and Makefiles were created by
26 | makeBaseApp.pl from EPICS R3.13.3 base and later updated
27 | for EPICS 3.14 base.
28 | - In iocBoot/iocether_ip/Makefile, select the ARCH for the test IOC
29 | (if you want to use that test setup).
30 | - You have to modify configure/RELEASE
31 | so that ETHER_IP point to where you put the stuff, e.g.
32 | ETHER_IP=/cs/epics/ADE/R3.14.11/support/ether_ip/current
33 |
34 | * I. ether_ip directory structure:
35 | ether_ip/
36 | README -- this file
37 | ether_ipApp/ - the DRIVER/DEVICE. You need this!
38 | src -- contains the source code and dbd definitions.
39 | Used to build and install the library
40 | libether_ip.a -- containing driver object file
41 | and to install
42 | ether_ip.dbd -- the database definition file
43 | needed by databases using the driver.
44 | doc -- contains the driver specific documentation
45 | testether_ipApp/ - example of EPICS database for ether_ip.
46 | You can use this for reference and tests.
47 | src -- contains an example application that builds a
48 | epics module that uses the ether_ip driver.
49 | Db -- contains sample databases using the ether_ip driver.
50 | dm2k -- contains sample dm2k adl display files.
51 |
52 | configure -- configuration setup with RELEASE referring to
53 | location of ETHER_IP for use by the example in testether_ipApp
54 |
55 | Makefile -- setup to build 1st ether_ipApp,
56 | then config,
57 | then testether_ipApp, so that the
58 | examples will work.
59 |
60 | * II. Build
61 | 1. Your usual EPICS environment variables need to be set:
62 | EPICS_HOST_ARCH, PATH to include the EPICS base tools
63 | 2. cd where_the_ether_ip_sources_are
64 | 3. Edit configure/RELEASE for EPICS BASE and ETHER_IP directory
65 | locations.
66 | 4. Edit iocBoot/iocether_ip/Makefile for ARCH
67 | 5. make
68 |
69 | * III. Use of the ether_ip driver in your ioc application
70 | 1. Make sure that the driver code has been checked out and built
71 | as described above. The Make in the config directory
72 | depends on the proper directories already existing.
73 |
74 | 2. Set up ETHER_IP definitions in the configuration directory
75 | for your application by:
76 | 2.1. cd /configure
77 | 2.2. edit the file RELEASE file, add the line
78 | ETHER_IP=/cs/epics/ADE/R3.14.11/support/ether_ip/
79 | 2.3. Make sure the new definitions take effect by
80 | make clean
81 | make
82 | in the configure directory.
83 | 3. Set up the dbd include file in your src directory to include
84 | ether_ip.dbd by adding the line
85 | include "ether_ip.dbd"
86 | after the line include "../base.dbd".
87 |
88 | Now that RELEASE file has been edited and config or configure has been
89 | rebuilt the Makefile will be able to find ether_ip.dbd
90 | when it expands your dbd file.
91 | 4. Set up your application to include the object libraries by
92 | including the following lines in Makefile:
93 | _LIBS += ether_ip
94 | ether_ip_DIR = $(ETHER_IP_LIB)
95 |
96 | ETHER_IP_LIB (3.14) will be automatically
97 | defined for every type of ioc for which your application is built.
98 |
99 | R. Wright, K. Kasemir
100 | 3.14 notes added by S. Allison
101 |
102 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2000-2018 Oak Ridge National Laboratory.
2 | All rights reserved.
3 |
4 | EtherIP is distributed subject to the following license conditions:
5 |
6 | SOFTWARE LICENSE AGREEMENT
7 | Software: EtherIP
8 |
9 | 1. The "Software", below, refers to EtherIP (in either source code, or
10 | binary form and accompanying documentation). Each licensee is
11 | addressed as "you" or "Licensee."
12 |
13 | 2. The copyright holders shown above and their third-party licensors
14 | hereby grant Licensee a royalty-free nonexclusive license, subject to
15 | the limitations stated herein and U.S. Government license rights.
16 |
17 | 3. You may modify and make a copy or copies of the Software for use
18 | within your organization, if you meet the following conditions:
19 | a. Copies in source code must include the copyright notice and this
20 | Software License Agreement.
21 | b. Copies in binary form must include the copyright notice and this
22 | Software License Agreement in the documentation and/or other
23 | materials provided with the copy.
24 |
25 | 4. You may modify a copy or copies of the Software or any portion of it,
26 | thus forming a work based on the Software, and distribute copies of
27 | such work outside your organization, if you meet all of the following
28 | conditions:
29 | a. Copies in source code must include the copyright notice and this
30 | Software License Agreement;
31 | b. Copies in binary form must include the copyright notice and this
32 | Software License Agreement in the documentation and/or other
33 | materials provided with the copy;
34 | c. Modified copies and works based on the Software must carry
35 | prominent notices stating that you changed specified portions of
36 | the Software.
37 |
38 | 5. Portions of the Software resulted from work developed under a U.S.
39 | Government contract and are subject to the following license: the
40 | Government is granted for itself and others acting on its behalf a
41 | paid-up, nonexclusive, irrevocable worldwide license in this computer
42 | software to reproduce, prepare derivative works, and perform publicly
43 | and display publicly.
44 |
45 | 6. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY
46 | OF ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY LICENSORS, THE
47 | UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND THEIR
48 | EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
49 | BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
50 | FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME
51 | ANY LEGAL LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS,
52 | OR USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE
53 | SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT
54 | THAT THE SOFTWARE WILL FUNCTION UNINTERRUPTED, THAT IT IS ERROR-FREE
55 | OR THAT ANY ERRORS WILL BE CORRECTED.
56 |
57 | 7. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, THEIR
58 | THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT
59 | OF ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
60 | CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF ANY KIND OR NATURE,
61 | INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS OR LOSS OF DATA, FOR ANY
62 | REASON WHATSOEVER, WHETHER SUCH LIABILITY IS ASSERTED ON THE BASIS OF
63 | CONTRACT, TORT (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR
64 | OTHERWISE, EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE
65 | POSSIBILITY OF SUCH LOSS OR DAMAGES.
66 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #Makefile at top of application tree
2 | TOP = .
3 |
4 | include $(TOP)/configure/CONFIG
5 |
6 | DIRS := configure
7 |
8 | DIRS += ether_ipApp
9 | ether_ipApp_DEPEND_DIRS = configure
10 |
11 | DIRS += testether_ipApp
12 | testether_ipApp_DEPEND_DIRS = ether_ipApp
13 |
14 | DIRS += iocBoot
15 | iocBoot_DEPEND_DIRS = configure
16 |
17 | include $(TOP)/configure/RULES_TOP
18 |
19 |
20 | test:
21 | bin/linux-x86/ether_ip_test -i 160.91.232.217 -v 10 K_RealArray_10[2]
22 |
23 | val:
24 | valgrind --trace-children=yes --leak-check=full --show-reachable=yes bin/linux-x86/ether_ip_test -i 160.91.232.217 -v 1 K_RealArray_10[2]
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | "EtherIP" driver/device support module for EPICS.
2 |
3 | Interfaces Allen Bradley PLCs (see www.ab.com) via Ethernet to EPICS IOCs
4 | * ControlLogix 5000,
5 | both original versions with separate controller and ENET module,
6 | and L8x series that includes a network port in the controller.
7 | * Compact Logix devices
8 |
9 | For EPICS R3.14.8 and higher,
10 | on Linux and several other operating systems supported by EPICS libCom.
11 | For earlier version of EPICS base, including R3.13, see tags/releases older than ether_ip-3-0.
12 | VxWorks 5.5 must also use an older version because its compiler requires
13 | K&R style declarations of all variables at the start of a code block.
14 |
15 | See
16 | * Manual.md for usage.
17 | * https://controlssoftware.sns.ornl.gov/etherip for more.
18 | * changes.txt for changes.
19 | * https://github.com/ornl-epics/etherip for a Java version of the basic communication library, not connected to an EPCIS IOC.
20 | * https://github.com/ottowayi/pycomm3 for an unrelated python library that supports many protocol features.
21 |
22 |
--------------------------------------------------------------------------------
/configure/CONFIG:
--------------------------------------------------------------------------------
1 | # CONFIG - Load build configuration data
2 | #
3 | # Do not make changes to this file!
4 |
5 | # Allow user to override where the build rules come from
6 | RULES = $(EPICS_BASE)
7 |
8 | # RELEASE files point to other application tops
9 | include $(TOP)/configure/RELEASE
10 | -include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common
11 | ifdef T_A
12 | -include $(TOP)/configure/RELEASE.Common.$(T_A)
13 | -include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
14 | endif
15 |
16 | CONFIG = $(RULES)/configure
17 | include $(CONFIG)/CONFIG
18 |
19 | # Override the Base definition:
20 | INSTALL_LOCATION = $(TOP)
21 |
22 | # CONFIG_SITE files contain other build configuration settings
23 | include $(TOP)/configure/CONFIG_SITE
24 | -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
25 | ifdef T_A
26 | -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A)
27 | -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
28 | endif
29 |
30 |
--------------------------------------------------------------------------------
/configure/CONFIG_SITE:
--------------------------------------------------------------------------------
1 | # CONFIG_SITE
2 |
3 | # Make any application-specific changes to the EPICS build
4 | # configuration variables in this file.
5 | #
6 | # Host/target specific settings can be specified in files named
7 | # CONFIG_SITE.$(EPICS_HOST_ARCH).Common
8 | # CONFIG_SITE.Common.$(T_A)
9 | # CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
10 |
11 | # CHECK_RELEASE controls the consistency checking of the support
12 | # applications pointed to by the RELEASE* files.
13 | # Normally CHECK_RELEASE should be set to YES.
14 | # Set CHECK_RELEASE to NO to disable checking completely.
15 | # Set CHECK_RELEASE to WARN to perform consistency checking but
16 | # continue building even if conflicts are found.
17 | CHECK_RELEASE = YES
18 |
19 | # Set this when you only want to compile this application
20 | # for a subset of the cross-compiled target architectures
21 | # that Base is built for.
22 | #CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32
23 |
24 | # To install files into a location other than $(TOP) define
25 | # INSTALL_LOCATION here.
26 | #INSTALL_LOCATION=
27 |
28 | # Set this when the IOC and build host use different paths
29 | # to the install location. This may be needed to boot from
30 | # a Microsoft FTP server say, or on some NFS configurations.
31 | #IOCS_APPL_TOP =
32 |
33 | # For application debugging purposes, override the HOST_OPT and/
34 | # or CROSS_OPT settings from base/configure/CONFIG_SITE
35 | #HOST_OPT = NO
36 | #CROSS_OPT = NO
37 |
38 | # These allow developers to override the CONFIG_SITE variable
39 | # settings without having to modify the configure/CONFIG_SITE
40 | # file itself.
41 | -include $(TOP)/../CONFIG_SITE.local
42 | -include $(TOP)/../configure/CONFIG_SITE.local
43 | -include $(TOP)/configure/CONFIG_SITE.local
44 | -include $(TOP)/configure/CONFIG_SITE.local.$(OS_CLASS)
45 | -include $(TOP)/configure/CONFIG_SITE.local.$(EPICS_HOST_ARCH)
46 | -include $(TOP)/configure/CONFIG_SITE.local.$(EPICS_HOST_ARCH).$(T_A)
47 |
--------------------------------------------------------------------------------
/configure/CONFIG_SITE.local:
--------------------------------------------------------------------------------
1 | # Enables support for long ints
2 | SUPPORT_LINT=NO
3 |
--------------------------------------------------------------------------------
/configure/CONFIG_SITE.local.darwin-aarch64:
--------------------------------------------------------------------------------
1 | #Support long int on Mac
2 | SUPPORT_LINT = YES
3 |
--------------------------------------------------------------------------------
/configure/CONFIG_SITE.local.darwin-x86:
--------------------------------------------------------------------------------
1 | #Support long int on Mac
2 | SUPPORT_LINT = YES
3 |
--------------------------------------------------------------------------------
/configure/CONFIG_SITE.local.linux-x86_64:
--------------------------------------------------------------------------------
1 | #Support long int on Linux 64
2 | SUPPORT_LINT = YES
3 |
--------------------------------------------------------------------------------
/configure/Makefile:
--------------------------------------------------------------------------------
1 | TOP=..
2 |
3 | include $(TOP)/configure/CONFIG
4 |
5 | TARGETS = $(CONFIG_TARGETS)
6 | CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
7 |
8 | include $(TOP)/configure/RULES
9 |
--------------------------------------------------------------------------------
/configure/RELEASE:
--------------------------------------------------------------------------------
1 | # RELEASE - Location of external support modules
2 |
3 | -include $(TOP)/../RELEASE.local
4 | -include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local
5 | -include $(TOP)/configure/RELEASE.local
6 |
--------------------------------------------------------------------------------
/configure/RULES:
--------------------------------------------------------------------------------
1 | # RULES
2 |
3 | include $(CONFIG)/RULES
4 |
5 | # Library should be rebuilt because LIBOBJS may have changed.
6 | $(LIBNAME): ../Makefile
7 |
--------------------------------------------------------------------------------
/configure/RULES.ioc:
--------------------------------------------------------------------------------
1 | #RULES.ioc
2 | include $(CONFIG)/RULES.ioc
3 |
--------------------------------------------------------------------------------
/configure/RULES_DIRS:
--------------------------------------------------------------------------------
1 | #RULES_DIRS
2 | include $(CONFIG)/RULES_DIRS
3 |
--------------------------------------------------------------------------------
/configure/RULES_TOP:
--------------------------------------------------------------------------------
1 | #RULES_TOP
2 | include $(CONFIG)/RULES_TOP
3 |
4 |
--------------------------------------------------------------------------------
/ether_ipApp/Makefile:
--------------------------------------------------------------------------------
1 | TOP = ..
2 |
3 | include $(TOP)/configure/CONFIG
4 |
5 | DIRS := src
6 |
7 | include $(TOP)/configure/RULES_DIRS
8 |
--------------------------------------------------------------------------------
/ether_ipApp/doc/CIP_sniff.txt:
--------------------------------------------------------------------------------
1 | Sniffed from communication between RSLogix and PLC
2 | when "online":
3 |
4 | 0A 02 20 02 24 01 - multi request
5 |
6 | 06 00 - 6 items
7 |
8 | 0E00 = 14 - offset to service #1
9 | 1800 = 24 - offset to service #2
10 | 2200 = 34 - offset to service #3
11 | 3600 = 54 - offset to service #4
12 | 4200 = 66 - offset to service #5
13 | 4C00 = 76 - offset to service #6
14 |
15 | Service 1 @ count + 14
16 | 03 02 20 01 24 01 - GetAttributeList Class 1, instance 1
17 | 01 00 05 00 - Get attribute 5
18 |
19 | Service 2
20 | 03 02 20 69 24 00 - ... Class 0x69
21 | 01 00 0B 00
22 |
23 | 03 02 20 AC 24 01 - ... Class 0xAC
24 | 06 00
25 | 01 00 02 00 03 00 - Attribs 1, 2, 3, 5, 7, 9
26 | 05 00 07 00 09 00
27 |
28 | 03 02 20 8E 24 01
29 | 02 00
30 | 03 00 08 00
31 |
32 | 03 02 20 69 24 00
33 | 01 00 09 00
34 |
35 | 03 03 20 69 25 00 04 D8
36 | 01 00 04 00
37 |
--------------------------------------------------------------------------------
/ether_ipApp/doc/bool.txt:
--------------------------------------------------------------------------------
1 |
2 | Some people have run into problems with binary records and BOOL tags.
3 |
4 | Symptom:
5 | The record can write a '1' to turn something on the PLC 'on',
6 | but writing a '0' to turn something 'off' seems to have no effect.
7 |
8 | Reason/explanation/underlying problem:
9 | The support for binary records (BO, MBBO, MBBODIRECT, ...) addresses bits.
10 |
11 | Problem 1:
12 | The protocol doesn't really distinguish between writing bits in a BOOL
13 | array and bits of a DINT.
14 | When writing BOOL[32], that's actually the same as writing DINT[1].0.
15 | Both refer to the 33rd bit (counting from 0) in some memory structure.
16 | So complcation #1 arises when your BO record writes to 'fred[2]',
17 | and you think that's DINT array 'fred', third element,
18 | but the driver will actually deal with the third bit of the first element.
19 |
20 | Problem 2:
21 | When we write a '1' to a bit in a BOOL array,
22 | that bit will read back as '1'
23 | (assuming that nothing else on the PLC changes it).
24 | The driver is specifically written to handle that case:
25 | The BO records will only touch bits.
26 |
27 | When you, however, write '1' to a scalar BOOL tag,
28 | it can read back as '255'.
29 | Which is OK, both values are considered 'on' by PLC
30 | logic.
31 | But if you now write a '0' to that tag,
32 | the driver will only write a zero bit,
33 | using the last readback.
34 | Meaning: it ends up writing 254 = 255 - bit 0,
35 | and the PLC will still consider that 'on'.
36 |
37 |
38 | --> Use binary records with BOOL arrays.
39 | That works, and is more efficient than single BOOL tags.
40 | If you have to deal with a single BOOL tag,
41 | remember that this really looks like an SINT with
42 | possible values 0 and 255,
43 | and use an AI or AO record for it.
44 | Maybe an AO record linked to a BO record.
45 |
46 |
47 |
--------------------------------------------------------------------------------
/ether_ipApp/doc/stats.txt:
--------------------------------------------------------------------------------
1 | -*- outline -*-
2 |
3 | This is mostly a log of email messages that I sent out
4 | while testing the protocol and developling the driver....
5 |
6 | * Test 1
7 | ========
8 |
9 | On same hub:
10 | - PC (100baseT)
11 | - ControlLogix PLC, 1756-ENET interface (10baseT)
12 | "System Overhead Time Slice" set to 10%
13 |
14 | - For the measurements indicated with (SW),
15 | the PLC and the PC were connected to a switch.
16 |
17 | LastScanTime: 140...200
18 |
19 | Read values, single tag:
20 | REAL : 90.909091 values/sec, 11.000000 msec/value
21 | REAL :136.986301 values/sec, 7.300000 msec/value (SW)
22 | 140.845070 values/sec, 7.100000 msec/value (Connected)
23 |
24 | BOOL : -same-
25 | DINT : -same-
26 | PV : -same-
27 | PVs[2] : -same-
28 | PVs[5] : -same-
29 | PVs[8] : 58.823529 values/sec, 17.000000 msec/value
30 | PVs[10] : 45.454545 values/sec, 22.000000 msec/value
31 | PVs[20] : 45.454545 values/sec, 22.000000 msec/value
32 | PVs[30] : 37.037037 values/sec, 27.000000 msec/value
33 | PVs[40] : 30.303030 values/sec, 33.000000 msec/value
34 | 33.333333 values/sec, 30.000000 msec/value (SW)
35 | 33.333333 values/sec, 30.000000 msec/value (Connected)
36 |
37 | BITS[352]: 90.909091 values/sec, 11.000000 msec/value
38 | BITS[512]: 83.333333 values/sec, 12.000000 msec/value
39 |
40 | PV is user-defined type:
41 | REAL .VAL (C float)
42 | DINT .STAT (32 bit)
43 | DINT .TIME
44 |
45 | PVs[#] is similar, but each entry is an array of # elements:
46 | REAL .VAL[#]
47 | DINT .STAT[#]
48 | DINT .TIME[#]
49 |
50 | -> PVs[40] combines 120 numbers
51 |
52 | BITS[3]: BOOL[#], e.g. 512 booleans packed as 64 bytes
53 |
54 |
55 | When going "online" with RSLogix5000 at the same time,
56 | the 90.909091 values/sec, 11.000000 msec/value
57 | turn into 83.333333 values/sec, 12.000000 msec/value
58 |
59 | There is hardly any load on PC, the hub shows up to 3%
60 | -> this must be the limitation of the PLC/ENET for doing
61 | communications.
62 |
63 | Indeed: change "System Overhead Time Slice" set to 50%
64 |
65 | LastScanTime: 140...200
66 |
67 | REAL : 142.857143 values/sec, 7.000000 msec/value
68 | PVs[40] : 35.714286 values/sec, 28.000000 msec/value
69 | BITS[352]: 100.000000 values/sec, 10.000000 msec/value
70 |
71 |
72 |
73 | * Test 2
74 | ========
75 |
76 | Hello:
77 |
78 | I have some updates on the Ethernet connection to ControlLogix.
79 | I won't explore the protocol further but start developement
80 | of an EPICS driver now.
81 | This leads to suggestions and questions on how to organize the data
82 | in the PLC for better communication with an EPICS IOC.
83 |
84 | The protocol
85 | ------------------
86 |
87 | The name has changed: ControlNet-over-Ethernet has become EtherNet/IP.
88 |
89 | Tim McAdams, Technology Transfer and Services, Rockwell Automation
90 | confirmed that
91 | "EtherNet/IP is THE Ethernet protocol that the ControlLogix does and
92 | will support. RSLinx uses EtherNet/IP to communicate with ControlLogix,
93 | but also supports an older proprietary Ethernet protocol to communicate
94 | with PLC5 and SLC5/05 even though they also now support EtherNet/IP."
95 |
96 | So using EtherNet/IP is not some hack into the PLC
97 | but it's officially OK to do so.
98 |
99 | It's also confirmed by McAdams that ControlLogix does
100 | not, yet, support other parts of the protocol that
101 | would sent scheduled updates or updates on change.
102 | ControlLogix might support this in the future,
103 | the other PLCs won't. All it does now is "unconnected"
104 | and "Class 3 connected" messaging.
105 |
106 | I found a way to use the "Class 3 connected"
107 | method in EtherNet/IP.
108 | For non-Ethernet ControlNet, this reserves bandwidth
109 | and guaranties delivery (like TCP does anyway).
110 | For EtherNet/IP, it basically informs the PLC what to expect
111 | and the header for following packages is a few bytes smaller.
112 | But one can run into timeout problems this way,
113 | and the effort seems not to be worth it:
114 |
115 | Read single REAL value:
116 | original : 90.909091 values/sec, 11.000000 msec/value
117 | switched: 136.986301 values/sec, 7.300000 msec/value
118 | "Class 3": 140.845070 values/sec, 7.100000 msec/value
119 | (changed the office. PC and PLC used to be on a hub,
120 | now they are connected to a switch which gives slightly better results)
121 |
122 | So the following tests are done "unconnected" again.
123 | Not to be confused:
124 | It's still keeping the same socket open and registering
125 | the session only once, so the rates shown are for data transfer only,
126 | without initial connection/registration overhead.
127 |
128 | Test Results
129 | ------------
130 |
131 | -- There is a tradeoff between fast and nice-to-use. --
132 |
133 | For the SNS PLCs I assume 150 analogs and 350 binary channels.
134 | While older PLCs used "N7:10"
135 | which gives no clue about the meaning of the value,
136 | ControlLogix uses tags (<= 40 char), arrays, user-defined structures.
137 |
138 | We still have to document the meaning of "TSenWatIn",
139 | but I think this is nicer to use for
140 | "Temperature Sensor, Water at Inlet" than N7:10.
141 | It might also help to avoid errors:
142 | Misspelling it as TSensWatInn" gives an "invalid tag",
143 | using N7:11 would run fine but yield garbage.
144 |
145 | 1) Single transfer, readable tag
146 | --------------------------------
147 |
148 | Over EtherNet/IP I can read simple tags like:
149 | "TempSensor1_Value"
150 | as well as drill down structure/array tags:
151 | "Sensors.Temperature[2].value"
152 |
153 | This makes for readable code,
154 | the tags could conform to some naming convention.
155 |
156 | Reading a single REAL value like this takes 7 ms.
157 | The same for a single BOOL value.
158 |
159 | Reading the ~350 binary values for the SNS water skid
160 | would take almost 3 secs.
161 | Each single one arrives within 7ms, but the overall
162 | time might be too slow.
163 |
164 | 2) Multi-request transfer, readable tags
165 | ----------------------------------------
166 | Multiple read requests can be sent in one package.
167 | The package size for the request is limited to ~510 bytes,
168 | so is the response package size.
169 | When the tag names are long, fewer will fit a request.
170 | If the result contains arrays/structures, fewer will fit
171 | into the response.
172 | -> about 30 4-char REAL tags,
173 | 15 tags of the form "analog_10Hz.V21"
174 |
175 | When reading the individual elements of a structure
176 | like this, the per-value speed is increased over the
177 | previous example.
178 |
179 | structure analog_10Hz { REAL V1, REAL V2, ...., REAL V29 }
180 | Read as { analog_10Hz.V0, ..., analog_10Hz.V14 }
181 | (cannot read more than 15 items at once):
182 | 47.62 runs/sec, 21.00 msec/run -> 714.29 values/sec, 1.40 msec/value
183 |
184 | The overall latency is increased:
185 | The single value took 7ms.
186 | When requested as part of a multi-request,
187 | we have to wait for all the values (21ms).
188 |
189 | The 150 analogs could be read in ~0.21sec.
190 | Good enough?
191 |
192 | 3) Arrays
193 | ---------
194 | Arrays are still limited (size of response packet),
195 | but in an array the values are packet more tightly
196 | -> more values than in a multi-request.
197 |
198 | Transmitting a single tag that is a REAL[30]:
199 | 106.38 runs/sec, 9.40 msec/run -> 3191.49 values/sec, 0.31 msec/value
200 |
201 | Better: the 150 analogs, transfered as 5 REAL[30] arrays,
202 | would take 0.047secs
203 |
204 | They could be organized tag-wise like this:
205 | analog_10Hz = REAL[30] : array of analogs to be scanned @ 10Hz
206 | ...
207 | But the meaning of analog_10Hz[2] is unknown,
208 | we'd be back to the N7:10 addressing.
209 |
210 | Do we have to do this, pick speed over readability for analogs?
211 |
212 | For Binary arrays, the bits are actually packed:
213 | Array of BOOL[352] = 44 bytes, treated as 11 DINT:
214 | 130.43 runs/sec, 7.67 msec/run ->45913.04 values/sec, 0.02 msec/value
215 |
216 | MUCH BETTER: All the binaries for an SNS PLC can be transmitted
217 | in ~8msec!
218 | Again, the meaning of the individual bits has to be documented,
219 | but I think we have no other choice in this case.
220 |
221 | 4) Structures
222 | -------------
223 | A structure can be transfered element-by-element.
224 | -> case 1 or 2. Neat but not fast.
225 |
226 | Structures can also be read as a whole:
227 | Structure "analog_10Hz" with 30 REAL elements,
228 | read as whole tag "analog_10Hz" (all 30 items):
229 | 75.76 runs/sec, 13.20 msec/run -> 2272.73 values/sec, 0.44 msec/value
230 |
231 | This provides
232 | + better performance than reading the individual structure elements
233 | + the PLC code looks nice because the elements can have
234 | meaningful names, unlike array elements
235 | --- the structure is not exposed:
236 | The result is raw data.
237 | Over EtherNet/IP I cannot see that e.g. the third element
238 | in the structure is a "REAL" called "FacilityWaterTemperature".
239 |
240 | I asked my Rockwell contact for some help about this,
241 | but is seems that a structure transfer would again
242 | mean that we have to document the structure content
243 | in a detailed manner, so overall it's similar to the array case.
244 |
245 | ------------------------------------------------------------------
246 |
247 | So my conclusion for now is that I'll support
248 | a) Access to individual REALs and BOOLs.
249 | Requests will be combined as much as possible.
250 | Structure elements can be accessed like this,
251 | but it also increases the tag length
252 | -> fewer combined requests
253 |
254 | This is hopefully good enough for most analogs
255 |
256 | b) Access to arrays
257 | The array will be read as a whole.
258 | We have to document the meaning of each array element.
259 |
260 | This is necessary for most binaries
261 | and provides a tremendous jump in speed.
262 |
263 | Reading structures as a whole will not be supported.
264 |
265 |
266 | * Test 3
267 | ========
268 |
269 | Read 20 BOOL tags, one-by-one in multi request
270 |
271 | SentUnconnected:
272 | 33.33 runs/sec, 30.00 msec/run -> 666.67 values/sec, 1.50 msec/value
273 |
274 | Connected:
275 | 34.09 runs/sec, 29.33 msec/run -> 681.82 values/sec, 1.47 msec/value
276 |
277 |
278 | Again: Not worth the effort of possible timeouts
279 | when there is no activity within the times
280 | specified in Forward_Open?!
281 |
282 | * Test 4
283 | ========
284 |
285 | First test with driver running on an IOC under EPICS.
286 |
287 | -> dbnr
288 | 0130 ai
289 | 0001 ao
290 | 0354 bi
291 | 0005 bo
292 | 0001 calc
293 | 0002 mbbi
294 | 0002 mbbiDirect
295 | 0001 mbbo
296 | 0001 mbboDirect
297 |
298 | Most important:
299 |
300 | 352 BI records, reading the bits of a BOOL[352].
301 | Driver scans at 10Hz, records receive I/O Intr.
302 |
303 | 7 AI records for displaying driver statistics
304 | about the PLC and the BI records.
305 |
306 | 120 AI records, reading 3 x REAL[40].
307 | Driver scans at 1 Hz, records scan at 1 Hz.
308 |
309 | Histogram of BOOL[352] transfer:
310 | Transfer time hits
311 | ------------------
312 | 0.006 40
313 | 0.007 13617
314 | 0.008 17542
315 | 0.009 5762
316 | 0.01 3101
317 | 0.011 2522
318 | 0.012 1922
319 | 0.013 1233
320 | 0.014 602
321 | 0.015 141
322 | 0.016 38
323 | 0.017 14
324 | 0.018 9
325 | 0.019 3
326 | 0.02 1
327 |
328 | I increased the vxWorks tick counter to get better statistics:
329 | sysClkRateSet 1000 (default is 60).
330 |
331 | After running for 1h, 15 min, the histogram of the BOOL[352] transfers
332 | shows that most transactions take 8ms, matching the previous protocol tests.
333 | Sometimes, though, it takes up to 20ms to get the BOOL array into the IOC.
334 | Why? General network traffic? Also:
335 | I've seen before that the PLC doesn't suffer under communication.
336 | Its time to run over the ladder logix stays the same. I guess this is
337 | because it has a dedicated communication time slice.
338 | So if the IOC asks for a value and the PLC is not ready to respond
339 | since the communication time is over, the transfer is handled in the
340 | next time slice.
341 |
342 | As for the analog values:
343 | They are transferred as three REAL[30] arrays.
344 | Each array arrives after about 9ms.
345 | The total transfer time for the three REAL[30] is:
346 | min 16 ms
347 | max 29 ms
348 | usual 18 ms
349 |
350 | (Note that most of the time it's 18ms, not 3x9ms.
351 | Two of those REAL[30] requests are actually combined in the driver
352 | because they fit the 500byte buffer limit.)
353 |
354 | Addendum:
355 | After one week, the max. scan time for the BOOLs[352] was 0.15secs,
356 | no errors.
--------------------------------------------------------------------------------
/ether_ipApp/src/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile
2 | TOP = ../..
3 |
4 | include $(TOP)/configure/CONFIG
5 | #----------------------------------------
6 | # ADD MACRO DEFINITIONS AFTER THIS LINE
7 |
8 | # On Darwin, got errors about unused assignment in recGblSetSevr
9 | USR_CFLAGS_Darwin += -Wno-unused-value
10 |
11 | # On WIN32, have to add socket library
12 | # to build the test program
13 | SYS_PROD_LIBS_WIN32 = wsock32
14 |
15 | ifdef BASE_3_15
16 | devEtherIP_CFLAGS += -DBUILD_LONG_STRING_SUPPORT
17 | USR_CFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET -DUSE_TYPED_DRVET
18 |
19 | # Since base 3_15, on Linux 64 and Mac, support LINT
20 | ifeq ($(SUPPORT_LINT),YES)
21 | USR_CFLAGS += -DSUPPORT_LINT
22 | USR_CPPFLAGS += -DSUPPORT_LINT
23 | ETHER_IP_DBD = ether_ip-lint.dbd
24 | else
25 | ETHER_IP_DBD = ether_ip-lsio.dbd
26 | endif
27 |
28 | else
29 | ETHER_IP_DBD = ether_ip-3-14.dbd
30 | endif
31 |
32 | PROD_HOST += ether_ip_test
33 | ether_ip_test_SRCS += ether_ip_test.c
34 | ether_ip_test_LIBS += Com
35 | ether_ip_test_SYS_LIBS_solaris += socket
36 | ether_ip_test_SYS_LIBS_solaris += nsl
37 |
38 | DBD = ether_ip.dbd
39 |
40 | LIBRARY_IOC = ether_ip
41 |
42 | INC += eip_bool.h
43 | INC += dl_list.h
44 | INC += ether_ip.h
45 | INC += drvEtherIP.h
46 |
47 | # create munch file for dynamic loading will install in
48 | PROD_IOC_vxWorks += ether_ipLib
49 |
50 | LIB_LIBS += $(EPICS_BASE_IOC_LIBS)
51 | DLL_LIBS = ca Com
52 | SYS_DLL_LIBS = wsock32
53 | ether_ip_RCS_WIN32 = ether_ip.rc
54 |
55 | ether_ip_SRCS += dl_list.c
56 | ether_ip_SRCS += ether_ip.c
57 | ether_ip_SRCS += drvEtherIP.c
58 | ether_ip_SRCS += devEtherIP.c
59 | ether_ip_SRCS += drvEtherIPRegister.cpp
60 |
61 | # The PROD_IOC_vxWorks is built from the same srcs and must include
62 | # the registry routines.
63 | ether_ipLib_SRCS+=$(ether_ip_SRCS)
64 | ether_ipLib_SRCS+= ether_ip_registerRecordDeviceDriver.cpp
65 |
66 | include $(TOP)/configure/RULES
67 | #----------------------------------------
68 | # ADD RULES AFTER THIS LINE
69 |
70 | ether_ip.dbd$(DEP): ../Makefile
71 | @$(RM) $@
72 | @echo $(COMMON_DIR)/ether_ip.dbd:> $@
73 |
74 | $(COMMON_DIR)/ether_ip.dbd: ../$(ETHER_IP_DBD)
75 | @$(RM) $@
76 | $(CP) $< $@
77 |
--------------------------------------------------------------------------------
/ether_ipApp/src/dl_list.c:
--------------------------------------------------------------------------------
1 | #include "dl_list.h"
2 |
3 | /* Remove head node from list (doesn't free node)
4 | * Returns 0 for empty list
5 | */
6 | void *DLL_decap (DL_List *list)
7 | {
8 | DLL_Node *node = list->first;
9 | if (! node)
10 | return 0;
11 |
12 | list->first = node->next;
13 | if (list->last == node)
14 | list->last = 0;
15 | return node;
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/ether_ipApp/src/dl_list.h:
--------------------------------------------------------------------------------
1 | #ifndef DLL_init
2 | /* Double-linked list */
3 |
4 | typedef struct __dll_node DLL_Node;
5 | struct __dll_node
6 | {
7 | DLL_Node *prev;
8 | DLL_Node *next;
9 | };
10 |
11 | typedef struct
12 | {
13 | DLL_Node *first;
14 | DLL_Node *last;
15 | } DL_List;
16 |
17 | #define DLL_init(list) \
18 | { \
19 | (list)->first = 0; \
20 | (list)->last = 0; \
21 | }
22 |
23 | #define DLL_first(T, list) \
24 | (T*)(list)->first
25 |
26 | #define DLL_last(T, list) \
27 | (T*)(list)->last
28 |
29 | #define DLL_next(T, node) \
30 | (T*)((DLL_Node*)(node))->next
31 |
32 | #define DLL_prev(T, node) \
33 | (T*)((DLL_Node*)(node))->prev
34 |
35 | /* Add single node to end of list */
36 | #define DLL_append(list, node) \
37 | { \
38 | if ((list)->first == 0) \
39 | (list)->first = (DLL_Node*)(node); \
40 | ((DLL_Node*)(node))->prev = (list)->last; \
41 | ((DLL_Node*)(node))->next = 0; \
42 | if ((list)->last) \
43 | (list)->last->next = (DLL_Node*)(node); \
44 | (list)->last = (DLL_Node*)(node); \
45 | }
46 |
47 | /* Remove node from list (doesn't free node) */
48 | #define DLL_unlink(list, node) \
49 | { \
50 | if ((list)->first == (DLL_Node*)(node)) \
51 | (list)->first = ((DLL_Node*)(node))->next; \
52 | else \
53 | ((DLL_Node*)(node))->prev->next = ((DLL_Node*)(node))->next; \
54 | if ((list)->last == (DLL_Node*)(node)) \
55 | (list)->last =((DLL_Node*)(node))->prev; \
56 | else \
57 | ((DLL_Node*)(node))->next->prev = ((DLL_Node*)(node))->prev; \
58 | ((DLL_Node*)(node))->prev = 0; \
59 | ((DLL_Node*)(node))->next = 0; \
60 | }
61 |
62 | /* Remove head node from list (doesn't free node)
63 | * Returns 0 for empty list
64 | */
65 | void *DLL_decap (DL_List *list);
66 |
67 | #endif
68 |
69 |
70 |
--------------------------------------------------------------------------------
/ether_ipApp/src/drvEtherIP.h:
--------------------------------------------------------------------------------
1 | /* drvEtherIP
2 | *
3 | * IOC driver that uses ether_ip routines,
4 | * keeping lists of PLCs and tags and scanlists etc.
5 | *
6 | * kasemirk@ornl.gov
7 | */
8 |
9 | #ifndef ETHERIP_MAYOR
10 |
11 | #include "epicsMutex.h"
12 | #include "epicsEvent.h"
13 | #include "epicsThread.h"
14 | #include "epicsTime.h"
15 |
16 | #include "ether_ip.h"
17 | #include "dl_list.h"
18 |
19 | #define ETHERIP_MAYOR 3
20 | #define ETHERIP_MINOR 7
21 |
22 | /* For timing */
23 | #define EIP_MIN_TIMEOUT 0.1 /* second */
24 | #define EIP_MIN_CONN_TIMEOUT 1.0 /* second */
25 |
26 | /* TCP port */
27 | #define ETHERIP_PORT 0xAF12
28 |
29 | /* TCP timeout in millisec for connection and readback */
30 | extern int EIP_TIMEOUT;
31 |
32 | typedef struct __TagInfo TagInfo; /* forwards */
33 | typedef struct __ScanList ScanList;
34 | typedef struct __PLC PLC;
35 |
36 | /* THE singleton main structure for this driver
37 | * Note that each PLC entry has it's own lock
38 | * for the scanlists & statistics.
39 | * Each PLC's scan task uses that per-PLC lock,
40 | * calls to loop/add/list PLCs also use this
41 | * more global lock.
42 | */
43 | typedef struct
44 | {
45 | DL_List PLCs; /* List of PLC structs */
46 | epicsMutexId lock;
47 | } DrvEtherIP_Private;
48 |
49 | /* PLCInfo:
50 | * Per-PLC information
51 | * Generated with call to drvEtherIP_define_PLC
52 | * in IOC startup file.
53 | *
54 | * Holds
55 | * - EIPConnection for ether_ip protocol routines
56 | * - ScanList for this PLC, filled by device support
57 | */
58 | struct __PLC
59 | {
60 | DLL_Node node;
61 | epicsMutexId lock;
62 | char *name; /* symbolic name, used to identify PLC */
63 | char *ip_addr; /* IP or DNS name that IOC knows */
64 | int slot; /* slot in ControlLogix Backplane: 0, ... */
65 | size_t plc_errors; /* # of communication errors */
66 | size_t slow_scans; /* Count: scan task is getting late */
67 | EIPConnection *connection;
68 | DL_List scanlists; /* List of struct ScanList */
69 | epicsThreadId scan_task_id;
70 | };
71 |
72 | /* ScanList:
73 | * A list of TagInfos,
74 | * to be scanned at the same rate
75 | */
76 | struct __ScanList
77 | {
78 | DLL_Node node;
79 | PLC *plc; /* PLC to which this Scanlist belongs */
80 | eip_bool enabled;
81 | double period; /* scan period [secs] */
82 | size_t list_errors; /* # of communication errors */
83 | size_t sched_errors; /* # of scheduling errors */
84 | epicsTimeStamp scan_time; /* stamp of last run time */
85 | epicsTimeStamp scheduled_time; /* stamp for next run time */
86 | double min_scan_time; /* statistics: scan time in seconds */
87 | double max_scan_time; /* minimum, maximum, */
88 | double last_scan_time; /* and most recent scan */
89 | DL_List taginfos; /* List of struct TagInfo */
90 | };
91 |
92 | typedef void (*EIPCallback) (void *arg);
93 | typedef struct
94 | {
95 | DLL_Node node;
96 | EIPCallback callback; /* called for each value */
97 | void *arg;
98 | } TagCallback;
99 |
100 | /* TagInfo:
101 | * Information for a single tag:
102 | * Actual tag, how many elements are requested,
103 | * size for request/response, ...
104 | *
105 | * TagInfos are held in list.
106 | * Naming in here: "tag" is a single TagInfo,
107 | * "tags" is used when the whole list is meant.
108 | *
109 | * A cip_request_size of 0 will cause this tag
110 | * to be skipped in read/write operations.
111 | *
112 | * See Locking info in drvEtherIP.c for details
113 | * on locking as well as cip_request/response size
114 | * and the do_write flag.
115 | */
116 | struct __TagInfo
117 | {
118 | DLL_Node node;
119 | ScanList *scanlist; /* list this tag in on */
120 | char *string_tag; /* tag as text */
121 | ParsedTag *tag; /* tag, compiled */
122 | size_t elements; /* array elements to read (or 1) */
123 | size_t cip_r_request_size; /* byte-size of read request */
124 | size_t cip_r_response_size;/* byte-size of read response */
125 | size_t cip_w_request_size; /* byte-size of write request */
126 | size_t cip_w_response_size;/* byte-size of write response */
127 | epicsMutexId data_lock; /* see "locking" in drvEtherIP.c */
128 | size_t data_size; /* total size of data buffer */
129 | size_t valid_data_size; /* used portion of data, 0 for "invalid" */
130 | eip_bool do_write; /* set by device, reset by driver */
131 | eip_bool is_writing; /* driver copy of do_write for cycle */
132 | CN_USINT *data; /* CIP data (type, raw data), with buffer capacity of data_size */
133 | double transfer_time; /* time needed for last transfer */
134 | DL_List callbacks; /* TagCallbacks for new values&write done */
135 | };
136 |
137 | #ifdef __cplusplus
138 | extern "C" {
139 | #endif
140 |
141 | extern double drvEtherIP_default_rate;
142 |
143 | void drvEtherIP_help();
144 |
145 | int drvEtherIP_initialized();
146 |
147 | void drvEtherIP_init();
148 |
149 | long drvEtherIP_report(int level);
150 |
151 | void drvEtherIP_dump();
152 |
153 | void drvEtherIP_reset_statistics();
154 |
155 | eip_bool drvEtherIP_define_PLC(const char *PLC_name,
156 | const char *ip_addr, int slot);
157 |
158 | PLC *drvEtherIP_find_PLC(const char *PLC_name);
159 |
160 | TagInfo *drvEtherIP_add_tag(PLC *plc, double period,
161 | const char *string_tag, size_t elements);
162 | /* Register callbacks for "received new data" and "finished the write".
163 | * Note: The data is already locked (data_lock taken)
164 | * when the callback is called!
165 | */
166 | void drvEtherIP_add_callback(PLC *plc, TagInfo *tag,
167 | EIPCallback callback, void *arg);
168 | void drvEtherIP_remove_callback(PLC *plc, TagInfo *tag,
169 | EIPCallback callback, void *arg);
170 |
171 | int drvEtherIP_restart();
172 |
173 | /* Command-line communication test,
174 | * not used by the driver */
175 | int drvEtherIP_read_tag(const char *ip_addr,
176 | int slot,
177 | const char *tag_name,
178 | int elements,
179 | int timeout);
180 |
181 | void drvEtherIP_Register();
182 |
183 | #ifdef __cplusplus
184 | }
185 | #endif
186 |
187 | #endif
188 |
189 |
--------------------------------------------------------------------------------
/ether_ipApp/src/drvEtherIPRegister.cpp:
--------------------------------------------------------------------------------
1 | /*drvEtherIPRegister.cpp */
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include "iocsh.h"
10 | #include "epicsExport.h"
11 | #include "drvEtherIP.h"
12 |
13 | #ifdef __cplusplus
14 | extern "C" {
15 | #endif /* __cplusplus */
16 |
17 | static const iocshArg drvEtherIP_default_rateArg0 = {"value", iocshArgDouble};
18 | static const iocshArg *const drvEtherIP_default_rateArgs[1] = {&drvEtherIP_default_rateArg0};
19 | static const iocshFuncDef drvEtherIP_default_rateDef = {"drvEtherIP_default_rate", 1, drvEtherIP_default_rateArgs};
20 | static void drvEtherIP_default_rateCall(const iocshArgBuf * args) {
21 | drvEtherIP_default_rate = args[0].dval;
22 | }
23 |
24 | static const iocshArg EIP_verbosityArg0 = {"value", iocshArgInt};
25 | static const iocshArg *const EIP_verbosityArgs[1] = {&EIP_verbosityArg0};
26 | static const iocshFuncDef EIP_verbosityDef = {"EIP_verbosity", 1, EIP_verbosityArgs};
27 | static void EIP_verbosityCall(const iocshArgBuf * args) {
28 | EIP_verbosity = args[0].ival;
29 | }
30 |
31 | static const iocshArg EIP_timeoutArg0 = {"value", iocshArgInt};
32 | static const iocshArg *const EIP_timeoutArgs[1] = {&EIP_timeoutArg0};
33 | static const iocshFuncDef EIP_timeoutDef = {"EIP_timeout", 1, EIP_timeoutArgs};
34 | static void EIP_timeoutCall(const iocshArgBuf * args) {
35 | EIP_TIMEOUT = args[0].ival;
36 | }
37 |
38 | static const iocshArg EIP_buffer_limitArg0 = {"bytes", iocshArgInt};
39 | static const iocshArg *const EIP_buffer_limitArgs[1] = {&EIP_buffer_limitArg0};
40 | static const iocshFuncDef EIP_buffer_limitDef = {"EIP_buffer_limit", 1, EIP_buffer_limitArgs};
41 | static void EIP_buffer_limitCall(const iocshArgBuf * args) {
42 | printf("Changing buffer limit from %lu ",
43 | (unsigned long) EIP_buffer_limit);
44 | EIP_buffer_limit = args[0].ival;
45 | printf("to %lu bytes\n",
46 | (unsigned long) EIP_buffer_limit);
47 | }
48 |
49 | static const iocshFuncDef drvEtherIP_helpDef =
50 | {"drvEtherIP_help", 0, 0};
51 | static void drvEtherIP_helpCall(const iocshArgBuf * args) {
52 | drvEtherIP_help();
53 | }
54 |
55 | static const iocshFuncDef drvEtherIP_initDef =
56 | {"drvEtherIP_init", 0, 0};
57 | static void drvEtherIP_initCall(const iocshArgBuf * args) {
58 | drvEtherIP_init();
59 | }
60 |
61 | static const iocshFuncDef drvEtherIP_restartDef =
62 | {"drvEtherIP_restart", 0, 0};
63 | static void drvEtherIP_restartCall(const iocshArgBuf * args) {
64 | drvEtherIP_restart();
65 | }
66 |
67 | static const iocshFuncDef drvEtherIP_dumpDef =
68 | {"drvEtherIP_dump", 0, 0};
69 | static void drvEtherIP_dumpCall(const iocshArgBuf * args) {
70 | drvEtherIP_dump();
71 | }
72 |
73 | static const iocshFuncDef drvEtherIP_reset_statisticsDef =
74 | {"drvEtherIP_reset_statistics", 0, 0};
75 | static void drvEtherIP_reset_statisticsCall(const iocshArgBuf * args) {
76 | drvEtherIP_reset_statistics();
77 | }
78 |
79 | static const iocshArg drvEtherIP_reportArg0 = {"value", iocshArgInt};
80 | static const iocshArg *const drvEtherIP_reportArgs[1] = {&drvEtherIP_reportArg0};
81 | static const iocshFuncDef drvEtherIP_reportDef = {"drvEtherIP_report", 1, drvEtherIP_reportArgs};
82 | static void drvEtherIP_reportCall(const iocshArgBuf * args) {
83 | drvEtherIP_report(args[0].ival);
84 | }
85 |
86 | static const iocshArg drvEtherIP_define_PLCArg0 = {"plc_name", iocshArgString};
87 | static const iocshArg drvEtherIP_define_PLCArg1 = {"ip_addr" , iocshArgString};
88 | static const iocshArg drvEtherIP_define_PLCArg2 = {"slot" , iocshArgInt };
89 | static const iocshArg * const drvEtherIP_define_PLCArgs[3] =
90 | {&drvEtherIP_define_PLCArg0, &drvEtherIP_define_PLCArg1, &drvEtherIP_define_PLCArg2};
91 | static const iocshFuncDef drvEtherIP_define_PLCDef = {"drvEtherIP_define_PLC", 3, drvEtherIP_define_PLCArgs};
92 | static void drvEtherIP_define_PLCCall(const iocshArgBuf * args) {
93 | drvEtherIP_define_PLC(args[0].sval, args[1].sval, args[2].ival);
94 | }
95 |
96 | static const iocshArg drvEtherIP_read_tagArg0 = {"ip_addr" , iocshArgString};
97 | static const iocshArg drvEtherIP_read_tagArg1 = {"slot" , iocshArgInt };
98 | static const iocshArg drvEtherIP_read_tagArg2 = {"tag_name", iocshArgString};
99 | static const iocshArg drvEtherIP_read_tagArg3 = {"elements", iocshArgInt };
100 | static const iocshArg drvEtherIP_read_tagArg4 = {"timeout" , iocshArgInt };
101 | static const iocshArg * const drvEtherIP_read_tagArgs[5] =
102 | {&drvEtherIP_read_tagArg0, &drvEtherIP_read_tagArg1, &drvEtherIP_read_tagArg2,
103 | &drvEtherIP_read_tagArg3, &drvEtherIP_read_tagArg4};
104 | static const iocshFuncDef drvEtherIP_read_tagDef = {"drvEtherIP_read_tag", 5, drvEtherIP_read_tagArgs};
105 | static void drvEtherIP_read_tagCall(const iocshArgBuf * args) {
106 | drvEtherIP_read_tag(args[0].sval, args[1].ival, args[2].sval,
107 | args[3].ival, args[4].ival);
108 | }
109 |
110 | void drvEtherIP_Register() {
111 | iocshRegister(&drvEtherIP_default_rateDef, drvEtherIP_default_rateCall);
112 | iocshRegister(&EIP_verbosityDef , EIP_verbosityCall);
113 | iocshRegister(&EIP_timeoutDef , EIP_timeoutCall);
114 | iocshRegister(&EIP_buffer_limitDef , EIP_buffer_limitCall);
115 | iocshRegister(&drvEtherIP_helpDef , drvEtherIP_helpCall);
116 | iocshRegister(&drvEtherIP_initDef , drvEtherIP_initCall);
117 | iocshRegister(&drvEtherIP_restartDef , drvEtherIP_restartCall);
118 | iocshRegister(&drvEtherIP_dumpDef , drvEtherIP_dumpCall);
119 | iocshRegister(&drvEtherIP_reset_statisticsDef, drvEtherIP_reset_statisticsCall);
120 | iocshRegister(&drvEtherIP_reportDef , drvEtherIP_reportCall);
121 | iocshRegister(&drvEtherIP_define_PLCDef, drvEtherIP_define_PLCCall);
122 | iocshRegister(&drvEtherIP_read_tagDef , drvEtherIP_read_tagCall);
123 | }
124 | #ifdef __cplusplus
125 | }
126 | #endif /* __cplusplus */
127 |
128 | epicsExportRegistrar(drvEtherIP_Register);
129 |
--------------------------------------------------------------------------------
/ether_ipApp/src/eip_bool.h:
--------------------------------------------------------------------------------
1 | #ifndef EIP_BOOL_H_
2 | #define EIP_BOOL_H_
3 |
4 | /* Andrew Johnson (ANL) found an issue with bool/true/false
5 | * and a PPC604-with-Altivec compiler, so we use eip_bool
6 | * and are careful not to redefine 'true'.
7 | */
8 | typedef int eip_bool;
9 | #ifndef __cplusplus
10 | #ifndef true
11 | #define true 1
12 | #define false 0
13 | #endif
14 | #endif
15 |
16 | #endif /*EIP_BOOL_H_*/
17 |
--------------------------------------------------------------------------------
/ether_ipApp/src/ether_ip-3-14.dbd:
--------------------------------------------------------------------------------
1 | # EtherIP for EPICS 3.14 (no long string, no int64)
2 |
3 | # Device support definitions
4 | device(ai, INST_IO, devAiEtherIP, "EtherIP")
5 | device(bi, INST_IO, devBiEtherIP, "EtherIP")
6 | device(mbbi, INST_IO, devMbbiEtherIP, "EtherIP")
7 | device(mbbiDirect, INST_IO, devMbbiDirectEtherIP, "EtherIP")
8 | device(stringin, INST_IO, devSiEtherIP, "EtherIP")
9 | device(waveform, INST_IO, devWfEtherIP, "EtherIP")
10 | device(ao, INST_IO, devAoEtherIP, "EtherIP")
11 | device(bo, INST_IO, devBoEtherIP, "EtherIP")
12 | device(bo, INST_IO, devBoEtherIPReset, "EtherIPReset")
13 | device(mbbo, INST_IO, devMbboEtherIP, "EtherIP")
14 | device(mbboDirect, INST_IO, devMbboDirectEtherIP, "EtherIP")
15 | device(stringout, INST_IO, devSoEtherIP, "EtherIP")
16 |
17 | # Other registration
18 | driver(drvEtherIP)
19 | registrar(drvEtherIP_Register)
20 |
--------------------------------------------------------------------------------
/ether_ipApp/src/ether_ip-lint.dbd:
--------------------------------------------------------------------------------
1 | # EtherIP for EPICS 3.15+ with long string and int64 support
2 |
3 | # Declarations to support dynamic loading
4 | recordtype(ai ) {}
5 | recordtype(int64in ) {}
6 | recordtype(bi ) {}
7 | recordtype(lsi ) {}
8 | recordtype(mbbi ) {}
9 | recordtype(mbbiDirect) {}
10 | recordtype(stringin ) {}
11 | recordtype(waveform ) {}
12 | recordtype(ao ) {}
13 | recordtype(int64out ) {}
14 | recordtype(bo ) {}
15 | recordtype(lso ) {}
16 | recordtype(mbbo ) {}
17 | recordtype(mbboDirect) {}
18 | recordtype(stringout ) {}
19 |
20 | # Device support definitions
21 | device(ai, INST_IO, devAiEtherIP, "EtherIP")
22 | device(int64in, INST_IO, devInt64inEtherIP, "EtherIP")
23 | device(bi, INST_IO, devBiEtherIP, "EtherIP")
24 | device(lsi, INST_IO, devLsiEtherIP, "EtherIP")
25 | device(mbbi, INST_IO, devMbbiEtherIP, "EtherIP")
26 | device(mbbiDirect, INST_IO, devMbbiDirectEtherIP, "EtherIP")
27 | device(stringin, INST_IO, devSiEtherIP, "EtherIP")
28 | device(waveform, INST_IO, devWfEtherIP, "EtherIP")
29 | device(ao, INST_IO, devAoEtherIP, "EtherIP")
30 | device(int64out, INST_IO, devInt64outEtherIP, "EtherIP")
31 | device(bo, INST_IO, devBoEtherIP, "EtherIP")
32 | device(bo, INST_IO, devBoEtherIPReset, "EtherIPReset")
33 | device(lso, INST_IO, devLsoEtherIP, "EtherIP")
34 | device(mbbo, INST_IO, devMbboEtherIP, "EtherIP")
35 | device(mbboDirect, INST_IO, devMbboDirectEtherIP, "EtherIP")
36 | device(stringout, INST_IO, devSoEtherIP, "EtherIP")
37 |
38 | # Other registration
39 | driver(drvEtherIP)
40 | registrar(drvEtherIP_Register)
41 |
--------------------------------------------------------------------------------
/ether_ipApp/src/ether_ip-lsio.dbd:
--------------------------------------------------------------------------------
1 | # EtherIP for EPICS 3.15+ with long string support
2 |
3 | # Declarations to support dynamic loading
4 | recordtype(ai ) {}
5 | recordtype(bi ) {}
6 | recordtype(lsi ) {}
7 | recordtype(mbbi ) {}
8 | recordtype(mbbiDirect) {}
9 | recordtype(stringin ) {}
10 | recordtype(waveform ) {}
11 | recordtype(ao ) {}
12 | recordtype(bo ) {}
13 | recordtype(lso ) {}
14 | recordtype(mbbo ) {}
15 | recordtype(mbboDirect) {}
16 | recordtype(stringout ) {}
17 |
18 | # Device support definitions
19 | device(ai, INST_IO, devAiEtherIP, "EtherIP")
20 | device(bi, INST_IO, devBiEtherIP, "EtherIP")
21 | device(lsi, INST_IO, devLsiEtherIP, "EtherIP")
22 | device(mbbi, INST_IO, devMbbiEtherIP, "EtherIP")
23 | device(mbbiDirect, INST_IO, devMbbiDirectEtherIP, "EtherIP")
24 | device(stringin, INST_IO, devSiEtherIP, "EtherIP")
25 | device(waveform, INST_IO, devWfEtherIP, "EtherIP")
26 | device(ao, INST_IO, devAoEtherIP, "EtherIP")
27 | device(bo, INST_IO, devBoEtherIP, "EtherIP")
28 | device(bo, INST_IO, devBoEtherIPReset, "EtherIPReset")
29 | device(lso, INST_IO, devLsoEtherIP, "EtherIP")
30 | device(mbbo, INST_IO, devMbboEtherIP, "EtherIP")
31 | device(mbboDirect, INST_IO, devMbboDirectEtherIP, "EtherIP")
32 | device(stringout, INST_IO, devSoEtherIP, "EtherIP")
33 |
34 | # Other registration
35 | driver(drvEtherIP)
36 | registrar(drvEtherIP_Register)
37 |
--------------------------------------------------------------------------------
/ether_ipApp/src/ether_ip.h:
--------------------------------------------------------------------------------
1 | /* ether_ip.h
2 | *
3 | * EtherNet/IP routines for Win32, Unix, vxWorks, and RTEMS.
4 | *
5 | * EtherNet/IP started as "ControlNet over Ethernet" (www.controlnet.org),
6 | * now defined as ODVA's "EtherNet/IP" (www.odva.org)
7 | *
8 | * Docs: "Spec" = ControlNet Spec. version 2.0, Errata 1
9 | * "ENET" = AB Publication 1756-RM005A-EN-E
10 | *
11 | * kasemirk@ornl.gov
12 | */
13 |
14 | #ifndef NO_EPICS
15 | #include"epicsVersion.h"
16 | #endif
17 |
18 |
19 | /* The socket compatibility stuff is stolen from R3.13 osiSock.h.
20 | * The R3.14 osiSock is a tad different, so we use neither "as is"
21 | * but have it all in here.
22 | */
23 | /* sys-independ. socket stuff, basically stolen from osiSock.h */
24 | #ifdef _WIN32
25 | #include
26 | #pragma pack(push, 1)
27 |
28 | #define EIP_SOCKET SOCKET
29 | #define EIP_INVALID_SOCKET INVALID_SOCKET
30 | #define EIP_SOCKERRNO WSAGetLastError()
31 | #define EIP_socket_close(S) closesocket(S)
32 | #define EIP_socket_ioctl(A,B,C) ioctlsocket(A,B,C)
33 | #define EIP_SOCK_EWOULDBLOCK WSAEWOULDBLOCK
34 | #define EIP_SOCK_EINPROGRESS WSAEINPROGRESS
35 | /* end of Win32 settings */
36 |
37 | #else
38 |
39 | #ifdef vxWorks
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 | #include
46 | #include
47 | #include
48 | #include
49 | #include
50 | #include
51 | #include
52 | #include
53 | #include
54 | #include
55 | #include
56 | #include
57 | #include
58 | typedef int EIP_SOCKET;
59 | #define EIP_INVALID_SOCKET (-1)
60 | #define EIP_SOCKERRNO errno
61 | #define EIP_socket_close(S) close(S)
62 | #define EIP_socket_ioctl(A,B,C) ioctl(A,B,(int)C)
63 | #define EIP_SOCK_EWOULDBLOCK EWOULDBLOCK
64 | #define EIP_SOCK_EINPROGRESS EINPROGRESS
65 | /* end of vxWorks settings */
66 |
67 | #else
68 |
69 | /* Unix settings */
70 | #include
71 | #include
72 | #include
73 | #include
74 | #include
75 | #include
76 | #include
77 | #include
78 | #include
79 | #include
80 | #include
81 | typedef int EIP_SOCKET;
82 | #define EIP_INVALID_SOCKET (-1)
83 | #define EIP_SOCKERRNO errno
84 | #define EIP_socket_close(S) close(S)
85 | #define EIP_socket_ioctl(A,B,C) ioctl(A,B,C)
86 | #define EIP_SOCK_EWOULDBLOCK EWOULDBLOCK
87 | #define EIP_SOCK_EINPROGRESS EINPROGRESS
88 |
89 | #ifdef SOLARIS
90 | #include
91 | #endif
92 |
93 | /* end of Unix settings */
94 | #endif
95 | #endif
96 |
97 | #include "eip_bool.h"
98 |
99 | /* This could be an application on its own...
100 | * Rough idea:
101 | * 10: Dump all protocol details
102 | * 9: Hexdump each sent/received buffer
103 | *
104 | * 6: show driver details
105 | * 5: device will show write-related operations
106 | *
107 | * 2: show more error info: "xxx failed because..."
108 | * 1: show error messages: "xxx failed"
109 | * 0: keep quiet
110 | */
111 | extern int EIP_verbosity;
112 |
113 | /* print if EIP_verbosity >= level */
114 | void EIP_printf(int level, const char *format, ...);
115 |
116 | /* print with time stamp if EIP_verbosity >= level */
117 | void EIP_printf_time(int level, const char *format, ...);
118 |
119 | void EIP_hexdump(int level, const void *_data, int len);
120 |
121 | /* There is a limit for the PLC transfer buffer.
122 | * Spec page 2-5 mentions 504 bytes as the CIP UCMM limit,
123 | * Spec page 156 in version 2.0, errata 2 mentions 511 bytes
124 | * as the Forward_Open connection size limit.
125 | * None if this tells me exactly where the limit is
126 | * and whether it's 500 or 504 or ??
127 | * Is it in the PLC controller, so the Ethernet overhead
128 | * (encapsulation header) is handled by the ENET module
129 | * and does not count?
130 | * Is it in the ENET module, so the total including encapsulation
131 | * is limited?
132 | *
133 | * Test: Used command-line EtherIP tool to read elements of SINT[].
134 | * 492 elements: Results in 538 byte response, OK
135 | * 493 elements: Results in 538 byte response, Fault
136 | * (error 0x06, Buffer too small, partial data only)
137 | * Likewise INT[] array: <=246 elements, <=538 byte response, OK
138 | * Note: That command-line tool sends a single read request.
139 | * The EPICS driver sends read/write requests within
140 | * a multi-request, so the individual array reads must
141 | * be slightly smaller for the driver! While the command-line
142 | * tool can read INT[246], the driver cannot!
143 | *
144 | * Possible conclusions:
145 | * -> Total response limited to 538 bytes?
146 | * 538 - EncapsulationHeader(24) = 514
147 | * - RR Data handle & timeout(6) = 508
148 | * - RR Data packet head.:count, address,..., length (10) = 498
149 | * -> MR_Response & data limited to 498 bytes?
150 | *
151 | * Tests w/ driver on IOC indicated that PLC also complains when
152 | * the _request_ reaches 538 bytes
153 | * -> request & response each limited to 538 bytes.
154 | *
155 | * These macros used to be the best guess for the buffer
156 | * plus the protocol overhead (encap. header), using
157 | * 538 - EIP_PROTOCOL_OVERHEAD
158 | * to fit the Multi-Request.
159 | * The response has an overhead of 40 bytes, see above: 24+6+10.
160 | * The request has an overhead of 52 bytes.
161 | *
162 | * However, the SNS CF PLCs seem to work best with a buffer limit
163 | * of 500, so that's now the EIP_DEFAULT_BUFFER_LIMIT.
164 | *
165 | * Overall, the driver uses a buffer of EIP_BUFFER_LIMIT bytes,
166 | * so nothing bigger than that can be transferred.
167 | */
168 |
169 | /** Limit used by the driver when constructing requests and
170 | * watching expected responses
171 | */
172 | extern int EIP_buffer_limit;
173 |
174 | /** Best estimate for EIP_buffer_limit */
175 | #define EIP_DEFAULT_BUFFER_LIMIT 480
176 |
177 | /** Used to be used to determine EIP_DEFAULT_BUFFER_LIMIT, but
178 | * didn't work out
179 | */
180 | #define EIP_PROTOCOL_OVERHEAD 52
181 |
182 | /** Absolute maximum for EIP_buffer_limit because this is the
183 | * buffer size that the driver uses to allocate the initial
184 | * buffer.
185 | */
186 | #define EIP_BUFFER_SIZE 580
187 |
188 | /********************************************************
189 | * ControlNet data types
190 | * Spec 5 p 3
191 | ********************************************************/
192 |
193 | /* ControlNet uses Little Endian, not the common IP format!
194 | * Exception:
195 | * Addresses packed at sockaddr_in are in network order as usual.
196 | */
197 | typedef signed char CN_SINT;
198 | typedef unsigned char CN_USINT;
199 | typedef unsigned short CN_UINT;
200 | typedef short CN_INT;
201 | typedef unsigned int CN_UDINT;
202 | typedef int CN_DINT;
203 | typedef float CN_REAL;
204 | typedef double CN_LREAL;
205 | #ifdef SUPPORT_LINT
206 | typedef long long CN_LINT;
207 | typedef unsigned long long CN_ULINT;
208 | #else
209 | #warning No 64 bit LINT/ULINT support
210 | #endif
211 |
212 | typedef enum
213 | {
214 | C_Identity = 0x01,
215 | C_MessageRouter = 0x02,
216 | C_ConnectionManager = 0x06
217 | } CN_Classes;
218 |
219 | /********************************************************
220 | * Message Router PDU (Protocol Data Unit)
221 | ********************************************************/
222 |
223 | typedef enum /* Spec 4, p.36 */
224 | {
225 | S_Get_Attribute_All = 0x01,
226 | S_Get_Attribute_Single = 0x0E,
227 | S_CIP_MultiRequest = 0x0A, /* Logix5000 Data Access */
228 | S_CIP_ReadData = 0x4C, /* Logix5000 Data Access */
229 | S_CIP_WriteData = 0x4D, /* Logix5000 Data Access */
230 | S_CM_Unconnected_Send = 0x52,
231 | S_CM_Forward_Open = 0x54,
232 | S_CM_Forward_Close = 0x4E
233 | } CN_Services;
234 |
235 | typedef struct
236 | {
237 | CN_USINT service; /* one of CN_Services */
238 | CN_USINT path_size; /* in number of UINTs ! */
239 | CN_USINT path[1]; /* defined as UINT (padded), but easier to handle as USINT */
240 | /* request data: depends on service */
241 | } MR_Request;
242 |
243 | typedef struct
244 | {
245 | CN_USINT service;
246 | CN_USINT reserved;
247 | CN_USINT general_status;
248 | CN_USINT extended_status_size; /* .. in UINT words ! */
249 | /* maybe CN_UINT extended_status[] */
250 | CN_USINT response[5]; /* depends on service */
251 | } MR_Response;
252 |
253 | /* Dump a raw (net format) MR Response */
254 | const CN_USINT *EIP_dump_raw_MR_Response(const CN_USINT *response,
255 | size_t response_size);
256 |
257 | /* MR_Response has fixed portion followed by (maybe) an extended
258 | * status and then (maybe) data.
259 | * Get pointer to data, fill data_size
260 | */
261 | CN_USINT *EIP_raw_MR_Response_data (const CN_USINT *response,
262 | size_t response_size,
263 | size_t *data_size);
264 |
265 | /********************************************************
266 | * CM, Connection Manager
267 | ********************************************************/
268 |
269 | /* Network Connection Parameters, spec 4 p. 28 */
270 | #define CM_NCP_Type0 0
271 | #define CM_NCP_Multicast (1 << 13)
272 | #define CM_NCP_Point2Point (2 << 13)
273 |
274 | #define CM_NCP_LowPriority 0
275 | #define CM_NCP_HighPriority (1 << 10)
276 | #define CM_NCP_ScheduledPriority (2 << 10)
277 | #define CM_NCP_Urgent (3 << 10)
278 |
279 | #define CM_NCP_Fixed 0
280 | #define CM_NCP_Variable (1 << 9)
281 |
282 | /* Transport and trigger, spec 4 p. 35 and 151 */
283 | #define CM_Trig_Cyclic 0
284 | #define CM_Trig_Change (1 << 4)
285 | #define CM_Trig_App (2 << 4)
286 |
287 | #define CM_Transp_IsServer 0x80
288 |
289 | /* Data portion of CM_Unconnected_Send_Request */
290 | typedef struct
291 | {
292 | CN_USINT priority_and_tick;
293 | CN_USINT connection_timeout_ticks;
294 | CN_UINT message_size; /* in bytes, w/o pad */
295 | MR_Request message_router_PDU; /* padded to 16bit boundary */
296 | /* then the second part follows */
297 | } CM_Unconnected_Send_Request;
298 |
299 | typedef struct
300 | {
301 | CN_USINT path_size; /* in UINT words */
302 | CN_USINT reserved;
303 | CN_USINT path[2];
304 | } CM_Unconnected_Send_Request_2;
305 |
306 | /* Data portion of CM_Forward_Open */
307 | typedef struct
308 | {
309 | CN_USINT priority_and_tick;
310 | CN_USINT connection_timeout_ticks;
311 | CN_UDINT O2T_CID;
312 | CN_UDINT T2O_CID;
313 | CN_UINT connection_serial;
314 | CN_UINT vendor_ID; /* vendor + originator_serial: */
315 | CN_UDINT originator_serial; /* unique, hardcoded */
316 | CN_USINT connection_timeout_multiplier;
317 | CN_USINT reserved[3];
318 | CN_UDINT O2T_RPI; /* requested packet interval, microsecs */
319 | CN_UINT O2T_connection_parameters;
320 | CN_UDINT T2O_RPI;
321 | CN_UINT T2O_connection_parameters;
322 | CN_USINT xport_type_and_trigger;
323 | CN_USINT connection_path_size;
324 | CN_USINT connection_path[1 /* path_size*2 */];
325 | } CM_Forward_Open_Request;
326 |
327 | /* Data portion of reply to CM_Forward_Open */
328 | typedef struct
329 | {
330 | CN_UDINT O2T_CID;
331 | CN_UDINT T2O_CID;
332 | CN_UINT connection_serial;
333 | CN_UINT vendor_ID;
334 | CN_UDINT originator_serial;
335 | CN_UDINT O2T_API; /* actual packet interval, microsecs */
336 | CN_UDINT T2O_API;
337 | CN_USINT application_reply_size;
338 | CN_USINT reserved;
339 | CN_UINT application_reply[1 /* size*2 */];
340 | } CM_Forward_Open_Good_Response;
341 |
342 | /* Data portion of CM_Forward_Close */
343 | typedef struct
344 | {
345 | CN_USINT priority_and_tick;
346 | CN_USINT connection_timeout_ticks;
347 | CN_UINT connection_serial;
348 | CN_UINT vendor_ID;
349 | CN_UDINT originator_serial;
350 | CN_USINT connection_path_size;
351 | CN_USINT reserved;
352 | CN_USINT connection_path[1 /* path_size*2 */];
353 | } CM_Forward_Close_Request;
354 |
355 | /* Data portion of reply to CM_Forward_Close */
356 | typedef struct
357 | {
358 | CN_UINT connection_serial;
359 | CN_UINT vendor_ID;
360 | CN_UDINT originator_serial;
361 | CN_USINT application_reply_size;
362 | CN_USINT reserved;
363 | CN_UINT application_reply[1 /* size*2 */];
364 | } CM_Forward_Close_Good_Response;
365 |
366 | size_t CM_Unconnected_Send_size (size_t message_size);
367 |
368 | /* Fill MR_Request with Unconnected_Send for message of given size,
369 | * path: backplane, given slot.
370 | * Returns pointer to message location in there
371 | * (to be filled, that's a nested, DIFFERENT request!)
372 | * or 0 on error
373 | */
374 | CN_USINT *make_CM_Unconnected_Send(CN_USINT *request, size_t message_size,
375 | int slot);
376 |
377 | /********************************************************
378 | * Logix5000
379 | ********************************************************/
380 |
381 | /* Parses tags of the form
382 | * name.name[element].name[element].name
383 | * and converts them into list of path elements
384 | */
385 | typedef struct __ParsedTag ParsedTag;
386 | struct __ParsedTag
387 | {
388 | enum
389 | {
390 | te_name,
391 | te_element
392 | } type;
393 | union
394 | {
395 | char *name;
396 | size_t element;
397 | } value;
398 | ParsedTag *next;
399 | };
400 |
401 | /* (Abbreviated) type codes for CIP data
402 | * ENET p. 11
403 | */
404 | typedef enum
405 | {
406 | T_CIP_BOOL = 0x00C1,
407 | T_CIP_SINT = 0x00C2,
408 | T_CIP_INT = 0x00C3,
409 | T_CIP_DINT = 0x00C4,
410 | T_CIP_LINT = 0x00C5,
411 | /*T_CIP_USINT = 0x00C6,*/
412 | T_CIP_UINT = 0x00C7,
413 | /*T_CIP_UDINT = 0x00C8,*/
414 | T_CIP_ULINT = 0x00C9,
415 | T_CIP_REAL = 0x00CA,
416 | T_CIP_LREAL = 0x00CB,
417 | T_CIP_STRING = 0x00D0,
418 | T_CIP_BITS = 0x00D3,
419 | T_CIP_STRUCT = 0x02A0
420 | } CIP_Type;
421 |
422 | /* These are experimental:
423 | * The ENEC doc just shows several structures
424 | * for TIMER, COUNTER, CONTROL and indicates that
425 | * the T_CIP_STRUCT = 0x02A0 is followed by
426 | * two more bytes, shown as "?? ??".
427 | * Looks like for strings, those are always 0x0FCE,
428 | * followed by INT length, INT 0, 82 characters and more zeroes
429 | */
430 | typedef enum
431 | {
432 | T_CIP_STRUCT_STRING = 0x0FCE
433 | } CIP_STRUCT_Type;
434 |
435 | /* Size of appreviated type code.
436 | * We only use those with size 2, no structures */
437 | #define CIP_Typecode_size 2
438 |
439 | /* Get typecode from type/data ptr "td".
440 | * (Does not work for structs) */
441 | #define get_CIP_typecode(td) ( (CIP_Type) (((CN_USINT *)td)[0]) )
442 |
443 | /* Determine byte size of CIP_Type */
444 | size_t CIP_Type_size(CIP_Type type);
445 |
446 | /* Turn tag string into ParsedTag,
447 | * convert back into string and free it
448 | */
449 | /*
450 | AB PLC has the max 82 chars for a tag string
451 | */
452 | #define EIP_MAX_TAG_LENGTH 100
453 | ParsedTag *EIP_parse_tag(const char *tag);
454 | void EIP_copy_ParsedTag(char *buffer, const ParsedTag *tag);
455 | void EIP_free_ParsedTag(ParsedTag *tag);
456 |
457 | CN_USINT *make_CIP_ReadData(CN_USINT *request,
458 | const ParsedTag *tag, size_t elements);
459 | const CN_USINT *check_CIP_ReadData_Response(const CN_USINT *response,
460 | size_t response_size,
461 | size_t *data_size);
462 |
463 | /* Fill buffer with CIP WriteData request
464 | * for tag, type of CIP data, given number of elements.
465 | * Also copies data into buffer,
466 | * data has to be in network format already!
467 | */
468 | CN_USINT *make_CIP_WriteData(CN_USINT *buf, size_t buf_size, const ParsedTag *tag,
469 | CIP_Type type, size_t elements,
470 | CN_USINT *raw_data);
471 | void dump_CIP_WriteRequest(const CN_USINT *request);
472 | /* Test CIP_WriteData response: If not OK, report error */
473 | eip_bool check_CIP_WriteData_Response(const CN_USINT *response,
474 | size_t response_size);
475 |
476 | size_t CIP_MultiRequest_size(size_t count, size_t requests_size);
477 | size_t CIP_MultiResponse_size(size_t count, size_t responses_size);
478 | eip_bool prepare_CIP_MultiRequest(CN_USINT *request, size_t count);
479 |
480 | CN_USINT *CIP_MultiRequest_item(CN_USINT *request,
481 | size_t request_no,
482 | size_t single_request_size);
483 |
484 | eip_bool check_CIP_MultiRequest_Response(const CN_USINT *response,
485 | size_t response_size);
486 | void dump_CIP_MultiRequest_Response_Error(const CN_USINT *response,
487 | size_t response_size);
488 | const CN_USINT *get_CIP_MultiRequest_Response(const CN_USINT *response,
489 | size_t response_size,
490 | size_t reply_no,
491 | size_t *reply_size);
492 |
493 | /* dump CIP data, type and data are in raw format */
494 | void dump_raw_CIP_data(const CN_USINT *raw_type_and_data, size_t elements);
495 | eip_bool get_CIP_double(const CN_USINT *raw_type_and_data,
496 | size_t element, double *result);
497 | eip_bool get_CIP_UDINT(const CN_USINT *raw_type_and_data,
498 | size_t element, CN_UDINT *result);
499 | eip_bool get_CIP_DINT(const CN_USINT *raw_type_and_data,
500 | size_t element, CN_DINT *result);
501 | #ifdef SUPPORT_LINT
502 | eip_bool get_CIP_LINT(const CN_USINT *raw_type_and_data,
503 | size_t element, CN_LINT *result);
504 | eip_bool put_CIP_LINT(const CN_USINT *raw_type_and_data,
505 | size_t element, CN_LINT value);
506 | #endif
507 | eip_bool get_CIP_USINT(const CN_USINT *raw_type_and_data,
508 | size_t element, CN_USINT *result);
509 | /* Fill buffer with up to 'size' characters (incl. ending '\0').
510 | * Return true for success */
511 | eip_bool get_CIP_STRING(const CN_USINT *raw_type_and_data,
512 | char *buffer, size_t size);
513 | eip_bool put_CIP_double(const CN_USINT *raw_type_and_data,
514 | size_t element, double value);
515 | eip_bool put_CIP_UDINT(const CN_USINT *raw_type_and_data,
516 | size_t element, CN_UDINT value);
517 | eip_bool put_CIP_DINT(const CN_USINT *raw_type_and_data,
518 | size_t element, CN_DINT value);
519 |
520 | /*
521 | * Fill raw_type_and_data with data and data length. Leave
522 | * the other portion of it unchanged.
523 | */
524 | eip_bool put_CIP_STRING(const CN_USINT *raw_type_and_data,
525 | char *value, size_t size);
526 |
527 | /********************************************************
528 | * Encapsulation
529 | ********************************************************/
530 |
531 | #define TRANS_ID_LEN 8
532 | typedef struct
533 | {
534 | CN_USINT byte[TRANS_ID_LEN];
535 | } TransactionID;
536 |
537 |
538 | typedef struct
539 | {
540 | CN_UINT command; /* Encapsulation_Command */
541 | CN_UINT length; /* # bytes that follow this header */
542 | CN_UDINT session; /* returned by EC_RegisterSession */
543 | CN_UDINT status;
544 | TransactionID trans_id; /* anything I like */
545 | CN_UDINT options;
546 | } EncapsulationHeader;
547 |
548 | #define sizeof_EncapsulationHeader 24
549 |
550 |
551 | /* Spec 4 p. 164 */
552 | typedef enum
553 | {
554 | EC_Nop = 0x0000,
555 | EC_ListInterfaces = 0x0064, /* "Encapsulation Overview" slides */
556 | EC_RegisterSession = 0x0065,
557 | EC_UnRegisterSession = 0x0066,
558 | EC_ListServices = 0x0004,
559 | EC_SendRRData = 0x006F,
560 | EC_SendUnitData = 0x0070,
561 | EC_IndicateStatus = 0x0072 /* "Encapsulation Overview" slides */
562 | } Encapsulation_Command;
563 |
564 | typedef struct
565 | {
566 | EncapsulationHeader header;
567 | /* "Common Packet Format": count + stuff */
568 | CN_UINT count;
569 | struct ServiceInfo
570 | {
571 | CN_UINT type; /* 0x100: "Communications" */
572 | CN_UINT length;
573 | CN_UINT version;
574 | CN_UINT flags;
575 | CN_USINT name[16];
576 | } service; /* 1 or more ... */
577 | } ListServicesReply;
578 |
579 | typedef struct
580 | {
581 | EncapsulationHeader header;
582 | CN_UINT protocol_version;
583 | CN_UINT options;
584 | } RegisterSessionData;
585 |
586 | #define sizeof_RegisterSessionData (sizeof_EncapsulationHeader + 4)
587 |
588 | /* A single PDU encapsulated for SendRRData commands */
589 | typedef struct
590 | {
591 | EncapsulationHeader header;
592 | CN_UDINT interface_handle;
593 | CN_UINT timeout;
594 | /* Common Packet Format: */
595 | CN_UINT count; /* >= 2 */
596 |
597 | /* Item 1 */
598 | CN_UINT address_type;
599 | CN_UINT address_length;
600 | /* could have addr. info in here .. */
601 |
602 | /* Item 2 */
603 | CN_UINT data_type;
604 | CN_UINT data_length;
605 |
606 | /* Following: MR_Request or MR_Response */
607 | } EncapsulationRRData;
608 |
609 | /* EncapsulationRRData up to the MR_Request/Response (exclusive) */
610 | #define sizeof_EncapsulationRRData (sizeof_EncapsulationHeader + 16)
611 |
612 |
613 | /* A single PDU encapsulated for SendUnitData commands */
614 | typedef struct
615 | {
616 | EncapsulationHeader header;
617 | CN_UDINT interface_handle;
618 | CN_UINT timeout;
619 | /* Common Packet Format: */
620 | CN_UINT count; /* >= 2 */
621 |
622 | /* Item 1 */
623 | CN_UINT address_type;
624 | CN_UINT address_length;
625 | CN_UDINT CID;
626 |
627 | /* Item 2 */
628 | CN_UINT data_type;
629 | CN_UINT data_length;
630 | CN_UINT PDU_sequence_number;
631 | union
632 | { /* PDU */
633 | MR_Request request;
634 | MR_Response response;
635 | } rr;
636 | } EncapsulationUnitData;
637 |
638 | /********************************************************
639 | * Utility types for this driver
640 | ********************************************************/
641 |
642 | /* Parameters used to identify a Forward_Open connection */
643 | typedef struct
644 | {
645 | /* Have to be set for make_CM_Forward_Open */
646 | CN_USINT priority_and_tick;
647 | CN_USINT connection_timeout_ticks;
648 | CN_UDINT O2T_CID;
649 | CN_UDINT T2O_CID;
650 | CN_UINT connection_serial;
651 | CN_UINT vendor_ID;
652 | CN_UDINT originator_serial;
653 | } EIPConnectionParameters;
654 |
655 | /* Some values taken from the Itentity object
656 | * of the target
657 | */
658 | typedef struct
659 | {
660 | CN_UINT vendor;
661 | CN_UINT device_type;
662 | CN_UINT revision;
663 | CN_UDINT serial_number;
664 | /* Table 10.3 in spec limits string to 32 chars,
665 | * but CompactLogix seems to return 52 characters.
666 | */
667 | CN_USINT name[100];
668 | } EIPIdentityInfo;
669 |
670 | /* Parameters & buffers for one EtherNet/IP connection.
671 | * sock == 0 is used to detect unused/shutdown connections. */
672 | typedef struct
673 | {
674 | EIP_SOCKET sock; /* silk or nylon */
675 | int slot; /* PLC's slot on backplane */
676 | size_t transfer_buffer_limit; /* PLC limit */
677 | size_t millisec_timeout; /* .. for socket calls */
678 | CN_UDINT session; /* session ID, generated by target */
679 | CN_USINT *buffer; /* buffer for read/write, EIP_BUFFER_SIZE */
680 | EIPIdentityInfo info;
681 | EIPConnectionParameters params;
682 | } EIPConnection;
683 |
684 | #ifdef _WIN32
685 | #pragma pack(pop)
686 | #endif
687 |
688 | void generateTransactionId(TransactionID *pid);
689 | int compareTransactionIds(const TransactionID *p1, const TransactionID *p2);
690 | void transactionIdString(const TransactionID *pId, char *str, int maxChars);
691 | void extractTransactionId(const EncapsulationHeader *pHeader, TransactionID *pId);
692 |
693 | CN_USINT *EIP_make_SendRRData(EIPConnection *c, size_t length, const TransactionID *pId);
694 |
695 | /* Unpack reponse to SendRRData.
696 | * Fills data with details, returns pointer to raw MRResponse
697 | * that's enclosed in the RRData
698 | */
699 | const CN_USINT *EIP_unpack_RRData(const CN_USINT *response,
700 | EncapsulationRRData *data);
701 |
702 | void EIP_dump_connection(const EIPConnection *c);
703 |
704 | /** Allocate EIPConnection */
705 | EIPConnection *EIP_init();
706 |
707 | /** Dispose EIPConnection */
708 | void EIP_dispose(EIPConnection *c);
709 |
710 | /** Connect to PLC */
711 | eip_bool EIP_startup(EIPConnection *c,
712 | const char *ip_addr, unsigned short port,
713 | int slot,
714 | size_t millisec_timeout);
715 |
716 | /** Disconnect from PLC */
717 | void EIP_shutdown(EIPConnection *c);
718 |
719 | /** Send content of buffer.
720 | * Buffer must contain valid EncapsulationHeader
721 | * which describes the size of the message.
722 | * @return true when OK
723 | */
724 | eip_bool EIP_send_connection_buffer(EIPConnection *c);
725 |
726 | /** Read message from PLC into connection's buffer:
727 | * EncapsulationHeader, which describes the length of
728 | * the message, followed by actual message.
729 | * @return true when a full reply was received
730 | */
731 | eip_bool EIP_read_connection_buffer(EIPConnection *c);
732 |
733 | /* VxWorks has no strdup */
734 | char *EIP_strdup(const char *text);
735 |
736 | /* Like EIP_strdup, but only copies the first 'len' chars */
737 | char *EIP_strdup_n(const char *text, size_t len);
738 |
739 | /* Read a single tag in a single CIP_ReadData request,
740 | * report data & data_length
741 | * as well as sizes of CIP_ReadData request/response
742 | */
743 | const CN_USINT *EIP_read_tag(EIPConnection *c,
744 | const ParsedTag *tag, size_t elements,
745 | size_t *data_size,
746 | size_t *request_size, size_t *response_size);
747 |
748 | eip_bool EIP_write_tag(EIPConnection *c, const ParsedTag *tag,
749 | CIP_Type type, size_t elements, CN_USINT *data,
750 | size_t *request_size,
751 | size_t *response_size);
752 |
753 | void *EIP_Get_Attribute_Single(EIPConnection *c,
754 | CN_Classes cls, CN_USINT instance,
755 | CN_USINT attr, size_t *len);
756 |
757 | /* EOF ether_ip.h */
758 |
--------------------------------------------------------------------------------
/ether_ipApp/src/ether_ip.rc:
--------------------------------------------------------------------------------
1 | #include
2 | #include "epicsVersion.h"
3 |
4 | VS_VERSION_INFO VERSIONINFO
5 | FILEVERSION EPICS_VERSION,EPICS_REVISION,EPICS_MODIFICATION,EPICS_UPDATE_LEVEL
6 | PRODUCTVERSION EPICS_VERSION,EPICS_REVISION,EPICS_MODIFICATION,EPICS_UPDATE_LEVEL
7 | FILEFLAGSMASK 0x3fL
8 | #ifdef _DEBUG
9 | FILEFLAGS 0x1L
10 | #else
11 | FILEFLAGS 0x0L
12 | #endif
13 | FILEOS VOS__WINDOWS32
14 | FILETYPE VFT_UNKNOWN
15 | FILESUBTYPE 0x0L
16 | BEGIN
17 | BLOCK "StringFileInfo"
18 | BEGIN
19 | BLOCK "040904b0"
20 | BEGIN
21 | VALUE "Comments","Ether IP Library for EPICS\0"
22 | VALUE "CompanyName", "The EPICS collaboration\0"
23 | VALUE "FileDescription", "Ether IP Library\0"
24 | VALUE "FileVersion", EPICS_VERSION_STRING "\0"
25 | VALUE "InternalName", "ether_ip\0"
26 | VALUE "LegalCopyright", "Copyright (C) Univ. of California, Univ. of Chicago\0"
27 | VALUE "OriginalFilename", "ether_ip.dll\0"
28 | VALUE "ProductName", "Experimental Physics and Industrial Control System (EPICS)\0"
29 | VALUE "ProductVersion", EPICS_VERSION_STRING "\0"
30 | END
31 | END
32 | BLOCK "VarFileInfo"
33 | BEGIN
34 | VALUE "Translation", 0x409, 1200
35 | END
36 | END
37 |
--------------------------------------------------------------------------------
/ether_ipApp/src/ether_ip_test.c:
--------------------------------------------------------------------------------
1 | /* EtherNet/IP: ControlNet over Ethernet
2 | *
3 | * Test program for hosts.
4 | *
5 | * kasemirk@ornl.gov
6 | */
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include"ether_ip.c"
15 |
16 | #ifdef DEFINE_CONNECTED_METHODS
17 |
18 | eip_bool ForwardOpen(EIPConnection *c)
19 | {
20 | size_t request_size = CM_Forward_Open_size ();
21 | MR_Request *request;
22 | EncapsulationRRData *data;
23 | CM_Forward_Open_Good_Response *open_response;
24 |
25 | calc_tick_time (245760,
26 | &c->params.priority_and_tick,
27 | &c->params.connection_timeout_ticks);
28 | c->params.O2T_CID = 0;
29 | c->params.T2O_CID = 2;
30 | c->params.connection_serial = 3;
31 | c->params.vendor_ID = 0xface;
32 | c->params.originator_serial = 0xeffec;
33 |
34 | request = EIP_make_SendRRData (c, request_size);
35 | if (! request)
36 | return false;
37 |
38 | if (! make_CM_Forward_Open (request, &c->params))
39 | return false;
40 | /* dump_CM_Forward_Open (request); */
41 |
42 | if (! EIP_send_connection_buffer (c))
43 | {
44 | printf ("Forward_Open: send failed\n");
45 | return 0;
46 | }
47 |
48 | if (! EIP_read_connection_buffer (c))
49 | {
50 | printf ("Forward_Open: No response\n");
51 | EIP_dump_connection (c);
52 | return 0;
53 | }
54 | data = (EncapsulationRRData *) c->buffer;
55 |
56 | if (data->rr.response.general_status != 0)
57 | {
58 | dump_CM_Forward_Open_Response (&data->rr.response, data->data_length);
59 | return false;
60 | }
61 |
62 | open_response = (CM_Forward_Open_Good_Response *)
63 | EIP_MR_Response_data (&data->rr.response, data->data_length, 0);
64 | c->params.O2T_CID = open_response->O2T_CID;
65 |
66 | #define CHECK(ITEM) \
67 | if (open_response->ITEM != c->params.ITEM) \
68 | { \
69 | printf ("different " # ITEM "\n"); \
70 | return false; \
71 | }
72 | CHECK (T2O_CID)
73 | CHECK (connection_serial)
74 | CHECK (vendor_ID)
75 | CHECK (originator_serial)
76 | #undef CHECK
77 |
78 | return true;
79 | }
80 |
81 | eip_bool ForwardClose(EIPConnection *c)
82 | {
83 | size_t request_size = CM_Forward_Close_size ();
84 | MR_Request *request;
85 | EncapsulationRRData *data;
86 | CM_Forward_Close_Good_Response *close_response;
87 |
88 | request = EIP_make_SendRRData (c, request_size);
89 | if (! request)
90 | return false;
91 |
92 | if (! make_CM_Forward_Close (request, &c->params))
93 | return false;
94 | /* hexdump (request, request_size); */
95 | if (! EIP_send_connection_buffer (c))
96 | {
97 | printf ("Forward_Close: send failed\n");
98 | return 0;
99 | }
100 |
101 | if (! EIP_read_connection_buffer (c))
102 | {
103 | printf ("Forward_Close: No response\n");
104 | EIP_dump_connection (c);
105 | return 0;
106 | }
107 | data = (EncapsulationRRData *) c->buffer;
108 | close_response = (CM_Forward_Close_Good_Response *)
109 | EIP_MR_Response_data (&data->rr.response, data->data_length, 0);
110 | if (data->rr.response.general_status)
111 | {
112 | printf ("Forward_Close Error: ");
113 | if (data->rr.response.general_status == 0x01 &&
114 | data->rr.response.extended_status_size == 1)
115 | {
116 | const CN_UINT *ext = MR_Response_ext_stat (&data->rr.response);
117 | switch (*ext)
118 | {
119 | case 0x0107: printf ("Connection not found\n");
120 | return false;
121 | }
122 | }
123 |
124 | dump_MR_Response (&data->rr.response, data->data_length);
125 | return false;
126 | }
127 |
128 | #define CHECK(ITEM) \
129 | if (close_response->ITEM != c->params.ITEM) \
130 | { \
131 | printf ("different " # ITEM "\n"); \
132 | return false; \
133 | }
134 | CHECK (connection_serial)
135 | CHECK (vendor_ID)
136 | CHECK (originator_serial)
137 | #undef CHECK
138 |
139 | return true;
140 | }
141 |
142 | eip_bool ReadConnected(EIPConnection *c, size_t count, const ParsedTag *tag[])
143 | {
144 | size_t i, msg_size[40], requests_size = 0, multi_size,
145 | single_response_size;
146 | MR_Request *multi_request, *single_request;
147 | const MR_Response *response, *single_response;
148 | EncapsulationUnitData *unit_data;
149 | static CN_USINT sequence = 0;
150 | CN_USINT *data;
151 | size_t data_size;
152 |
153 | /* size indiv. requests, pack into multi request, then Unconn. send */
154 | for (i=0; ibuffer;
186 | response = &unit_data->rr.response;
187 |
188 | if (! check_CIP_MultiRequest_Response (response))
189 | {
190 | EIP_dump_connection (c);
191 | return false;
192 | }
193 |
194 | for (i=0; idata_length,
199 | i,
200 | &single_response_size);
201 | if (! single_response)
202 | return false;
203 |
204 | if (check_CIP_ReadData_Response (single_response, single_response_size))
205 | {
206 | data = EIP_raw_MR_Response_data (single_response, single_response_size,
207 | &data_size);
208 | dump_raw_CIP_data (data, data_size);
209 | }
210 | }
211 |
212 | return true;
213 | }
214 |
215 | void TestConnected(EIPConnection *c, const ParsedTag *tag[])
216 | {
217 | printf ("ForwardOpen:\n");
218 | if (ForwardOpen (c))
219 | printf ("OK.\n");
220 |
221 | ReadConnected (c, 1, tag);
222 |
223 | printf ("ForwardClose:\n");
224 | if (ForwardClose (c))
225 | printf ("OK.\n");
226 | }
227 |
228 | #endif /* DEFINE_CONNECTED_METHODS */
229 |
230 |
231 | #if 0
232 | void stressC(EIPConnection *c, size_t count, const ParsedTag *tag[], size_t runs)
233 | {
234 | TimerValue t;
235 | double secs;
236 | size_t i;
237 |
238 | ForwardOpen (c);
239 | TimerInit (&t);
240 | TimerStart (&t);
241 | for (i=0; i",
251 | runs/secs, secs/runs*1000.0);
252 | printf ("%8.2f values/sec, %6.2f msec/value\n",
253 | runs*count/secs, secs/(runs*count)*1000.0);
254 | }
255 | else
256 | printf ("Try more runs\n");
257 | ForwardClose (c);
258 | }
259 |
260 | void stress(EIPConnection *c, size_t count, const ParsedTag *tags[], size_t runs)
261 | {
262 | TimerValue t;
263 | double secs;
264 | size_t i;
265 |
266 | TimerInit (&t);
267 | TimerStart (&t);
268 | for (i=0; i",
281 | runs/secs, secs/runs*1000.0);
282 | printf ("%8.2f values/sec, %6.2f msec/value\n",
283 | runs*count/secs, secs/(runs*count)*1000.0);
284 | }
285 | else
286 | printf ("Try more runs\n");
287 | }
288 | #endif
289 |
290 | void usage(const char *progname)
291 | {
292 | fprintf(stderr, "Usage: %s [tag]\n", progname);
293 | fprintf(stderr, "Options:\n");
294 | fprintf(stderr, " -v verbosity (Numerical digit)\n");
295 | fprintf(stderr, " -i ip (as 123.456.789.001 or DNS name)\n");
296 | fprintf(stderr, " -p port\n");
297 | fprintf(stderr, " -s PLC slot in ControlLogix crate (default: 0)\n");
298 | fprintf(stderr, " -t timeout (ms)\n");
299 | fprintf(stderr, " -a array size\n");
300 | fprintf(stderr, " -w \n");
301 | #ifdef SUPPORT_LINT
302 | fprintf(stderr, " -W <64 bit value to write>\n");
303 | #endif
304 | fprintf(stderr, " -T times-to-do-all-this (default: 1)\n");
305 | exit(-1);
306 | }
307 |
308 | int main (int argc, const char *argv[])
309 | {
310 | EIPConnection *c = EIP_init();
311 | const char *ip = "172.31.72.94";
312 | unsigned short port = 0xAF12;
313 | int slot = 0;
314 | size_t timeout_ms = 5000;
315 | size_t elements = 1;
316 | ParsedTag *tag = 0;
317 | const char *arg;
318 | size_t i;
319 | CN_REAL writeval = 0.0;
320 | eip_bool write = false;
321 | #ifdef SUPPORT_LINT
322 | CN_LINT Writeval = 0x0000000000000000ll;
323 | eip_bool Write = false;
324 | #endif
325 | size_t test_runs = 1;
326 | #ifndef _WIN32
327 | struct timeval now;
328 | #endif
329 | double start, end, duration;
330 |
331 | #ifdef _WIN32
332 | /* Win32 socket init. */
333 | WORD wVersionRequested;
334 | WSADATA wsaData;
335 | wVersionRequested = MAKEWORD(2, 2);
336 | WSAStartup(wVersionRequested, &wsaData);
337 | #endif
338 |
339 | EIP_verbosity = 5;
340 | if (argc < 2) {
341 | usage (argv[0]);
342 | return 1;
343 | }
344 | /* parse arguments */
345 | for (i=1; i<(size_t)argc; ++i)
346 | {
347 | if (argv[i][0] == '-')
348 | {
349 | #define GETARG \
350 | if (argv[i][2]) { arg = &argv[i ][2]; } \
351 | else { arg = &argv[i+1][0]; ++i; }
352 | switch (argv[i][1])
353 | {
354 | case 'v':
355 | GETARG
356 | if (arg) {
357 | if (isdigit(*arg) == 0) usage(argv[0]);
358 | else EIP_verbosity = atoi(arg);
359 | }
360 | else usage (argv[0]);
361 | break;
362 | case 'i':
363 | GETARG
364 | if (arg) ip = arg;
365 | else usage (argv[0]);
366 |
367 | break;
368 | case 'p':
369 | GETARG
370 | if (arg) port = (unsigned short) strtol(arg, 0, 0);
371 | else usage (argv[0]);
372 | break;
373 | case 's':
374 | GETARG
375 | if (arg) slot = (int) strtol(arg, 0, 0);
376 | else usage (argv[0]);
377 | break;
378 | case 'a':
379 | GETARG
380 | if (arg) elements = atoi(arg);
381 | else usage (argv[0]);
382 | break;
383 | case 't':
384 | GETARG
385 | if (arg) timeout_ms = atol(arg);
386 | else usage (argv[0]);
387 | break;
388 | case 'w':
389 | GETARG
390 | if (arg) {
391 | writeval = strtod(arg, NULL);
392 | write = true;
393 | }
394 | else usage (argv[0]);
395 | break;
396 | #ifdef SUPPORT_LINT
397 | case 'W':
398 | GETARG
399 | if (arg) {
400 | Writeval = strtoull(arg, NULL, 0);
401 | Write = true;
402 | }
403 | else usage (argv[0]);
404 | break;
405 | #endif
406 | case 'T':
407 | GETARG
408 | if (arg) {
409 | test_runs = atol(arg);
410 | if (test_runs <= 0)
411 | test_runs = 1;
412 | }
413 | else usage (argv[0]);
414 | break;
415 | default:
416 | usage (argv[0]);
417 | #undef GETARG
418 | }
419 | }
420 | else
421 | {
422 | tag = EIP_parse_tag(argv[i]);
423 | }
424 | }
425 | if (tag && EIP_verbosity >= 3)
426 | {
427 | char buffer[EIP_MAX_TAG_LENGTH];
428 | EIP_copy_ParsedTag(buffer, tag);
429 | EIP_printf(3, "Tag '%s'\n", buffer);
430 | }
431 | #ifdef _WIN32
432 | start = (double) time(0);
433 | #else
434 | gettimeofday(&now, NULL);
435 | start = now.tv_sec + now.tv_usec/1000000.0;
436 | #endif
437 | for (i=0; i %f ms / tag\n",
474 | (unsigned)test_runs,
475 | duration,
476 | duration / test_runs * 1000.0);
477 |
478 | EIP_dispose(c);
479 |
480 | #ifdef _WIN32
481 | /* Win32 socket shutdown */
482 | WSACleanup( );
483 | #endif
484 |
485 | return 0;
486 | }
487 |
--------------------------------------------------------------------------------
/iocBoot/Makefile:
--------------------------------------------------------------------------------
1 | TOP = ..
2 | include $(TOP)/configure/CONFIG
3 |
4 | DIRS += $(wildcard *ioc*)
5 | DIRS += $(wildcard as*)
6 |
7 | include $(EPICS_BASE)/configure/RULES_DIRS
8 |
--------------------------------------------------------------------------------
/iocBoot/iocether_ip/Makefile:
--------------------------------------------------------------------------------
1 | TOP = ../..
2 |
3 | include $(TOP)/configure/CONFIG
4 | #ARCH = RTEMS-svgm
5 | ARCH = vxWorks-ppc603
6 | TARGETS = cdCommands
7 | include $(TOP)/configure/RULES.ioc
8 |
9 |
--------------------------------------------------------------------------------
/iocBoot/iocether_ip/README:
--------------------------------------------------------------------------------
1 | A bit confusing with all the different versions.
2 |
3 | Linux Host, R3.14.4 base:
4 | ../../bin/linux-x86/example st.cmd.host
5 |
6 | You might need to set this:
7 | export LD_LIBRARY_PATH=../../lib/linux-x86:$LD_LIBRARY_PATH;
8 |
9 | st.cmd.3_14 is meant for a vxWorks IOC under R3.14
10 |
11 | st.cmd is meant for Linux
12 |
13 |
--------------------------------------------------------------------------------
/iocBoot/iocether_ip/run_iocLogServer.sh:
--------------------------------------------------------------------------------
1 | # This is just for getting an ioc log server to run,
2 | # for testing message capture from the driver.
3 | # Read the appdevguide.
4 |
5 | export EPICS_IOC_LOG_FILE_NAME=`pwd`/ioclog.txt
6 | export EPICS_IOC_LOG_PORT=6505
7 | iocLogServer
8 |
--------------------------------------------------------------------------------
/iocBoot/iocether_ip/st.cmd:
--------------------------------------------------------------------------------
1 | #! ../../bin/linux-x86_64/eipIoc
2 | # 3.14 example startup file for a Host -*- shell-script -*-
3 |
4 | # Load dbd, register the drvEtherIP.. commands
5 | dbLoadDatabase("../../dbd/eipIoc.dbd")
6 | eipIoc_registerRecordDeviceDriver(pdbbase)
7 |
8 |
9 | # Initialize EtherIP driver, define PLCs
10 | drvEtherIP_init()
11 |
12 | # EIP_verbosity(10)
13 | # EIP_timeout(5000)
14 |
15 | drvEtherIP_define_PLC("plc1", "160.91.233.45", 0)
16 |
17 | #dbLoadRecords("db/mbbo.db", "PLC=plc1,IOC=test")
18 | #dbLoadRecords("../../db/test.db", "PLC=plc1,IOC=test")
19 | #dbLoadRecords("../../db/mod.db", "PLC=plc1,IOC=test")
20 | dbLoadRecords("string.db", "PLC=plc1,IOC=test")
21 |
22 | iocInit()
23 |
24 |
--------------------------------------------------------------------------------
/iocBoot/iocether_ip/st.cmd.3_14:
--------------------------------------------------------------------------------
1 | # 3.14 ether_ip_test vxWorks startup file
2 |
3 | # Following will be needed for many board support packages
4 | #cd ""
5 |
6 | < cdCommands
7 |
8 | #< ../nfsCommands
9 |
10 | cd topbin
11 | ld < example.munch
12 |
13 | # Initialize EtherIP driver, define PLCs
14 | # -------------------------------------
15 | drvEtherIP_init()
16 |
17 | # Tell vxWorks how to get to "myplc",
18 | # that is the ENET module of a ControlLogix PLC.
19 | # vxWorks doesn't generally use DNS, so if you
20 | # want to use names, you have to define them:
21 | hostAdd("myplc", "192.168.0.50")
22 | # You might need this, too, if the IP is on
23 | # a different subnet: routeAdd ,
24 | # routeAdd("192.168.0.50, "128.165.160.241")
25 | # Test if we can get to the PLC:
26 | ping "myplc", 2
27 |
28 | # drvEtherIP_define_PLC , ,
29 | # The driver/device uses the to indentify the PLC.
30 | #
31 | # can be an IP address in dot-notation
32 | # or a name that the IOC knows about (defined via hostAdd,
33 | # see step 4).
34 | # The IP address gets us to the ENET interface.
35 | # To get to the PLC itself, we need the slot that
36 | # it resides in. The first, left-most slot in the
37 | # ControlLogix crate is slot 0.
38 | drvEtherIP_define_PLC("plc1", "myplc", 0)
39 |
40 | # 10 - Truckload of detailed messages down to the raw send/receive buffers
41 | # 7 - Good value for operation
42 | # 0 - Nothing except very severe problems
43 | EIP_verbosity=7
44 |
45 | cd top
46 | dbLoadDatabase("dbd/example.dbd")
47 | example_registerRecordDeviceDriver(pdbbase)
48 | #dbLoadRecords("db/ramp.db", "IOC=snsioc4")
49 | #dbLoadRecords("db/eip_stat.db","PLC=plc1,IOC=snsioc4,TAG=REAL")
50 | #dbLoadRecords("db/ai.db", "PLC=plc1,IOC=snsioc4")
51 | #dbLoadRecords("db/ana.db", "PLC=plc1,IOC=snsioc4")
52 | #dbLoadRecords("db/bi.db", "PLC=plc1,IOC=snsioc4")
53 | #dbLoadRecords("db/bin.db", "PLC=plc1,IOC=snsioc4")
54 | #dbLoadRecords("db/mbbi.db", "PLC=plc1,IOC=snsioc4")
55 | #dbLoadRecords("db/ao.db", "PLC=plc1,IOC=snsioc4")
56 | #dbLoadRecords("db/bo.db", "PLC=plc1,IOC=snsioc4")
57 | #dbLoadRecords("db/mbbo.db", "PLC=plc1,IOC=snsioc4")
58 | dbLoadRecords("db/test.db", "PLC=plc1,IOC=plc1")
59 |
60 | cd startup
61 | iocInit()
62 |
--------------------------------------------------------------------------------
/iocBoot/iocether_ip/st.cmd.host:
--------------------------------------------------------------------------------
1 | #! ../../bin/linux-x86/eipIoc
2 | # 3.14 example startup file for a Host -*- shell-script -*-
3 |
4 | # Load dbd, register the drvEtherIP.. commands
5 | dbLoadDatabase("../../dbd/eipIoc.dbd")
6 | eipIoc_registerRecordDeviceDriver(pdbbase)
7 |
8 | epicsEnvSet("EPICS_IOC_LOG_INET", "127.0.0.1")
9 | epicsEnvSet("EPICS_IOC_LOG_PORT", "6505")
10 | #iocLogInit
11 |
12 | # Initialize EtherIP driver, define PLCs
13 | EIP_buffer_limit(450)
14 | drvEtherIP_init()
15 |
16 | EIP_verbosity(7)
17 |
18 | # drvEtherIP_define_PLC , ,
19 | # The driver/device uses the to indentify the PLC.
20 | #
21 | # can be an IP address in dot-notation
22 | # or a name about which the IOC knows.
23 | # The IP address gets us to the ENET interface.
24 | # To get to the PLC itself, we need the slot that
25 | # it resides in. The first, left-most slot in the
26 | # ControlLogix crate is slot 0.
27 | #drvEtherIP_define_PLC("plc1", "172.31.72.94", 0)
28 | #drvEtherIP_define_PLC("plc1", "172.31.74.78", 0)
29 | drvEtherIP_define_PLC("plc1", "160.91.233.45", 0)
30 |
31 | #dbLoadRecords("db/ramp.db", "IOC=test")
32 | dbLoadRecords("../../db/eip_stat.db", "PLC=plc1,IOC=test,TAG=DINT")
33 | #dbLoadRecords("db/ai.db", "PLC=plc1,IOC=test")
34 | #dbLoadRecords("db/ana.db", "PLC=plc1,IOC=test")
35 | #dbLoadRecords("db/bi.db", "PLC=plc1,IOC=test")
36 | #dbLoadRecords("db/bin.db", "PLC=plc1,IOC=test")
37 | #dbLoadRecords("db/mbbi.db", "PLC=plc1,IOC=test")
38 | #dbLoadRecords("db/ao.db", "PLC=plc1,IOC=test")
39 | #dbLoadRecords("db/bo.db", "PLC=plc1,IOC=test")
40 | #dbLoadRecords("db/mbbo.db", "PLC=plc1,IOC=test")
41 | #dbLoadRecords("../../db/test.db", "PLC=plc1,IOC=test")
42 | #dbLoadRecords("../../db/mod.db", "PLC=plc1,IOC=test")
43 | dbLoadRecords("../../db/brad.db", "PLC=plc1,IOC=test")
44 |
45 | iocInit()
46 |
47 | epicsThreadSleep 5
48 |
49 | drvEtherIP_report 10
50 |
--------------------------------------------------------------------------------
/iocBoot/iocether_ip/string.db:
--------------------------------------------------------------------------------
1 | # Note that string data type of PLC is longer
2 | # than the string record's value,
3 | # so what you get might be truncated
4 | record(stringin, "string")
5 | {
6 | field(SCAN, "1 second")
7 | field(DTYP, "EtherIP")
8 | field(INP, "@$(PLC) testStr2")
9 | }
10 |
11 | record(stringout, "out")
12 | {
13 | field(DTYP, "EtherIP")
14 | field(OUT, "@$(PLC) testStr2")
15 | }
16 |
17 | record(lsi, "lsi")
18 | {
19 | field(SCAN, "1 second")
20 | field(DTYP, "EtherIP")
21 | field(SIZV, "60")
22 | field(INP, "@$(PLC) testStr3")
23 | }
24 |
25 | record(lso, "lso")
26 | {
27 | field(DTYP, "EtherIP")
28 | field(OUT, "@$(PLC) testStr3")
29 | field(SIZV, "60")
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/iocBoot/nfsCommands:
--------------------------------------------------------------------------------
1 | #Instructions for creating and using a real nfsCommands file
2 | #
3 | # in order to use nfs do the following:
4 | # 1) Create hostAdd and nfsMountAll commands for each nfs server
5 | # 2) In each st.cmd file add the following two commands BEFORE any load commands
6 | # ../nfs.cmd
7 | # cd "
8 | #
9 | # The hostAdd and nfsMountAll commands have the form:
10 | # hostAdd("","xxx.xxx.xxx.xxx")
11 | # nfsMountAll("")
12 | #
13 | # You can also mount subdirectories as follows:
14 | # nfsMount("", "/xxx/xxx/xxx", "/xxx")
15 | #
16 | # For example assume
17 | #
18 | # host is mercury with inet address 155.77.2.56
19 | # You want to mount the directory (which is a file system of mercury)
20 | # /home/mercury5/iocinfo
21 | # as
22 | # /iocinfo
23 | #
24 | # The commands would be
25 | #
26 | # hostAdd("mercury","155.77.2.56")
27 | # nfsMountAll("mercury")
28 | # nfsMount("mercury","/home/mercury5/iocinfo","/iocinfo")
29 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile.Host
2 | TOP = ../..
3 |
4 | include $(TOP)/configure/CONFIG
5 | #----------------------------------------
6 | # ADD MACRO DEFINITIONS AFTER THIS LINE
7 |
8 | #----------------------------------------------------
9 | # Add databases, templates, substitutions like this
10 |
11 | DB += ai.db
12 | DB += ana.db
13 | DB += ao.db
14 | DB += bi.db
15 | DB += bin.db
16 | DB += bo.db
17 | DB += mbbi.db
18 | DB += mbbo.db
19 | DB += ramp.db
20 | DB += eip_stat.db
21 | DB += test.db
22 | DB += mod.db
23 | DB += brad.db
24 | DB += brad2.db
25 |
26 | include $(TOP)/configure/RULES
27 | #----------------------------------------
28 | # ADD RULES AFTER THIS LINE
29 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/ai.db:
--------------------------------------------------------------------------------
1 | record(ai, "$(IOC):ai_REAL")
2 | {
3 | field(SCAN, ".1 second")
4 | field(DTYP, "EtherIP")
5 | field(INP, "@plc1 REAL")
6 | field(EGUF, "10")
7 | field(EGU, "Counts")
8 | field(HOPR, "10")
9 | field(LOPR, "0")
10 | field(HIHI, "8")
11 | field(HIGH, "6")
12 | field(LOW, "4")
13 | field(LOLO, "2")
14 | field(HHSV, "MAJOR")
15 | field(HSV, "MINOR")
16 | field(LSV, "MINOR")
17 | field(LLSV, "MAJOR")
18 | }
19 |
20 | record(ai, "$(IOC):ai_DINT")
21 | {
22 | field(SCAN, "I/O Intr")
23 | field(DTYP, "EtherIP")
24 | field(INP, "@plc1 DINT S .05")
25 | field(EGUF, "10")
26 | field(EGU, "Counts")
27 | field(HOPR, "10")
28 | field(LOPR, "0")
29 | field(HIHI, "8")
30 | field(HIGH, "6")
31 | field(LOW, "4")
32 | field(LOLO, "2")
33 | field(HHSV, "MAJOR")
34 | field(HSV, "MINOR")
35 | field(LSV, "MINOR")
36 | field(LLSV, "MAJOR")
37 | }
38 |
39 | record(ai, "$(IOC):ai_USER")
40 | {
41 | field(SCAN, "1 second")
42 | field(DTYP, "EtherIP")
43 | field(INP, "@plc1 USER.REAL")
44 | field(EGUF, "10")
45 | field(EGU, "Counts")
46 | field(HOPR, "10")
47 | field(LOPR, "0")
48 | field(HIHI, "8")
49 | field(HIGH, "6")
50 | field(LOW, "4")
51 | field(LOLO, "2")
52 | field(HHSV, "MAJOR")
53 | field(HSV, "MINOR")
54 | field(LSV, "MINOR")
55 | field(LLSV, "MAJOR")
56 | }
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/ana.db:
--------------------------------------------------------------------------------
1 | record(ai, "$(IOC):ai_REALs0")
2 | {
3 | field(SCAN, "1 second")
4 | field(DTYP, "EtherIP")
5 | field(INP, "@$(PLC) REALs[0]")
6 | field(EGUF, "10")
7 | field(EGU, "socks")
8 | field(HOPR, "10")
9 | field(LOPR, "0")
10 | }
11 |
12 | record(ai, "$(IOC):ai_REALs2_0")
13 | {
14 | field(SCAN, "1 second")
15 | field(DTYP, "EtherIP")
16 | field(INP, "@$(PLC) REALs2[0]")
17 | field(EGUF, "10")
18 | field(EGU, "socks")
19 | field(HOPR, "10")
20 | field(LOPR, "0")
21 | }
22 |
23 | record(ai, "$(IOC):ai_REALs3_0")
24 | {
25 | field(SCAN, "1 second")
26 | field(DTYP, "EtherIP")
27 | field(INP, "@$(PLC) REALs3[0]")
28 | field(EGUF, "10")
29 | field(EGU, "socks")
30 | field(HOPR, "10")
31 | field(LOPR, "0")
32 | }
33 |
34 | record(ai, "$(IOC):ai_REALs1")
35 | {
36 | field(SCAN, "1 second")
37 | field(DTYP, "EtherIP")
38 | field(INP, "@$(PLC) REALs[1]")
39 | field(EGUF, "10")
40 | field(EGU, "socks")
41 | field(HOPR, "10")
42 | field(LOPR, "0")
43 | }
44 |
45 | record(ai, "$(IOC):ai_REALs2_1")
46 | {
47 | field(SCAN, "1 second")
48 | field(DTYP, "EtherIP")
49 | field(INP, "@$(PLC) REALs2[1]")
50 | field(EGUF, "10")
51 | field(EGU, "socks")
52 | field(HOPR, "10")
53 | field(LOPR, "0")
54 | }
55 |
56 | record(ai, "$(IOC):ai_REALs3_1")
57 | {
58 | field(SCAN, "1 second")
59 | field(DTYP, "EtherIP")
60 | field(INP, "@$(PLC) REALs3[1]")
61 | field(EGUF, "10")
62 | field(EGU, "socks")
63 | field(HOPR, "10")
64 | field(LOPR, "0")
65 | }
66 |
67 | record(ai, "$(IOC):ai_REALs2")
68 | {
69 | field(SCAN, "1 second")
70 | field(DTYP, "EtherIP")
71 | field(INP, "@$(PLC) REALs[2]")
72 | field(EGUF, "10")
73 | field(EGU, "socks")
74 | field(HOPR, "10")
75 | field(LOPR, "0")
76 | }
77 |
78 | record(ai, "$(IOC):ai_REALs2_2")
79 | {
80 | field(SCAN, "1 second")
81 | field(DTYP, "EtherIP")
82 | field(INP, "@$(PLC) REALs2[2]")
83 | field(EGUF, "10")
84 | field(EGU, "socks")
85 | field(HOPR, "10")
86 | field(LOPR, "0")
87 | }
88 |
89 | record(ai, "$(IOC):ai_REALs3_2")
90 | {
91 | field(SCAN, "1 second")
92 | field(DTYP, "EtherIP")
93 | field(INP, "@$(PLC) REALs3[2]")
94 | field(EGUF, "10")
95 | field(EGU, "socks")
96 | field(HOPR, "10")
97 | field(LOPR, "0")
98 | }
99 |
100 | record(ai, "$(IOC):ai_REALs3")
101 | {
102 | field(SCAN, "1 second")
103 | field(DTYP, "EtherIP")
104 | field(INP, "@$(PLC) REALs[3]")
105 | field(EGUF, "10")
106 | field(EGU, "socks")
107 | field(HOPR, "10")
108 | field(LOPR, "0")
109 | }
110 |
111 | record(ai, "$(IOC):ai_REALs2_3")
112 | {
113 | field(SCAN, "1 second")
114 | field(DTYP, "EtherIP")
115 | field(INP, "@$(PLC) REALs2[3]")
116 | field(EGUF, "10")
117 | field(EGU, "socks")
118 | field(HOPR, "10")
119 | field(LOPR, "0")
120 | }
121 |
122 | record(ai, "$(IOC):ai_REALs3_3")
123 | {
124 | field(SCAN, "1 second")
125 | field(DTYP, "EtherIP")
126 | field(INP, "@$(PLC) REALs3[3]")
127 | field(EGUF, "10")
128 | field(EGU, "socks")
129 | field(HOPR, "10")
130 | field(LOPR, "0")
131 | }
132 |
133 | record(ai, "$(IOC):ai_REALs4")
134 | {
135 | field(SCAN, "1 second")
136 | field(DTYP, "EtherIP")
137 | field(INP, "@$(PLC) REALs[4]")
138 | field(EGUF, "10")
139 | field(EGU, "socks")
140 | field(HOPR, "10")
141 | field(LOPR, "0")
142 | }
143 |
144 | record(ai, "$(IOC):ai_REALs2_4")
145 | {
146 | field(SCAN, "1 second")
147 | field(DTYP, "EtherIP")
148 | field(INP, "@$(PLC) REALs2[4]")
149 | field(EGUF, "10")
150 | field(EGU, "socks")
151 | field(HOPR, "10")
152 | field(LOPR, "0")
153 | }
154 |
155 | record(ai, "$(IOC):ai_REALs3_4")
156 | {
157 | field(SCAN, "1 second")
158 | field(DTYP, "EtherIP")
159 | field(INP, "@$(PLC) REALs3[4]")
160 | field(EGUF, "10")
161 | field(EGU, "socks")
162 | field(HOPR, "10")
163 | field(LOPR, "0")
164 | }
165 |
166 | record(ai, "$(IOC):ai_REALs5")
167 | {
168 | field(SCAN, "1 second")
169 | field(DTYP, "EtherIP")
170 | field(INP, "@$(PLC) REALs[5]")
171 | field(EGUF, "10")
172 | field(EGU, "socks")
173 | field(HOPR, "10")
174 | field(LOPR, "0")
175 | }
176 |
177 | record(ai, "$(IOC):ai_REALs2_5")
178 | {
179 | field(SCAN, "1 second")
180 | field(DTYP, "EtherIP")
181 | field(INP, "@$(PLC) REALs2[5]")
182 | field(EGUF, "10")
183 | field(EGU, "socks")
184 | field(HOPR, "10")
185 | field(LOPR, "0")
186 | }
187 |
188 | record(ai, "$(IOC):ai_REALs3_5")
189 | {
190 | field(SCAN, "1 second")
191 | field(DTYP, "EtherIP")
192 | field(INP, "@$(PLC) REALs3[5]")
193 | field(EGUF, "10")
194 | field(EGU, "socks")
195 | field(HOPR, "10")
196 | field(LOPR, "0")
197 | }
198 |
199 | record(ai, "$(IOC):ai_REALs6")
200 | {
201 | field(SCAN, "1 second")
202 | field(DTYP, "EtherIP")
203 | field(INP, "@$(PLC) REALs[6]")
204 | field(EGUF, "10")
205 | field(EGU, "socks")
206 | field(HOPR, "10")
207 | field(LOPR, "0")
208 | }
209 |
210 | record(ai, "$(IOC):ai_REALs2_6")
211 | {
212 | field(SCAN, "1 second")
213 | field(DTYP, "EtherIP")
214 | field(INP, "@$(PLC) REALs2[6]")
215 | field(EGUF, "10")
216 | field(EGU, "socks")
217 | field(HOPR, "10")
218 | field(LOPR, "0")
219 | }
220 |
221 | record(ai, "$(IOC):ai_REALs3_6")
222 | {
223 | field(SCAN, "1 second")
224 | field(DTYP, "EtherIP")
225 | field(INP, "@$(PLC) REALs3[6]")
226 | field(EGUF, "10")
227 | field(EGU, "socks")
228 | field(HOPR, "10")
229 | field(LOPR, "0")
230 | }
231 |
232 | record(ai, "$(IOC):ai_REALs7")
233 | {
234 | field(SCAN, "1 second")
235 | field(DTYP, "EtherIP")
236 | field(INP, "@$(PLC) REALs[7]")
237 | field(EGUF, "10")
238 | field(EGU, "socks")
239 | field(HOPR, "10")
240 | field(LOPR, "0")
241 | }
242 |
243 | record(ai, "$(IOC):ai_REALs2_7")
244 | {
245 | field(SCAN, "1 second")
246 | field(DTYP, "EtherIP")
247 | field(INP, "@$(PLC) REALs2[7]")
248 | field(EGUF, "10")
249 | field(EGU, "socks")
250 | field(HOPR, "10")
251 | field(LOPR, "0")
252 | }
253 |
254 | record(ai, "$(IOC):ai_REALs3_7")
255 | {
256 | field(SCAN, "1 second")
257 | field(DTYP, "EtherIP")
258 | field(INP, "@$(PLC) REALs3[7]")
259 | field(EGUF, "10")
260 | field(EGU, "socks")
261 | field(HOPR, "10")
262 | field(LOPR, "0")
263 | }
264 |
265 | record(ai, "$(IOC):ai_REALs8")
266 | {
267 | field(SCAN, "1 second")
268 | field(DTYP, "EtherIP")
269 | field(INP, "@$(PLC) REALs[8]")
270 | field(EGUF, "10")
271 | field(EGU, "socks")
272 | field(HOPR, "10")
273 | field(LOPR, "0")
274 | }
275 |
276 | record(ai, "$(IOC):ai_REALs2_8")
277 | {
278 | field(SCAN, "1 second")
279 | field(DTYP, "EtherIP")
280 | field(INP, "@$(PLC) REALs2[8]")
281 | field(EGUF, "10")
282 | field(EGU, "socks")
283 | field(HOPR, "10")
284 | field(LOPR, "0")
285 | }
286 |
287 | record(ai, "$(IOC):ai_REALs3_8")
288 | {
289 | field(SCAN, "1 second")
290 | field(DTYP, "EtherIP")
291 | field(INP, "@$(PLC) REALs3[8]")
292 | field(EGUF, "10")
293 | field(EGU, "socks")
294 | field(HOPR, "10")
295 | field(LOPR, "0")
296 | }
297 |
298 | record(ai, "$(IOC):ai_REALs9")
299 | {
300 | field(SCAN, "1 second")
301 | field(DTYP, "EtherIP")
302 | field(INP, "@$(PLC) REALs[9]")
303 | field(EGUF, "10")
304 | field(EGU, "socks")
305 | field(HOPR, "10")
306 | field(LOPR, "0")
307 | }
308 |
309 | record(ai, "$(IOC):ai_REALs2_9")
310 | {
311 | field(SCAN, "1 second")
312 | field(DTYP, "EtherIP")
313 | field(INP, "@$(PLC) REALs2[9]")
314 | field(EGUF, "10")
315 | field(EGU, "socks")
316 | field(HOPR, "10")
317 | field(LOPR, "0")
318 | }
319 |
320 | record(ai, "$(IOC):ai_REALs3_9")
321 | {
322 | field(SCAN, "1 second")
323 | field(DTYP, "EtherIP")
324 | field(INP, "@$(PLC) REALs3[9]")
325 | field(EGUF, "10")
326 | field(EGU, "socks")
327 | field(HOPR, "10")
328 | field(LOPR, "0")
329 | }
330 |
331 | record(ai, "$(IOC):ai_REALs10")
332 | {
333 | field(SCAN, "1 second")
334 | field(DTYP, "EtherIP")
335 | field(INP, "@$(PLC) REALs[10]")
336 | field(EGUF, "10")
337 | field(EGU, "socks")
338 | field(HOPR, "10")
339 | field(LOPR, "0")
340 | }
341 |
342 | record(ai, "$(IOC):ai_REALs2_10")
343 | {
344 | field(SCAN, "1 second")
345 | field(DTYP, "EtherIP")
346 | field(INP, "@$(PLC) REALs2[10]")
347 | field(EGUF, "10")
348 | field(EGU, "socks")
349 | field(HOPR, "10")
350 | field(LOPR, "0")
351 | }
352 |
353 | record(ai, "$(IOC):ai_REALs3_10")
354 | {
355 | field(SCAN, "1 second")
356 | field(DTYP, "EtherIP")
357 | field(INP, "@$(PLC) REALs3[10]")
358 | field(EGUF, "10")
359 | field(EGU, "socks")
360 | field(HOPR, "10")
361 | field(LOPR, "0")
362 | }
363 |
364 | record(ai, "$(IOC):ai_REALs11")
365 | {
366 | field(SCAN, "1 second")
367 | field(DTYP, "EtherIP")
368 | field(INP, "@$(PLC) REALs[11]")
369 | field(EGUF, "10")
370 | field(EGU, "socks")
371 | field(HOPR, "10")
372 | field(LOPR, "0")
373 | }
374 |
375 | record(ai, "$(IOC):ai_REALs2_11")
376 | {
377 | field(SCAN, "1 second")
378 | field(DTYP, "EtherIP")
379 | field(INP, "@$(PLC) REALs2[11]")
380 | field(EGUF, "10")
381 | field(EGU, "socks")
382 | field(HOPR, "10")
383 | field(LOPR, "0")
384 | }
385 |
386 | record(ai, "$(IOC):ai_REALs3_11")
387 | {
388 | field(SCAN, "1 second")
389 | field(DTYP, "EtherIP")
390 | field(INP, "@$(PLC) REALs3[11]")
391 | field(EGUF, "10")
392 | field(EGU, "socks")
393 | field(HOPR, "10")
394 | field(LOPR, "0")
395 | }
396 |
397 | record(ai, "$(IOC):ai_REALs12")
398 | {
399 | field(SCAN, "1 second")
400 | field(DTYP, "EtherIP")
401 | field(INP, "@$(PLC) REALs[12]")
402 | field(EGUF, "10")
403 | field(EGU, "socks")
404 | field(HOPR, "10")
405 | field(LOPR, "0")
406 | }
407 |
408 | record(ai, "$(IOC):ai_REALs2_12")
409 | {
410 | field(SCAN, "1 second")
411 | field(DTYP, "EtherIP")
412 | field(INP, "@$(PLC) REALs2[12]")
413 | field(EGUF, "10")
414 | field(EGU, "socks")
415 | field(HOPR, "10")
416 | field(LOPR, "0")
417 | }
418 |
419 | record(ai, "$(IOC):ai_REALs3_12")
420 | {
421 | field(SCAN, "1 second")
422 | field(DTYP, "EtherIP")
423 | field(INP, "@$(PLC) REALs3[12]")
424 | field(EGUF, "10")
425 | field(EGU, "socks")
426 | field(HOPR, "10")
427 | field(LOPR, "0")
428 | }
429 |
430 | record(ai, "$(IOC):ai_REALs13")
431 | {
432 | field(SCAN, "1 second")
433 | field(DTYP, "EtherIP")
434 | field(INP, "@$(PLC) REALs[13]")
435 | field(EGUF, "10")
436 | field(EGU, "socks")
437 | field(HOPR, "10")
438 | field(LOPR, "0")
439 | }
440 |
441 | record(ai, "$(IOC):ai_REALs2_13")
442 | {
443 | field(SCAN, "1 second")
444 | field(DTYP, "EtherIP")
445 | field(INP, "@$(PLC) REALs2[13]")
446 | field(EGUF, "10")
447 | field(EGU, "socks")
448 | field(HOPR, "10")
449 | field(LOPR, "0")
450 | }
451 |
452 | record(ai, "$(IOC):ai_REALs3_13")
453 | {
454 | field(SCAN, "1 second")
455 | field(DTYP, "EtherIP")
456 | field(INP, "@$(PLC) REALs3[13]")
457 | field(EGUF, "10")
458 | field(EGU, "socks")
459 | field(HOPR, "10")
460 | field(LOPR, "0")
461 | }
462 |
463 | record(ai, "$(IOC):ai_REALs14")
464 | {
465 | field(SCAN, "1 second")
466 | field(DTYP, "EtherIP")
467 | field(INP, "@$(PLC) REALs[14]")
468 | field(EGUF, "10")
469 | field(EGU, "socks")
470 | field(HOPR, "10")
471 | field(LOPR, "0")
472 | }
473 |
474 | record(ai, "$(IOC):ai_REALs2_14")
475 | {
476 | field(SCAN, "1 second")
477 | field(DTYP, "EtherIP")
478 | field(INP, "@$(PLC) REALs2[14]")
479 | field(EGUF, "10")
480 | field(EGU, "socks")
481 | field(HOPR, "10")
482 | field(LOPR, "0")
483 | }
484 |
485 | record(ai, "$(IOC):ai_REALs3_14")
486 | {
487 | field(SCAN, "1 second")
488 | field(DTYP, "EtherIP")
489 | field(INP, "@$(PLC) REALs3[14]")
490 | field(EGUF, "10")
491 | field(EGU, "socks")
492 | field(HOPR, "10")
493 | field(LOPR, "0")
494 | }
495 |
496 | record(ai, "$(IOC):ai_REALs15")
497 | {
498 | field(SCAN, "1 second")
499 | field(DTYP, "EtherIP")
500 | field(INP, "@$(PLC) REALs[15]")
501 | field(EGUF, "10")
502 | field(EGU, "socks")
503 | field(HOPR, "10")
504 | field(LOPR, "0")
505 | }
506 |
507 | record(ai, "$(IOC):ai_REALs2_15")
508 | {
509 | field(SCAN, "1 second")
510 | field(DTYP, "EtherIP")
511 | field(INP, "@$(PLC) REALs2[15]")
512 | field(EGUF, "10")
513 | field(EGU, "socks")
514 | field(HOPR, "10")
515 | field(LOPR, "0")
516 | }
517 |
518 | record(ai, "$(IOC):ai_REALs3_15")
519 | {
520 | field(SCAN, "1 second")
521 | field(DTYP, "EtherIP")
522 | field(INP, "@$(PLC) REALs3[15]")
523 | field(EGUF, "10")
524 | field(EGU, "socks")
525 | field(HOPR, "10")
526 | field(LOPR, "0")
527 | }
528 |
529 | record(ai, "$(IOC):ai_REALs16")
530 | {
531 | field(SCAN, "1 second")
532 | field(DTYP, "EtherIP")
533 | field(INP, "@$(PLC) REALs[16]")
534 | field(EGUF, "10")
535 | field(EGU, "socks")
536 | field(HOPR, "10")
537 | field(LOPR, "0")
538 | }
539 |
540 | record(ai, "$(IOC):ai_REALs2_16")
541 | {
542 | field(SCAN, "1 second")
543 | field(DTYP, "EtherIP")
544 | field(INP, "@$(PLC) REALs2[16]")
545 | field(EGUF, "10")
546 | field(EGU, "socks")
547 | field(HOPR, "10")
548 | field(LOPR, "0")
549 | }
550 |
551 | record(ai, "$(IOC):ai_REALs3_16")
552 | {
553 | field(SCAN, "1 second")
554 | field(DTYP, "EtherIP")
555 | field(INP, "@$(PLC) REALs3[16]")
556 | field(EGUF, "10")
557 | field(EGU, "socks")
558 | field(HOPR, "10")
559 | field(LOPR, "0")
560 | }
561 |
562 | record(ai, "$(IOC):ai_REALs17")
563 | {
564 | field(SCAN, "1 second")
565 | field(DTYP, "EtherIP")
566 | field(INP, "@$(PLC) REALs[17]")
567 | field(EGUF, "10")
568 | field(EGU, "socks")
569 | field(HOPR, "10")
570 | field(LOPR, "0")
571 | }
572 |
573 | record(ai, "$(IOC):ai_REALs2_17")
574 | {
575 | field(SCAN, "1 second")
576 | field(DTYP, "EtherIP")
577 | field(INP, "@$(PLC) REALs2[17]")
578 | field(EGUF, "10")
579 | field(EGU, "socks")
580 | field(HOPR, "10")
581 | field(LOPR, "0")
582 | }
583 |
584 | record(ai, "$(IOC):ai_REALs3_17")
585 | {
586 | field(SCAN, "1 second")
587 | field(DTYP, "EtherIP")
588 | field(INP, "@$(PLC) REALs3[17]")
589 | field(EGUF, "10")
590 | field(EGU, "socks")
591 | field(HOPR, "10")
592 | field(LOPR, "0")
593 | }
594 |
595 | record(ai, "$(IOC):ai_REALs18")
596 | {
597 | field(SCAN, "1 second")
598 | field(DTYP, "EtherIP")
599 | field(INP, "@$(PLC) REALs[18]")
600 | field(EGUF, "10")
601 | field(EGU, "socks")
602 | field(HOPR, "10")
603 | field(LOPR, "0")
604 | }
605 |
606 | record(ai, "$(IOC):ai_REALs2_18")
607 | {
608 | field(SCAN, "1 second")
609 | field(DTYP, "EtherIP")
610 | field(INP, "@$(PLC) REALs2[18]")
611 | field(EGUF, "10")
612 | field(EGU, "socks")
613 | field(HOPR, "10")
614 | field(LOPR, "0")
615 | }
616 |
617 | record(ai, "$(IOC):ai_REALs3_18")
618 | {
619 | field(SCAN, "1 second")
620 | field(DTYP, "EtherIP")
621 | field(INP, "@$(PLC) REALs3[18]")
622 | field(EGUF, "10")
623 | field(EGU, "socks")
624 | field(HOPR, "10")
625 | field(LOPR, "0")
626 | }
627 |
628 | record(ai, "$(IOC):ai_REALs19")
629 | {
630 | field(SCAN, "1 second")
631 | field(DTYP, "EtherIP")
632 | field(INP, "@$(PLC) REALs[19]")
633 | field(EGUF, "10")
634 | field(EGU, "socks")
635 | field(HOPR, "10")
636 | field(LOPR, "0")
637 | }
638 |
639 | record(ai, "$(IOC):ai_REALs2_19")
640 | {
641 | field(SCAN, "1 second")
642 | field(DTYP, "EtherIP")
643 | field(INP, "@$(PLC) REALs2[19]")
644 | field(EGUF, "10")
645 | field(EGU, "socks")
646 | field(HOPR, "10")
647 | field(LOPR, "0")
648 | }
649 |
650 | record(ai, "$(IOC):ai_REALs3_19")
651 | {
652 | field(SCAN, "1 second")
653 | field(DTYP, "EtherIP")
654 | field(INP, "@$(PLC) REALs3[19]")
655 | field(EGUF, "10")
656 | field(EGU, "socks")
657 | field(HOPR, "10")
658 | field(LOPR, "0")
659 | }
660 |
661 | record(ai, "$(IOC):ai_REALs20")
662 | {
663 | field(SCAN, "1 second")
664 | field(DTYP, "EtherIP")
665 | field(INP, "@$(PLC) REALs[20]")
666 | field(EGUF, "10")
667 | field(EGU, "socks")
668 | field(HOPR, "10")
669 | field(LOPR, "0")
670 | }
671 |
672 | record(ai, "$(IOC):ai_REALs2_20")
673 | {
674 | field(SCAN, "1 second")
675 | field(DTYP, "EtherIP")
676 | field(INP, "@$(PLC) REALs2[20]")
677 | field(EGUF, "10")
678 | field(EGU, "socks")
679 | field(HOPR, "10")
680 | field(LOPR, "0")
681 | }
682 |
683 | record(ai, "$(IOC):ai_REALs3_20")
684 | {
685 | field(SCAN, "1 second")
686 | field(DTYP, "EtherIP")
687 | field(INP, "@$(PLC) REALs3[20]")
688 | field(EGUF, "10")
689 | field(EGU, "socks")
690 | field(HOPR, "10")
691 | field(LOPR, "0")
692 | }
693 |
694 | record(ai, "$(IOC):ai_REALs21")
695 | {
696 | field(SCAN, "1 second")
697 | field(DTYP, "EtherIP")
698 | field(INP, "@$(PLC) REALs[21]")
699 | field(EGUF, "10")
700 | field(EGU, "socks")
701 | field(HOPR, "10")
702 | field(LOPR, "0")
703 | }
704 |
705 | record(ai, "$(IOC):ai_REALs2_21")
706 | {
707 | field(SCAN, "1 second")
708 | field(DTYP, "EtherIP")
709 | field(INP, "@$(PLC) REALs2[21]")
710 | field(EGUF, "10")
711 | field(EGU, "socks")
712 | field(HOPR, "10")
713 | field(LOPR, "0")
714 | }
715 |
716 | record(ai, "$(IOC):ai_REALs3_21")
717 | {
718 | field(SCAN, "1 second")
719 | field(DTYP, "EtherIP")
720 | field(INP, "@$(PLC) REALs3[21]")
721 | field(EGUF, "10")
722 | field(EGU, "socks")
723 | field(HOPR, "10")
724 | field(LOPR, "0")
725 | }
726 |
727 | record(ai, "$(IOC):ai_REALs22")
728 | {
729 | field(SCAN, "1 second")
730 | field(DTYP, "EtherIP")
731 | field(INP, "@$(PLC) REALs[22]")
732 | field(EGUF, "10")
733 | field(EGU, "socks")
734 | field(HOPR, "10")
735 | field(LOPR, "0")
736 | }
737 |
738 | record(ai, "$(IOC):ai_REALs2_22")
739 | {
740 | field(SCAN, "1 second")
741 | field(DTYP, "EtherIP")
742 | field(INP, "@$(PLC) REALs2[22]")
743 | field(EGUF, "10")
744 | field(EGU, "socks")
745 | field(HOPR, "10")
746 | field(LOPR, "0")
747 | }
748 |
749 | record(ai, "$(IOC):ai_REALs3_22")
750 | {
751 | field(SCAN, "1 second")
752 | field(DTYP, "EtherIP")
753 | field(INP, "@$(PLC) REALs3[22]")
754 | field(EGUF, "10")
755 | field(EGU, "socks")
756 | field(HOPR, "10")
757 | field(LOPR, "0")
758 | }
759 |
760 | record(ai, "$(IOC):ai_REALs23")
761 | {
762 | field(SCAN, "1 second")
763 | field(DTYP, "EtherIP")
764 | field(INP, "@$(PLC) REALs[23]")
765 | field(EGUF, "10")
766 | field(EGU, "socks")
767 | field(HOPR, "10")
768 | field(LOPR, "0")
769 | }
770 |
771 | record(ai, "$(IOC):ai_REALs2_23")
772 | {
773 | field(SCAN, "1 second")
774 | field(DTYP, "EtherIP")
775 | field(INP, "@$(PLC) REALs2[23]")
776 | field(EGUF, "10")
777 | field(EGU, "socks")
778 | field(HOPR, "10")
779 | field(LOPR, "0")
780 | }
781 |
782 | record(ai, "$(IOC):ai_REALs3_23")
783 | {
784 | field(SCAN, "1 second")
785 | field(DTYP, "EtherIP")
786 | field(INP, "@$(PLC) REALs3[23]")
787 | field(EGUF, "10")
788 | field(EGU, "socks")
789 | field(HOPR, "10")
790 | field(LOPR, "0")
791 | }
792 |
793 | record(ai, "$(IOC):ai_REALs24")
794 | {
795 | field(SCAN, "1 second")
796 | field(DTYP, "EtherIP")
797 | field(INP, "@$(PLC) REALs[24]")
798 | field(EGUF, "10")
799 | field(EGU, "socks")
800 | field(HOPR, "10")
801 | field(LOPR, "0")
802 | }
803 |
804 | record(ai, "$(IOC):ai_REALs2_24")
805 | {
806 | field(SCAN, "1 second")
807 | field(DTYP, "EtherIP")
808 | field(INP, "@$(PLC) REALs2[24]")
809 | field(EGUF, "10")
810 | field(EGU, "socks")
811 | field(HOPR, "10")
812 | field(LOPR, "0")
813 | }
814 |
815 | record(ai, "$(IOC):ai_REALs3_24")
816 | {
817 | field(SCAN, "1 second")
818 | field(DTYP, "EtherIP")
819 | field(INP, "@$(PLC) REALs3[24]")
820 | field(EGUF, "10")
821 | field(EGU, "socks")
822 | field(HOPR, "10")
823 | field(LOPR, "0")
824 | }
825 |
826 | record(ai, "$(IOC):ai_REALs25")
827 | {
828 | field(SCAN, "1 second")
829 | field(DTYP, "EtherIP")
830 | field(INP, "@$(PLC) REALs[25]")
831 | field(EGUF, "10")
832 | field(EGU, "socks")
833 | field(HOPR, "10")
834 | field(LOPR, "0")
835 | }
836 |
837 | record(ai, "$(IOC):ai_REALs2_25")
838 | {
839 | field(SCAN, "1 second")
840 | field(DTYP, "EtherIP")
841 | field(INP, "@$(PLC) REALs2[25]")
842 | field(EGUF, "10")
843 | field(EGU, "socks")
844 | field(HOPR, "10")
845 | field(LOPR, "0")
846 | }
847 |
848 | record(ai, "$(IOC):ai_REALs3_25")
849 | {
850 | field(SCAN, "1 second")
851 | field(DTYP, "EtherIP")
852 | field(INP, "@$(PLC) REALs3[25]")
853 | field(EGUF, "10")
854 | field(EGU, "socks")
855 | field(HOPR, "10")
856 | field(LOPR, "0")
857 | }
858 |
859 | record(ai, "$(IOC):ai_REALs26")
860 | {
861 | field(SCAN, "1 second")
862 | field(DTYP, "EtherIP")
863 | field(INP, "@$(PLC) REALs[26]")
864 | field(EGUF, "10")
865 | field(EGU, "socks")
866 | field(HOPR, "10")
867 | field(LOPR, "0")
868 | }
869 |
870 | record(ai, "$(IOC):ai_REALs2_26")
871 | {
872 | field(SCAN, "1 second")
873 | field(DTYP, "EtherIP")
874 | field(INP, "@$(PLC) REALs2[26]")
875 | field(EGUF, "10")
876 | field(EGU, "socks")
877 | field(HOPR, "10")
878 | field(LOPR, "0")
879 | }
880 |
881 | record(ai, "$(IOC):ai_REALs3_26")
882 | {
883 | field(SCAN, "1 second")
884 | field(DTYP, "EtherIP")
885 | field(INP, "@$(PLC) REALs3[26]")
886 | field(EGUF, "10")
887 | field(EGU, "socks")
888 | field(HOPR, "10")
889 | field(LOPR, "0")
890 | }
891 |
892 | record(ai, "$(IOC):ai_REALs27")
893 | {
894 | field(SCAN, "1 second")
895 | field(DTYP, "EtherIP")
896 | field(INP, "@$(PLC) REALs[27]")
897 | field(EGUF, "10")
898 | field(EGU, "socks")
899 | field(HOPR, "10")
900 | field(LOPR, "0")
901 | }
902 |
903 | record(ai, "$(IOC):ai_REALs2_27")
904 | {
905 | field(SCAN, "1 second")
906 | field(DTYP, "EtherIP")
907 | field(INP, "@$(PLC) REALs2[27]")
908 | field(EGUF, "10")
909 | field(EGU, "socks")
910 | field(HOPR, "10")
911 | field(LOPR, "0")
912 | }
913 |
914 | record(ai, "$(IOC):ai_REALs3_27")
915 | {
916 | field(SCAN, "1 second")
917 | field(DTYP, "EtherIP")
918 | field(INP, "@$(PLC) REALs3[27]")
919 | field(EGUF, "10")
920 | field(EGU, "socks")
921 | field(HOPR, "10")
922 | field(LOPR, "0")
923 | }
924 |
925 | record(ai, "$(IOC):ai_REALs28")
926 | {
927 | field(SCAN, "1 second")
928 | field(DTYP, "EtherIP")
929 | field(INP, "@$(PLC) REALs[28]")
930 | field(EGUF, "10")
931 | field(EGU, "socks")
932 | field(HOPR, "10")
933 | field(LOPR, "0")
934 | }
935 |
936 | record(ai, "$(IOC):ai_REALs2_28")
937 | {
938 | field(SCAN, "1 second")
939 | field(DTYP, "EtherIP")
940 | field(INP, "@$(PLC) REALs2[28]")
941 | field(EGUF, "10")
942 | field(EGU, "socks")
943 | field(HOPR, "10")
944 | field(LOPR, "0")
945 | }
946 |
947 | record(ai, "$(IOC):ai_REALs3_28")
948 | {
949 | field(SCAN, "1 second")
950 | field(DTYP, "EtherIP")
951 | field(INP, "@$(PLC) REALs3[28]")
952 | field(EGUF, "10")
953 | field(EGU, "socks")
954 | field(HOPR, "10")
955 | field(LOPR, "0")
956 | }
957 |
958 | record(ai, "$(IOC):ai_REALs29")
959 | {
960 | field(SCAN, "1 second")
961 | field(DTYP, "EtherIP")
962 | field(INP, "@$(PLC) REALs[29]")
963 | field(EGUF, "10")
964 | field(EGU, "socks")
965 | field(HOPR, "10")
966 | field(LOPR, "0")
967 | }
968 |
969 | record(ai, "$(IOC):ai_REALs2_29")
970 | {
971 | field(SCAN, "1 second")
972 | field(DTYP, "EtherIP")
973 | field(INP, "@$(PLC) REALs2[29]")
974 | field(EGUF, "10")
975 | field(EGU, "socks")
976 | field(HOPR, "10")
977 | field(LOPR, "0")
978 | }
979 |
980 | record(ai, "$(IOC):ai_REALs3_29")
981 | {
982 | field(SCAN, "1 second")
983 | field(DTYP, "EtherIP")
984 | field(INP, "@$(PLC) REALs3[29]")
985 | field(EGUF, "10")
986 | field(EGU, "socks")
987 | field(HOPR, "10")
988 | field(LOPR, "0")
989 | }
990 |
991 | record(ai, "$(IOC):ai_REALs30")
992 | {
993 | field(SCAN, "1 second")
994 | field(DTYP, "EtherIP")
995 | field(INP, "@$(PLC) REALs[30]")
996 | field(EGUF, "10")
997 | field(EGU, "socks")
998 | field(HOPR, "10")
999 | field(LOPR, "0")
1000 | }
1001 |
1002 | record(ai, "$(IOC):ai_REALs2_30")
1003 | {
1004 | field(SCAN, "1 second")
1005 | field(DTYP, "EtherIP")
1006 | field(INP, "@$(PLC) REALs2[30]")
1007 | field(EGUF, "10")
1008 | field(EGU, "socks")
1009 | field(HOPR, "10")
1010 | field(LOPR, "0")
1011 | }
1012 |
1013 | record(ai, "$(IOC):ai_REALs3_30")
1014 | {
1015 | field(SCAN, "1 second")
1016 | field(DTYP, "EtherIP")
1017 | field(INP, "@$(PLC) REALs3[30]")
1018 | field(EGUF, "10")
1019 | field(EGU, "socks")
1020 | field(HOPR, "10")
1021 | field(LOPR, "0")
1022 | }
1023 |
1024 | record(ai, "$(IOC):ai_REALs31")
1025 | {
1026 | field(SCAN, "1 second")
1027 | field(DTYP, "EtherIP")
1028 | field(INP, "@$(PLC) REALs[31]")
1029 | field(EGUF, "10")
1030 | field(EGU, "socks")
1031 | field(HOPR, "10")
1032 | field(LOPR, "0")
1033 | }
1034 |
1035 | record(ai, "$(IOC):ai_REALs2_31")
1036 | {
1037 | field(SCAN, "1 second")
1038 | field(DTYP, "EtherIP")
1039 | field(INP, "@$(PLC) REALs2[31]")
1040 | field(EGUF, "10")
1041 | field(EGU, "socks")
1042 | field(HOPR, "10")
1043 | field(LOPR, "0")
1044 | }
1045 |
1046 | record(ai, "$(IOC):ai_REALs3_31")
1047 | {
1048 | field(SCAN, "1 second")
1049 | field(DTYP, "EtherIP")
1050 | field(INP, "@$(PLC) REALs3[31]")
1051 | field(EGUF, "10")
1052 | field(EGU, "socks")
1053 | field(HOPR, "10")
1054 | field(LOPR, "0")
1055 | }
1056 |
1057 | record(ai, "$(IOC):ai_REALs32")
1058 | {
1059 | field(SCAN, "1 second")
1060 | field(DTYP, "EtherIP")
1061 | field(INP, "@$(PLC) REALs[32]")
1062 | field(EGUF, "10")
1063 | field(EGU, "socks")
1064 | field(HOPR, "10")
1065 | field(LOPR, "0")
1066 | }
1067 |
1068 | record(ai, "$(IOC):ai_REALs2_32")
1069 | {
1070 | field(SCAN, "1 second")
1071 | field(DTYP, "EtherIP")
1072 | field(INP, "@$(PLC) REALs2[32]")
1073 | field(EGUF, "10")
1074 | field(EGU, "socks")
1075 | field(HOPR, "10")
1076 | field(LOPR, "0")
1077 | }
1078 |
1079 | record(ai, "$(IOC):ai_REALs3_32")
1080 | {
1081 | field(SCAN, "1 second")
1082 | field(DTYP, "EtherIP")
1083 | field(INP, "@$(PLC) REALs3[32]")
1084 | field(EGUF, "10")
1085 | field(EGU, "socks")
1086 | field(HOPR, "10")
1087 | field(LOPR, "0")
1088 | }
1089 |
1090 | record(ai, "$(IOC):ai_REALs33")
1091 | {
1092 | field(SCAN, "1 second")
1093 | field(DTYP, "EtherIP")
1094 | field(INP, "@$(PLC) REALs[33]")
1095 | field(EGUF, "10")
1096 | field(EGU, "socks")
1097 | field(HOPR, "10")
1098 | field(LOPR, "0")
1099 | }
1100 |
1101 | record(ai, "$(IOC):ai_REALs2_33")
1102 | {
1103 | field(SCAN, "1 second")
1104 | field(DTYP, "EtherIP")
1105 | field(INP, "@$(PLC) REALs2[33]")
1106 | field(EGUF, "10")
1107 | field(EGU, "socks")
1108 | field(HOPR, "10")
1109 | field(LOPR, "0")
1110 | }
1111 |
1112 | record(ai, "$(IOC):ai_REALs3_33")
1113 | {
1114 | field(SCAN, "1 second")
1115 | field(DTYP, "EtherIP")
1116 | field(INP, "@$(PLC) REALs3[33]")
1117 | field(EGUF, "10")
1118 | field(EGU, "socks")
1119 | field(HOPR, "10")
1120 | field(LOPR, "0")
1121 | }
1122 |
1123 | record(ai, "$(IOC):ai_REALs34")
1124 | {
1125 | field(SCAN, "1 second")
1126 | field(DTYP, "EtherIP")
1127 | field(INP, "@$(PLC) REALs[34]")
1128 | field(EGUF, "10")
1129 | field(EGU, "socks")
1130 | field(HOPR, "10")
1131 | field(LOPR, "0")
1132 | }
1133 |
1134 | record(ai, "$(IOC):ai_REALs2_34")
1135 | {
1136 | field(SCAN, "1 second")
1137 | field(DTYP, "EtherIP")
1138 | field(INP, "@$(PLC) REALs2[34]")
1139 | field(EGUF, "10")
1140 | field(EGU, "socks")
1141 | field(HOPR, "10")
1142 | field(LOPR, "0")
1143 | }
1144 |
1145 | record(ai, "$(IOC):ai_REALs3_34")
1146 | {
1147 | field(SCAN, "1 second")
1148 | field(DTYP, "EtherIP")
1149 | field(INP, "@$(PLC) REALs3[34]")
1150 | field(EGUF, "10")
1151 | field(EGU, "socks")
1152 | field(HOPR, "10")
1153 | field(LOPR, "0")
1154 | }
1155 |
1156 | record(ai, "$(IOC):ai_REALs35")
1157 | {
1158 | field(SCAN, "1 second")
1159 | field(DTYP, "EtherIP")
1160 | field(INP, "@$(PLC) REALs[35]")
1161 | field(EGUF, "10")
1162 | field(EGU, "socks")
1163 | field(HOPR, "10")
1164 | field(LOPR, "0")
1165 | }
1166 |
1167 | record(ai, "$(IOC):ai_REALs2_35")
1168 | {
1169 | field(SCAN, "1 second")
1170 | field(DTYP, "EtherIP")
1171 | field(INP, "@$(PLC) REALs2[35]")
1172 | field(EGUF, "10")
1173 | field(EGU, "socks")
1174 | field(HOPR, "10")
1175 | field(LOPR, "0")
1176 | }
1177 |
1178 | record(ai, "$(IOC):ai_REALs3_35")
1179 | {
1180 | field(SCAN, "1 second")
1181 | field(DTYP, "EtherIP")
1182 | field(INP, "@$(PLC) REALs3[35]")
1183 | field(EGUF, "10")
1184 | field(EGU, "socks")
1185 | field(HOPR, "10")
1186 | field(LOPR, "0")
1187 | }
1188 |
1189 | record(ai, "$(IOC):ai_REALs36")
1190 | {
1191 | field(SCAN, "1 second")
1192 | field(DTYP, "EtherIP")
1193 | field(INP, "@$(PLC) REALs[36]")
1194 | field(EGUF, "10")
1195 | field(EGU, "socks")
1196 | field(HOPR, "10")
1197 | field(LOPR, "0")
1198 | }
1199 |
1200 | record(ai, "$(IOC):ai_REALs2_36")
1201 | {
1202 | field(SCAN, "1 second")
1203 | field(DTYP, "EtherIP")
1204 | field(INP, "@$(PLC) REALs2[36]")
1205 | field(EGUF, "10")
1206 | field(EGU, "socks")
1207 | field(HOPR, "10")
1208 | field(LOPR, "0")
1209 | }
1210 |
1211 | record(ai, "$(IOC):ai_REALs3_36")
1212 | {
1213 | field(SCAN, "1 second")
1214 | field(DTYP, "EtherIP")
1215 | field(INP, "@$(PLC) REALs3[36]")
1216 | field(EGUF, "10")
1217 | field(EGU, "socks")
1218 | field(HOPR, "10")
1219 | field(LOPR, "0")
1220 | }
1221 |
1222 | record(ai, "$(IOC):ai_REALs37")
1223 | {
1224 | field(SCAN, "1 second")
1225 | field(DTYP, "EtherIP")
1226 | field(INP, "@$(PLC) REALs[37]")
1227 | field(EGUF, "10")
1228 | field(EGU, "socks")
1229 | field(HOPR, "10")
1230 | field(LOPR, "0")
1231 | }
1232 |
1233 | record(ai, "$(IOC):ai_REALs2_37")
1234 | {
1235 | field(SCAN, "1 second")
1236 | field(DTYP, "EtherIP")
1237 | field(INP, "@$(PLC) REALs2[37]")
1238 | field(EGUF, "10")
1239 | field(EGU, "socks")
1240 | field(HOPR, "10")
1241 | field(LOPR, "0")
1242 | }
1243 |
1244 | record(ai, "$(IOC):ai_REALs3_37")
1245 | {
1246 | field(SCAN, "1 second")
1247 | field(DTYP, "EtherIP")
1248 | field(INP, "@$(PLC) REALs3[37]")
1249 | field(EGUF, "10")
1250 | field(EGU, "socks")
1251 | field(HOPR, "10")
1252 | field(LOPR, "0")
1253 | }
1254 |
1255 | record(ai, "$(IOC):ai_REALs38")
1256 | {
1257 | field(SCAN, "1 second")
1258 | field(DTYP, "EtherIP")
1259 | field(INP, "@$(PLC) REALs[38]")
1260 | field(EGUF, "10")
1261 | field(EGU, "socks")
1262 | field(HOPR, "10")
1263 | field(LOPR, "0")
1264 | }
1265 |
1266 | record(ai, "$(IOC):ai_REALs2_38")
1267 | {
1268 | field(SCAN, "1 second")
1269 | field(DTYP, "EtherIP")
1270 | field(INP, "@$(PLC) REALs2[38]")
1271 | field(EGUF, "10")
1272 | field(EGU, "socks")
1273 | field(HOPR, "10")
1274 | field(LOPR, "0")
1275 | }
1276 |
1277 | record(ai, "$(IOC):ai_REALs3_38")
1278 | {
1279 | field(SCAN, "1 second")
1280 | field(DTYP, "EtherIP")
1281 | field(INP, "@$(PLC) REALs3[38]")
1282 | field(EGUF, "10")
1283 | field(EGU, "socks")
1284 | field(HOPR, "10")
1285 | field(LOPR, "0")
1286 | }
1287 |
1288 | record(ai, "$(IOC):ai_REALs39")
1289 | {
1290 | field(SCAN, "1 second")
1291 | field(DTYP, "EtherIP")
1292 | field(INP, "@$(PLC) REALs[39]")
1293 | field(EGUF, "10")
1294 | field(EGU, "socks")
1295 | field(HOPR, "10")
1296 | field(LOPR, "0")
1297 | }
1298 |
1299 | record(ai, "$(IOC):ai_REALs2_39")
1300 | {
1301 | field(SCAN, "1 second")
1302 | field(DTYP, "EtherIP")
1303 | field(INP, "@$(PLC) REALs2[39]")
1304 | field(EGUF, "10")
1305 | field(EGU, "socks")
1306 | field(HOPR, "10")
1307 | field(LOPR, "0")
1308 | }
1309 |
1310 | record(ai, "$(IOC):ai_REALs3_39")
1311 | {
1312 | field(SCAN, "1 second")
1313 | field(DTYP, "EtherIP")
1314 | field(INP, "@$(PLC) REALs3[39]")
1315 | field(EGUF, "10")
1316 | field(EGU, "socks")
1317 | field(HOPR, "10")
1318 | field(LOPR, "0")
1319 | }
1320 |
1321 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/ao.db:
--------------------------------------------------------------------------------
1 |
2 | record(ao, "$(IOC):ao_REAL2")
3 | {
4 | field(SCAN, "Passive")
5 | field(DTYP, "EtherIP")
6 | field(OUT, "@$(PLC) REAL2 S 1")
7 | field(HOPR, "10.0")
8 | field(LOPR, "0.0")
9 | }
10 |
11 |
12 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/bi.db:
--------------------------------------------------------------------------------
1 |
2 | record(bi, "$(IOC):BOOL")
3 | {
4 | field(SCAN, ".5 second")
5 | field(DTYP, "EtherIP")
6 | field(INP, "@$(PLC) BOOL")
7 | field(ZNAM, "False")
8 | field(ONAM, "True")
9 | field(ZSV, "NO_ALARM")
10 | field(OSV, "MAJOR")
11 | }
12 |
13 | record(bi, "$(IOC):bi_REAL")
14 | {
15 | field(SCAN, ".5 second")
16 | field(DTYP, "EtherIP")
17 | field(INP, "@$(PLC) REAL")
18 | field(ZNAM, "False")
19 | field(ONAM, "True")
20 | field(ZSV, "NO_ALARM")
21 | field(OSV, "MAJOR")
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/bo.db:
--------------------------------------------------------------------------------
1 |
2 | record(bo, "$(IOC):bo0")
3 | {
4 | field(SCAN, "Passive")
5 | field(DTYP, "EtherIP")
6 | field(OUT, "@$(PLC) BOOLs[0] S 1")
7 | field(ZNAM, "False")
8 | field(ONAM, "True")
9 | }
10 |
11 | record(bo, "$(IOC):bo2")
12 | {
13 | field(SCAN, "Passive")
14 | field(DTYP, "EtherIP")
15 | field(OUT, "@$(PLC) BOOLs[2] S 1")
16 | field(ZNAM, "False")
17 | field(ONAM, "True")
18 | }
19 |
20 | record(bo, "$(IOC):bo33")
21 | {
22 | field(SCAN, "Passive")
23 | field(DTYP, "EtherIP")
24 | field(OUT, "@$(PLC) BOOLs[33] S 1")
25 | field(ZNAM, "False")
26 | field(ONAM, "True")
27 | }
28 |
29 | record(bo, "$(IOC):bo240")
30 | {
31 | field(SCAN, "Passive")
32 | field(DTYP, "EtherIP")
33 | field(OUT, "@$(PLC) BOOLs[240] S 1")
34 | field(ZNAM, "False")
35 | field(ONAM, "True")
36 | }
37 |
38 | record(bo, "$(IOC):bo_IOC")
39 | {
40 | field(SCAN, "Passive")
41 | field(DTYP, "EtherIP")
42 | field(OUT, "@$(PLC) IOC.BOOL S 1")
43 | field(ZNAM, "False")
44 | field(ONAM, "True")
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/brad.db:
--------------------------------------------------------------------------------
1 | # EPICS Database file -*- shell-script -*-
2 |
3 | record(ai, "$(IOC):ai")
4 | {
5 | field(SCAN, "1 second")
6 | field(DTYP, "EtherIP")
7 | field(INP, "@$(PLC) DINT")
8 | field(PREC, "3")
9 | }
10 |
11 |
12 | record(stringin, "string")
13 | {
14 | field(SCAN, "1 second")
15 | field(DTYP, "EtherIP")
16 | field(INP, "@$(PLC) testStr2")
17 | }
18 |
19 | record(stringout, "out")
20 | {
21 | field(DTYP, "EtherIP")
22 | field(OUT, "@$(PLC) testStr2")
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/brad2.db:
--------------------------------------------------------------------------------
1 | # EPICS Database file -*- shell-script -*-
2 |
3 | record(ai, "$(IOC):ai")
4 | {
5 | field(SCAN, "1 second")
6 | field(DTYP, "EtherIP")
7 | field(INP, "@$(PLC) L85E_RealArray40[0]")
8 | field(PREC, "3")
9 | }
10 | record(bi, "$(IOC):ai1")
11 | {
12 | field(SCAN, "1 second")
13 | field(DTYP, "EtherIP")
14 | field(INP, "@$(PLC) L85E_RealArray40[1]")
15 | }
16 | record(bi, "$(IOC):ai1b")
17 | {
18 | field(SCAN, "1 second")
19 | field(DTYP, "EtherIP")
20 | field(INP, "@$(PLC) L85E_DINTArray40[0] B 1")
21 | }
22 |
23 | record(ao, "$(IOC):ao")
24 | {
25 | field(SCAN, "Passive")
26 | field(DTYP, "EtherIP")
27 | field(OUT, "@$(PLC) L85E_RealArray40[0] S 1")
28 | field(PREC, "3")
29 | }
30 |
31 | record(stringin, "$(IOC):si")
32 | {
33 | field(SCAN, "1 second")
34 | field(DTYP, "EtherIP")
35 | field(INP, "@$(PLC) L85E_String1")
36 | }
37 |
38 | record(stringout, "$(IOC):so")
39 | {
40 | field(DTYP, "EtherIP")
41 | field(OUT, "@$(PLC) L85E_String1 S 1")
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/eip_stat.db:
--------------------------------------------------------------------------------
1 | # -*- shell-script -*-
2 | # Example for reading statistical information from EtherIP driver/device
3 | #
4 | # IOC: prefix to records
5 | # PLC: PLC to use
6 | # TAG: queried tag (leads to PLC's ScanList)
7 | #
8 | # The Alarm/warn thresholds in here are an example.
9 | # You'll have to check with your PLC setup what
10 | # the normal, expected transfer times are.
11 |
12 | # The error counter will unfortunately be "INVALID" while disconnected from the PLC,
13 | # then indicate the error count once we're re-connected.
14 | # Good enough? While disconnected, the fact is pretty obvious.
15 | # Then when all looks good again, this record will tell us how many disconnects there used to be.
16 | record(ai, "$(IOC):PLC_ERRORS")
17 | {
18 | field(SCAN, ".5 second")
19 | field(DTYP, "EtherIP")
20 | field(INP, "@$(PLC) $(TAG) PLC_ERRORS")
21 | field(EGUF, "5")
22 | field(EGU, "Errors")
23 | field(HOPR, "5")
24 | field(LOPR, "0")
25 | # Ideally, there are zero errors
26 | field(HIGH, "1")
27 | field(HSV, "MINOR")
28 | }
29 |
30 | record(ai, "$(IOC):PLC_TASK_SLOW")
31 | {
32 | field(SCAN, ".5 second")
33 | field(DTYP, "EtherIP")
34 | field(INP, "@$(PLC) $(TAG) PLC_TASK_SLOW")
35 | field(EGUF, "5")
36 | field(EGU, "Holdups")
37 | field(HOPR, "5")
38 | field(LOPR, "0")
39 | }
40 |
41 | record(ai, "$(IOC):LIST_TICKS")
42 | {
43 | field(SCAN, ".5 second")
44 | field(DTYP, "EtherIP")
45 | field(INP, "@$(PLC) $(TAG) LIST_TICKS")
46 | field(EGUF, "5")
47 | field(EGU, "vx ticks")
48 | field(HOPR, "5")
49 | field(LOPR, "0")
50 | }
51 |
52 | record(ai, "$(IOC):LIST_SCAN_TIME")
53 | {
54 | field(SCAN, ".5 second")
55 | field(DTYP, "EtherIP")
56 | field(INP, "@$(PLC) $(TAG) LIST_SCAN_TIME")
57 | field(EGUF, "1")
58 | field(EGU, "s")
59 | field(HOPR, "1")
60 | field(LOPR, "0")
61 | field(PREC, "5")
62 | # To support 10 Hz, should return within 0.1 sec
63 | field(HIGH, "0.1")
64 | field(HSV, "MINOR")
65 | }
66 |
67 | record(ai, "$(IOC):LIST_MIN_SCAN_TIME")
68 | {
69 | field(SCAN, ".5 second")
70 | field(DTYP, "EtherIP")
71 | field(INP, "@$(PLC) $(TAG) LIST_MIN_SCAN_TIME")
72 | field(EGUF, "1")
73 | field(EGU, "s")
74 | field(HOPR, "1")
75 | field(LOPR, "0")
76 | field(PREC, "5")
77 | field(HIGH, "0.01")
78 | field(HSV, "MINOR")
79 | }
80 |
81 | record(ai, "$(IOC):LIST_MAX_SCAN_TIME")
82 | {
83 | field(SCAN, ".5 second")
84 | field(DTYP, "EtherIP")
85 | field(INP, "@$(PLC) $(TAG) LIST_MAX_SCAN_TIME")
86 | field(EGUF, "1")
87 | field(EGU, "s")
88 | field(HOPR, "1")
89 | field(LOPR, "0")
90 | field(PREC, "5")
91 | field(HIGH, "1.0")
92 | field(HSV, "MINOR")
93 | }
94 |
95 | record(ai, "$(IOC):TAG_TRANSFER_TIME")
96 | {
97 | field(SCAN, ".5 second")
98 | field(DTYP, "EtherIP")
99 | field(INP, "@$(PLC) $(TAG) TAG_TRANSFER_TIME")
100 | field(EGUF, "1000000000")
101 | field(EGU, "s")
102 | field(HOPR, "1")
103 | field(LOPR, "0")
104 | field(PREC, "5")
105 | }
106 |
107 | # Resets when writing "1".
108 | # Self-resets after 1 second
109 | record(bo, "$(IOC):RESET_PLC_STATS")
110 | {
111 | field(DTYP, "EtherIPReset")
112 | field(DOL, "0")
113 | field(PINI, "YES")
114 | field(ZNAM, "Reset")
115 | field(ONAM, "Reset!")
116 | field(HIGH, "1")
117 | }
118 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/lint.db:
--------------------------------------------------------------------------------
1 | # Test PLC:
2 | #
3 | # eipIoc -p plc1=160.91.233.45 -m IOC=test -d testether_ipApp/Db/lint.db
4 |
5 | record(int64in, "$(IOC):i64in")
6 | {
7 | field(SCAN, "I/O Intr")
8 | field(DTYP, "EtherIP")
9 | field(INP, "@plc1 testLint S 1")
10 | field(EGU, "Counts")
11 | }
12 |
13 | record(int64out, "$(IOC):i64out")
14 | {
15 | field(SCAN, "Passive")
16 | field(DTYP, "EtherIP")
17 | field(OUT, "@plc1 testLint S 1")
18 | field(TPRO, "1")
19 | }
20 |
21 | record(int64in, "$(IOC):a64in0")
22 | {
23 | field(SCAN, "I/O Intr")
24 | field(DTYP, "EtherIP")
25 | field(INP, "@plc1 testLArray[0] S 1")
26 | field(EGU, "Counts")
27 | }
28 |
29 | record(int64out, "$(IOC):a64out0")
30 | {
31 | field(SCAN, "Passive")
32 | field(DTYP, "EtherIP")
33 | field(OUT, "@plc1 testLArray[0] S 1")
34 | field(TPRO, "1")
35 | }
36 |
37 | record(int64in, "$(IOC):a64in1")
38 | {
39 | field(SCAN, "I/O Intr")
40 | field(DTYP, "EtherIP")
41 | field(INP, "@plc1 testLArray[1] S 1")
42 | field(EGU, "Counts")
43 | }
44 |
45 | record(int64out, "$(IOC):a64out1")
46 | {
47 | field(SCAN, "Passive")
48 | field(DTYP, "EtherIP")
49 | field(OUT, "@plc1 testLArray[1] S 1")
50 | field(TPRO, "1")
51 | }
52 |
53 | record(int64in, "$(IOC):a64in9")
54 | {
55 | field(SCAN, "I/O Intr")
56 | field(DTYP, "EtherIP")
57 | field(INP, "@plc1 testLArray[9] S 1")
58 | field(EGU, "Counts")
59 | }
60 |
61 | record(int64out, "$(IOC):a64out9")
62 | {
63 | field(SCAN, "Passive")
64 | field(DTYP, "EtherIP")
65 | field(OUT, "@plc1 testLArray[9] S 1")
66 | field(TPRO, "1")
67 | }
68 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/mbbi.db:
--------------------------------------------------------------------------------
1 | record(mbbi, "$(IOC):mbbi0")
2 | {
3 | field(SCAN, "1 second")
4 | field(DTYP, "EtherIP")
5 | field(INP, "@$(PLC) BOOLs[30]")
6 | field(NOBT, "3")
7 | field(ZRVL, "0")
8 | field(ONVL, "1")
9 | field(TWVL, "2")
10 | field(THVL, "3")
11 | field(FRVL, "4")
12 | field(FVVL, "5")
13 | field(SXVL, "6")
14 | field(SVVL, "7")
15 | field(ZRST, "Zero-Zero-Zero")
16 | field(ONST, "Zero-Zero- One")
17 | field(TWST, "Zero-One -Zero")
18 | field(THST, "Zero-One - One")
19 | field(FRST, "One -Zero-Zero")
20 | field(FVST, "One -Zero- One")
21 | field(SXST, "One -One -Zero")
22 | field(SVST, "One -One - One")
23 | }
24 |
25 | record(mbbi, "$(IOC):mbbi1")
26 | {
27 | field(SCAN, "I/O Intr")
28 | field(DTYP, "EtherIP")
29 | field(INP, "@$(PLC) BOOLs[10] S .5")
30 | field(NOBT, "2")
31 | field(ZRVL, "0")
32 | field(ONVL, "1")
33 | field(TWVL, "2")
34 | field(THVL, "3")
35 | field(ZRST, "Zero-Zero")
36 | field(ONST, "Zero- One")
37 | field(TWST, "One -Zero")
38 | field(THST, "One - One")
39 | }
40 |
41 | record(mbbiDirect, "$(IOC):mbbid0")
42 | {
43 | field(SCAN, "I/O Intr")
44 | field(DTYP, "EtherIP")
45 | field(INP, "@$(PLC) BOOLs[20] S .5")
46 | field(NOBT, "5")
47 | }
48 |
49 | record(mbbiDirect, "$(IOC):mbbid1")
50 | {
51 | field(SCAN, "1 second")
52 | field(DTYP, "EtherIP")
53 | field(INP, "@$(PLC) BOOLs[30]")
54 | field(NOBT, "32")
55 | }
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/mbbo.db:
--------------------------------------------------------------------------------
1 | record(mbbo, "$(IOC):mbbo0")
2 | {
3 | field(SCAN, "Passive")
4 | field(DTYP, "EtherIP")
5 | field(OUT, "@$(PLC) BOOLs[30] S 0.5")
6 | field(NOBT, "3")
7 | field(ZRVL, "0")
8 | field(ONVL, "1")
9 | field(TWVL, "2")
10 | field(THVL, "3")
11 | field(FRVL, "4")
12 | field(FVVL, "5")
13 | field(SXVL, "6")
14 | field(SVVL, "7")
15 | field(ZRST, "Zero-Zero-Zero")
16 | field(ONST, "Zero-Zero- One")
17 | field(TWST, "Zero-One -Zero")
18 | field(THST, "Zero-One - One")
19 | field(FRST, "One -Zero-Zero")
20 | field(FVST, "One -Zero- One")
21 | field(SXST, "One -One -Zero")
22 | field(SVST, "One -One - One")
23 | }
24 |
25 | record(mbboDirect, "$(IOC):mbbod0")
26 | {
27 | field(SCAN, "Passive")
28 | field(DTYP, "EtherIP")
29 | field(OUT, "@$(PLC) BOOLs[35] S 0.1")
30 | field(NOBT, "10")
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/mkana.pl:
--------------------------------------------------------------------------------
1 | $OUT=">ana.db";
2 |
3 | open OUT or die "Cannot create $OUT";
4 |
5 | select OUT;
6 |
7 | for ($i=0; $i<40; ++$i)
8 | {
9 | printf ("record(ai, \"\$(IOC):ai_REALs%d\")\n", $i);
10 | printf ("{\n");
11 | printf (" field(SCAN, \"1 second\")\n");
12 | printf (" field(DTYP, \"EtherIP\")\n");
13 | printf (" field(INP, \"\@\$(PLC) REALs[%d]\")\n", $i);
14 | printf (" field(EGUF, \"10\")\n");
15 | printf (" field(EGU, \"socks\")\n");
16 | printf (" field(HOPR, \"10\")\n");
17 | printf (" field(LOPR, \"0\")\n");
18 | printf ("}\n");
19 | printf ("\n");
20 | printf ("record(ai, \"\$(IOC):ai_REALs2_%d\")\n", $i);
21 | printf ("{\n");
22 | printf (" field(SCAN, \"1 second\")\n");
23 | printf (" field(DTYP, \"EtherIP\")\n");
24 | printf (" field(INP, \"\@\$(PLC) REALs2[%d]\")\n", $i);
25 | printf (" field(EGUF, \"10\")\n");
26 | printf (" field(EGU, \"socks\")\n");
27 | printf (" field(HOPR, \"10\")\n");
28 | printf (" field(LOPR, \"0\")\n");
29 | printf ("}\n");
30 | printf ("\n");
31 | printf ("record(ai, \"\$(IOC):ai_REALs3_%d\")\n", $i);
32 | printf ("{\n");
33 | printf (" field(SCAN, \"1 second\")\n");
34 | printf (" field(DTYP, \"EtherIP\")\n");
35 | printf (" field(INP, \"\@\$(PLC) REALs3[%d]\")\n", $i);
36 | printf (" field(EGUF, \"10\")\n");
37 | printf (" field(EGU, \"socks\")\n");
38 | printf (" field(HOPR, \"10\")\n");
39 | printf (" field(LOPR, \"0\")\n");
40 | printf ("}\n");
41 | printf ("\n");
42 | }
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/mkbin.pl:
--------------------------------------------------------------------------------
1 | # Create binary record for testing EtherIP
2 |
3 | $OUT=">bin.db";
4 |
5 | open OUT or die "Cannot create $OUT";
6 |
7 | select OUT;
8 | for ($i=0; $i<352; ++$i)
9 | {
10 | printf ("record(bi, \"\$(IOC):bi%d\")\n", $i);
11 | printf ("{\n");
12 | printf (" field(SCAN, \"I/O Intr\")\n");
13 | printf (" field(DTYP, \"EtherIP\")\n");
14 | printf (" field(INP, \"\@\$(PLC) BOOLs[%d] S 0.1\")\n", $i);
15 | printf (" field(ZNAM, \"False\")\n");
16 | printf (" field(ONAM, \"True\")\n");
17 | printf (" field(ZSV, \"NO_ALARM\")\n");
18 | printf (" field(OSV, \"MAJOR\")\n");
19 | printf ("}\n");
20 | printf ("\n");
21 | }
22 |
23 | close OUT;
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/mod.db:
--------------------------------------------------------------------------------
1 | # EPICS Database file -*- shell-script -*-
2 | #
3 | # Testing access to SNS NC RF Modulator
4 | # Read a single REAL tag called "REAL"
5 | record(ai, "Vmon")
6 | {
7 | field(SCAN, "1 second")
8 | field(DTYP, "EtherIP")
9 | field(INP, "@$(PLC) P1R0[2]")
10 | field(PREC, "1")
11 | field(EGU, "kV")
12 | }
13 |
14 | record(ai, "Imon")
15 | {
16 | field(SCAN, "1 second")
17 | field(DTYP, "EtherIP")
18 | field(INP, "@$(PLC) P1R0[3]")
19 | field(PREC, "1")
20 | field(EGU, "A")
21 | }
22 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/ramp.db:
--------------------------------------------------------------------------------
1 | record(calc, "$(IOC):ramp")
2 | {
3 | field(DESC, "Random Number")
4 | field(SCAN, ".1 second")
5 | field(EGU,"flueps")
6 | field(CALC,"A>=B?0:A+0.5*RNDM")
7 | field(INPA,"$(IOC):ramp.VAL")
8 | field(INPB,"10")
9 | field(PREC,"4")
10 | field(LOPR,"0.0")
11 | field(HOPR,"10.0")
12 | }
13 |
--------------------------------------------------------------------------------
/testether_ipApp/Db/test.db:
--------------------------------------------------------------------------------
1 | # EPICS Database file -*- shell-script -*-
2 | # The following record types are tested in here:
3 | #
4 | # ai, ao
5 | # bi, bo
6 | # mbbi
7 | # mbbiDirect
8 | # stringin
9 | # waveform
10 | # mbbo
11 | # mbboDirect
12 | #
13 | # ... in combination with these tags on the PLC,
14 | # where the tag names match their types,
15 | # using a very strange rule for upper-or lowercase 's':
16 | #
17 | # REAL REAL, REALs[40]
18 | # BOOL BOOL, BOOLs[352]
19 | # REAL REALs[40]
20 | # DINT DINTS[40]
21 | # INT INTs[40]
22 | # BOOL NESTED.BOOLs[32]
23 | # REAL NESTED.REALs[2]
24 | # INT NESTED.STRUCTS[5].INT
25 | # REAL NESTED.STRUCTS[5].REAL
26 | # DINT NESTED.STRUCTS[5].DINT
27 | # BOOL NESTED.STRUCTS[5].BOOL
28 | # STRING STRING
29 | # MainProgram.timer_1.TT
30 | #
31 | # Record/tag combinations that are not listed
32 | # in here might not work or give unexpected results.
33 |
34 | # -------------------------------------------------
35 | # ai
36 | # -------------------------------------------------
37 | # Read a single REAL tag called "REAL"
38 | record(ai, "$(IOC):aiREAL")
39 | {
40 | field(SCAN, "1 second")
41 | field(DTYP, "EtherIP")
42 | field(INP, "@$(PLC) REAL")
43 | field(PREC, "3")
44 | }
45 | # Read a single tag from an array called "REALs"
46 | record(ai, "$(IOC):aiREALs2")
47 | {
48 | field(SCAN, "1 second")
49 | field(DTYP, "EtherIP")
50 | field(INP, "@$(PLC) REALs[2]")
51 | field(PREC, "3")
52 | }
53 | # Similar, just different array elements.
54 | # NOTE: As a result, the driver will
55 | # read the array from elements 0 to 5.
56 | #
57 | # On the IOC, "drvEtherIP_report(10)" would show
58 | # something like this:
59 | # *** Tag 'REALs' @ 0x1B4CB08:
60 | # ...
61 | # compiled tag : REALs
62 | # elements : 6
63 | # -> the driver scans 6 elements from the tag "REALs"
64 | record(ai, "$(IOC):aiREALs5")
65 | {
66 | field(SCAN, "1 second")
67 | field(DTYP, "EtherIP")
68 | field(INP, "@$(PLC) REALs[5]")
69 | field(PREC, "3")
70 | }
71 | # Read a single tag from an array called "REALs",
72 | # but really only the single element ("E" flag)!
73 | # The driver does not combine this one
74 | # into an array request for elements 0..39
75 | #
76 | # On the IOC, "drvEtherIP_report(10)" would show
77 | # something like this:
78 | # *** Tag 'REALs[39]' @ 0x1B4CD58:
79 | # ...
80 | # compiled tag : REALs[39]
81 | # elements : 1
82 | # -> the driver scans "REALs[39]" as a single element.
83 | record(ai, "$(IOC):aiREALs39")
84 | {
85 | field(SCAN, "1 second")
86 | field(DTYP, "EtherIP")
87 | field(INP, "@$(PLC) REALs[39] E")
88 | field(PREC, "3")
89 | }
90 | # As before, but connected to a DINT
91 | record(ai, "$(IOC):aiDINT")
92 | {
93 | field(SCAN, ".1 second")
94 | field(DTYP, "EtherIP")
95 | field(INP, "@$(PLC) DINT")
96 | }
97 | record(ai, "$(IOC):aiDINTs1")
98 | {
99 | field(SCAN, ".1 second")
100 | field(DTYP, "EtherIP")
101 | field(INP, "@$(PLC) DINTs[1]")
102 | }
103 | record(ai, "$(IOC):aiDINTs2")
104 | {
105 | field(SCAN, ".1 second")
106 | field(DTYP, "EtherIP")
107 | field(INP, "@$(PLC) DINTs[2]")
108 | }
109 | record(ai, "$(IOC):aiDINTs3")
110 | {
111 | field(SCAN, ".1 second")
112 | field(DTYP, "EtherIP")
113 | field(INP, "@$(PLC) DINTs[3]")
114 | }
115 | # As before, but connected to an INT array element
116 | record(ai, "$(IOC):aiINTs2")
117 | {
118 | field(SCAN, ".1 second")
119 | field(DTYP, "EtherIP")
120 | field(INP, "@$(PLC) INTs[2]")
121 | }
122 | record(ai, "$(IOC):aiINTs3")
123 | {
124 | field(SCAN, ".1 second")
125 | field(DTYP, "EtherIP")
126 | field(INP, "@$(PLC) INTs[3]")
127 | }
128 |
129 | # -------------------------------------------------
130 | # ao
131 | # -------------------------------------------------
132 | # Output record, write to REAL tag.
133 | # Record is "Passive", will only process when
134 | # a) changed via operator display/ChannelAccess:
135 | # -> value is written to PLC
136 | # b) tag changed on PLC
137 | # -> record's VAL is updated
138 | #
139 | # "S" flag: though record is passive, driver
140 | # needs some scan period at which
141 | # it monitors the PLC for changes
142 | # of the tag. Here we pick 1 second.
143 | record(ao, "$(IOC):aoREAL")
144 | {
145 | field(SCAN, "Passive")
146 | field(DTYP, "EtherIP")
147 | field(OUT, "@$(PLC) REAL S 1")
148 | field(PREC, "3")
149 | }
150 | record(ao, "$(IOC):aoREALs2")
151 | {
152 | field(SCAN, "Passive")
153 | field(DTYP, "EtherIP")
154 | field(OUT, "@$(PLC) REALs[2] S 1")
155 | field(PREC, "3")
156 | }
157 | # Dito, but DINT
158 | record(ao, "$(IOC):aoDINT")
159 | {
160 | field(SCAN, "Passive")
161 | field(DTYP, "EtherIP")
162 | field(OUT, "@$(PLC) DINT S 1")
163 | }
164 | record(ao, "$(IOC):aoDINTs2")
165 | {
166 | field(SCAN, "Passive")
167 | field(DTYP, "EtherIP")
168 | field(OUT, "@$(PLC) DINTs[2] S 1")
169 | }
170 | record(ao, "$(IOC):aoINTs3")
171 | {
172 | field(SCAN, "Passive")
173 | field(DTYP, "EtherIP")
174 | field(OUT, "@$(PLC) INTs[3] S 1")
175 | }
176 |
177 | # -------------------------------------------------
178 | # bi records
179 | # -------------------------------------------------
180 | # Binary input, connected to a BOOL tag
181 | record(bi, "$(IOC):biBOOL")
182 | {
183 | field(SCAN, "1 second")
184 | field(DTYP, "EtherIP")
185 | field(INP, "@$(PLC) BOOL")
186 | field(ZNAM, "False")
187 | field(ONAM, "True")
188 | }
189 | # Binary input, connected to a DINT
190 | # -> reads bit 0 of DINT value
191 | record(bi, "$(IOC):biDINT")
192 | {
193 | field(SCAN, "1 second")
194 | field(DTYP, "EtherIP")
195 | field(INP, "@$(PLC) DINT")
196 | field(ZNAM, "False")
197 | field(ONAM, "True")
198 | }
199 | # .. reads bit 3 of DINT value
200 | record(bi, "$(IOC):biDINT_3")
201 | {
202 | field(SCAN, "1 second")
203 | field(DTYP, "EtherIP")
204 | field(INP, "@$(PLC) DINT B 3")
205 | field(ZNAM, "False")
206 | field(ONAM, "True")
207 | }
208 | # BOOL array element
209 | record(bi, "$(IOC):biBOOLs5")
210 | {
211 | field(SCAN, "1 second")
212 | field(DTYP, "EtherIP")
213 | field(INP, "@$(PLC) BOOLs[5]")
214 | field(ZNAM, "False")
215 | field(ONAM, "True")
216 | }
217 | # !! Note !!
218 | # The following binary records are NOT connected
219 | # to BOOL arrays.
220 | # Binary input, connected to a DINT element
221 | # The bi expects a BOOL array, not a DINT array.
222 | # This will *NOT* read array element #40 but bit #40
223 | # which is bit # 8 in the second DINT.
224 | #
225 | # You can check this by setting the "TPRO" field
226 | # of this record. TPRO=trace processing, logs
227 | # to IOC console when record is processed.
228 | # The EtherIP driver will show this additional information:
229 | # process: snsioc4:biDINTs40
230 | # link_text : 'plc1 DINTs[40]'
231 | # PLC_name : 'plc1'
232 | # string_tag : 'DINTs'
233 | # element : 1 <- element 1, not 40!
234 | # mask : 0x100 <- mask selects bit 8
235 | #
236 | # Hint: TPRO causes logging when the record is processed,
237 | # in this case every second, so you can't read the output
238 | # since you always get new stuff.
239 | # -> use channel access (edm, caput, ...) to set it to "1",
240 | # wait 3 seconds, then set it to "0" again,
241 | # and then inspect the messsages you got.
242 | record(bi, "$(IOC):biDINTs40_error")
243 | {
244 | field(SCAN, "1 second")
245 | field(DTYP, "EtherIP")
246 | field(INP, "@$(PLC) DINTs[40]")
247 | field(ZNAM, "False")
248 | field(ONAM, "True")
249 | }
250 | # Use the "B " flag to
251 | # override the default behaviour will explicit
252 | # bit addressing:
253 | # Read DINT[8], bit 5
254 | #
255 | # Set TPRO and you should get:
256 | # process: snsioc4:biDINTs8_5
257 | # link_text : 'plc1 DINTs[8] B 5'
258 | # PLC_name : 'plc1'
259 | # string_tag : 'DINTs'
260 | # element : 8 <- indeed element 8
261 | # mask : 0x20 <- mask selects bit 5
262 | record(bi, "$(IOC):biDINTs8_5")
263 | {
264 | field(SCAN, "1 second")
265 | field(DTYP, "EtherIP")
266 | field(INP, "@$(PLC) DINTs[8] B 5")
267 | field(ZNAM, "False")
268 | field(ONAM, "True")
269 | }
270 |
271 | # -------------------------------------------------
272 | # bo records
273 | # -------------------------------------------------
274 | record(bo, "$(IOC):boBOOL")
275 | {
276 | field(DTYP, "EtherIP")
277 | field(OUT, "@$(PLC) BOOL S 1")
278 | field(ZNAM, "False")
279 | field(ONAM, "True")
280 | }
281 | record(bo, "$(IOC):boBOOLs5")
282 | {
283 | field(DTYP, "EtherIP")
284 | field(OUT, "@$(PLC) BOOLs[5] S 1")
285 | field(ZNAM, "False")
286 | field(ONAM, "True")
287 | }
288 | record(bo, "$(IOC):boINTs3_2")
289 | {
290 | field(DTYP, "EtherIP")
291 | field(OUT, "@$(PLC) INTs[3] B 2 S 1")
292 | field(ZNAM, "False")
293 | field(ONAM, "True")
294 | }
295 |
296 | # -------------------------------------------------
297 | # mbbi records
298 | # -------------------------------------------------
299 | # BOOL array elements, decodes 2 bits
300 | record(mbbi, "$(IOC):mbbiBOOLs300")
301 | {
302 | field(SCAN, "1 second")
303 | field(DTYP, "EtherIP")
304 | field(INP, "@$(PLC) BOOLs[300]")
305 | field(NOBT, "2")
306 | field(ZRVL, "0")
307 | field(ONVL, "1")
308 | field(TWVL, "2")
309 | field(THVL, "3")
310 | field(ZRST, "Zero-Zero")
311 | field(ONST, "Zero- One")
312 | field(TWST, "One -Zero")
313 | field(THST, "One - One")
314 | }
315 | record(mbbi, "$(IOC):mbbiDINTs2_3")
316 | {
317 | field(SCAN, "1 second")
318 | field(DTYP, "EtherIP")
319 | field(INP, "@$(PLC) DINTs[2] B 3")
320 | field(NOBT, "2")
321 | field(ZRVL, "0")
322 | field(ONVL, "1")
323 | field(TWVL, "2")
324 | field(THVL, "3")
325 | field(ZRST, "Zero-Zero")
326 | field(ONST, "Zero- One")
327 | field(TWST, "One -Zero")
328 | field(THST, "One - One")
329 | }
330 |
331 | # -------------------------------------------------
332 | # mbbo records
333 | # -------------------------------------------------
334 | # BOOL array elements, writes 2 bits
335 | # Used SCAN to set period, no "S" flag needed in OUT
336 | # (but possibly not the ideal configuration)
337 | record(mbbo, "$(IOC):mbboBOOLs300")
338 | {
339 | field(SCAN, "1 second")
340 | field(DTYP, "EtherIP")
341 | field(OUT, "@$(PLC) BOOLs[300]")
342 | field(NOBT, "2")
343 | field(ZRVL, "0")
344 | field(ONVL, "1")
345 | field(TWVL, "2")
346 | field(THVL, "3")
347 | field(ZRST, "Zero-Zero")
348 | field(ONST, "Zero- One")
349 | field(TWST, "One -Zero")
350 | field(THST, "One - One")
351 | }
352 |
353 | # B flag again: write to DINT array element #4, bit31.
354 | # Note: This mbbo writes to 2 bits, so it crosses
355 | # DINT boundaries into element #5, bit 0.
356 | # This works for 32bit UDINT but not for INTs,
357 | # you might not want to depend on this feature.
358 | record(mbbo, "$(IOC):mbboDINTs4_31")
359 | {
360 | field(SCAN, "1 second")
361 | field(DTYP, "EtherIP")
362 | field(OUT, "@$(PLC) DINTs[4] B 31")
363 | field(NOBT, "2")
364 | field(ZRVL, "0")
365 | field(ONVL, "1")
366 | field(TWVL, "2")
367 | field(THVL, "3")
368 | field(ZRST, "Zero-Zero")
369 | field(ONST, "Zero- One")
370 | field(TWST, "One -Zero")
371 | field(THST, "One - One")
372 | }
373 | # Like mbboDINTs4_31, but targetting INT
374 | # which has only 16 bits.
375 | record(mbbo, "$(IOC):mbboINTs2_14")
376 | {
377 | field(SCAN, "1 second")
378 | field(DTYP, "EtherIP")
379 | field(OUT, "@$(PLC) INTs[2] B 14")
380 | field(NOBT, "2")
381 | field(ZRVL, "0")
382 | field(ONVL, "1")
383 | field(TWVL, "2")
384 | field(THVL, "3")
385 | field(ZRST, "Zero-Zero")
386 | field(ONST, "Zero- One")
387 | field(TWST, "One -Zero")
388 | field(THST, "One - One")
389 | }
390 |
391 | # INT, bit addressing.
392 | # Uses "I/O Intr" to process when data changes.
393 | # Since the SCAN field doesn't tell the driver
394 | # how often it should check, we need the "S" flag
395 | record(mbbiDirect, "$(IOC):mbbidINTs3_4")
396 | {
397 | field(SCAN, "I/O Intr")
398 | field(DTYP, "EtherIP")
399 | field(INP, "@plc1 INTs[3] B 4 S 1")
400 | field(NOBT, "5")
401 | }
402 |
403 | # -------------------------------------------------
404 | # Other odd records
405 | # -------------------------------------------------
406 |
407 | # Note that string data type of PLC is longer
408 | # than the string record's value,
409 | # so what you get might be truncated
410 | record(stringin, "$(IOC):string")
411 | {
412 | field(SCAN, "1 second")
413 | field(DTYP, "EtherIP")
414 | field(INP, "@$(PLC) STRING")
415 | }
416 |
417 | # IF the tag is of type REAL,
418 | # the waveform must use DOUBLE !
419 | record(waveform, "$(IOC):REALwf")
420 | {
421 | field(SCAN, "1 second")
422 | field(DTYP, "EtherIP")
423 | field(INP, "@$(PLC) REALs")
424 | field(NELM, "40")
425 | field(FTVL, "DOUBLE")
426 | }
427 |
428 | # IF the tag is of type not-REAL,
429 | # the waveform must use LONG !
430 | record(waveform, "$(IOC):DINTLwf")
431 | {
432 | field(SCAN, "1 second")
433 | field(DTYP, "EtherIP")
434 | field(INP, "@$(PLC) DINTs")
435 | field(NELM, "40")
436 | field(FTVL, "LONG")
437 | }
438 |
439 | # Some I/O Intr tests
440 | record(bi, "$(IOC):bi_int0")
441 | {
442 | field(SCAN, "I/O Intr")
443 | field(DTYP, "EtherIP")
444 | field(INP, "@$(PLC) DINTs[0] B 0 S 1")
445 | field(ZNAM, "False")
446 | field(ONAM, "True")
447 | }
448 |
449 | record(bi, "$(IOC):bi_int1")
450 | {
451 | field(SCAN, "I/O Intr")
452 | field(DTYP, "EtherIP")
453 | field(INP, "@$(PLC) DINTs[0] B 1 S 1")
454 | field(ZNAM, "False")
455 | field(ONAM, "True")
456 | }
457 |
458 | record(bi, "$(IOC):bi_int2")
459 | {
460 | field(SCAN, "I/O Intr")
461 | field(DTYP, "EtherIP")
462 | field(INP, "@$(PLC) DINTs[0] B 2 S 1")
463 | field(ZNAM, "False")
464 | field(ONAM, "True")
465 | }
466 |
467 | record(ao, "$(IOC):aoDINTs0")
468 | {
469 | field(SCAN, "Passive")
470 | field(DTYP, "EtherIP")
471 | field(OUT, "@$(PLC) DINTs[0] S 1")
472 | }
473 |
--------------------------------------------------------------------------------
/testether_ipApp/Makefile:
--------------------------------------------------------------------------------
1 | TOP = ..
2 |
3 | include $(TOP)/configure/CONFIG
4 |
5 | DIRS := src
6 | DIRS += Db
7 |
8 | include $(TOP)/configure/RULES_DIRS
9 |
--------------------------------------------------------------------------------
/testether_ipApp/RSLogix/test.L5K:
--------------------------------------------------------------------------------
1 | (*********************************************
2 |
3 | Import-Export
4 | Version := RSLogix 5000 v12.02
5 | Owner := kasemir, ORNL
6 | Exported := Wed Oct 06 11:00:39 2004
7 | **********************************************)
8 | IE_VER := 2.3;
9 |
10 | CONTROLLER EtherIP_Test (ProcessorType := 1756-L1,
11 | Major := 12,
12 | TimeSlice := 10,
13 | CommPath := AB_DF1-1\1,
14 | RedundancyEnabled := 0,
15 | KeepTestEditsOnSwitchOver := 0,
16 | DataTablePadPercentage := 50,
17 | SecurityCode := 0,
18 | SFCExecutionControl := CurrentActive,
19 | SFCRestartPosition := MostRecent,
20 | SFCLastScan := DontScan)
21 | DATATYPE Nested (FamilyType := NoFamily)
22 | BOOL BOOLs[32];
23 | REAL REALs[2];
24 | TestStruct STRUCTS[5] (Radix := Float);
25 | END_DATATYPE
26 |
27 | DATATYPE TestStruct (FamilyType := NoFamily)
28 | INT INT;
29 | REAL REAL;
30 | DINT DINT;
31 | SINT ZZZZZZZZZZTestStruct3 (Hidden := 1);
32 | BIT BOOL ZZZZZZZZZZTestStruct3 : 0;
33 | END_DATATYPE
34 |
35 | MODULE Local (Parent := Local,
36 | CatalogNumber := 1756-L1,
37 | Major := 12,
38 | Minor := 1,
39 | PortLabel := RxBACKPLANE,
40 | ChassisSize := 7,
41 | Slot := 0,
42 | Mode := 2#0000_0000_0000_0001,
43 | CompatibleModule := 0,
44 | KeyMask := 2#0000_0000_0001_1111)
45 | END_MODULE
46 |
47 | MODULE ENET (Parent := Local,
48 | CatalogNumber := 1756-ENET/B,
49 | Major := 2,
50 | Minor := 1,
51 | PortLabel := RxBACKPLANE,
52 | Slot := 1,
53 | NodeAddress := 172.31.72.94,
54 | Mode := 2#0000_0000_0000_0000,
55 | CompatibleModule := 0,
56 | KeyMask := 2#0000_0000_0000_0000)
57 | END_MODULE
58 |
59 | TAG
60 | BOOL : BOOL (RADIX := Decimal) := 1;
61 | BOOLs : BOOL[352] (RADIX := Decimal) := [2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0
62 | ,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0
63 | ,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0
64 | ,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0
65 | ,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0
66 | ,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0
67 | ,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0
68 | ,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0
69 | ,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0
70 | ,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0
71 | ,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0
72 | ,2#0,2#0,2#0,2#0,2#1,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0
73 | ,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0
74 | ,2#0];
75 | DINT : DINT (RADIX := Decimal) := 0;
76 | DINTS : DINT[40] (RADIX := Decimal) := [1,2,15,4,5,6,7,8,9,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
77 | INTs : INT[40] (RADIX := Decimal) := [0,0,-32768,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
78 | NESTED : Nested := [[2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0,2#0
79 | ,2#0,2#0,2#0,2#0,2#0],[0.00000000e+000,0.00000000e+000],[[0,0.00000000e+000,0,0],[0,4.20000000e+001,0,0
80 | ],[0,0.00000000e+000,0,0],[0,0.00000000e+000,0,0],[0,0.00000000e+000,0,0]]];
81 | REAL : REAL (RADIX := Float) := 3.14000010e+000;
82 | REALs : REAL[40] (RADIX := Float) := [1.00000000e+000,2.00000000e+000,5.00000000e+001,4.00000000e+000,5.00000000e+000,6.00000000e+000
83 | ,7.00000000e+000,8.00000000e+000,9.00000000e+000,1.00000000e+001,0.00000000e+000,0.00000000e+000
84 | ,0.00000000e+000,0.00000000e+000,0.00000000e+000,0.00000000e+000,0.00000000e+000,0.00000000e+000
85 | ,0.00000000e+000,0.00000000e+000,0.00000000e+000,0.00000000e+000,0.00000000e+000,0.00000000e+000
86 | ,0.00000000e+000,0.00000000e+000,0.00000000e+000,0.00000000e+000,0.00000000e+000,0.00000000e+000
87 | ,0.00000000e+000,0.00000000e+000,0.00000000e+000,0.00000000e+000,0.00000000e+000,0.00000000e+000
88 | ,0.00000000e+000,0.00000000e+000,0.00000000e+000,3.90000000e+001];
89 | STRING : STRING := [3,'Hi!$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
90 | ];
91 | END_TAG
92 |
93 | PROGRAM MainProgram (MAIN := MainRoutine,
94 | MODE := 0,
95 | DisableFlag := 0)
96 | TAG
97 | timer_1 : TIMER := [216121,200,0];
98 | timer_2 : TIMER := [215921,200,0];
99 | END_TAG
100 |
101 | ROUTINE MainRoutine
102 | RC: "Two timers, running mutually exclusive";
103 | N: XIO(timer_2.TT)TON(timer_1,?,?);
104 | N: XIO(timer_1.TT)TON(timer_2,?,?);
105 | END_ROUTINE
106 |
107 | END_PROGRAM
108 |
109 | TASK MainTask (Type := CONTINUOUS,
110 | Watchdog := 500.000,
111 | Priority := 10,
112 | Rate := 10.000,
113 | EnableTimeout := No,
114 | DisableUpdateOutputs := No,
115 | InhibitTask := No)
116 | MainProgram;
117 | END_TASK
118 |
119 | CONFIG ASCII(XONXOFFEnable := 0,
120 | DeleteMode := 0,
121 | EchoMode := 0,
122 | TerminationChars := -243,
123 | AppendChars := 2573,
124 | BufferSize := 82) END_CONFIG
125 |
126 | CONFIG ControllerDevice END_CONFIG
127 |
128 | CONFIG CST(SystemTimeMasterID := 0) END_CONFIG
129 |
130 | CONFIG DF1(DuplicateDetection := 1,
131 | ErrorDetection := BCC Error,
132 | EmbeddedResponseEnable := 0,
133 | DF1Mode := Pt to Pt,
134 | ACKTimeout := 50,
135 | NAKReceiveLimit := 3,
136 | ENQTransmitLimit := 3,
137 | TransmitRetries := 3,
138 | StationAddress := 0,
139 | ReplyMessageWait := 5,
140 | PollingMode := 1,
141 | MasterMessageTransmit := 0,
142 | NormalPollNodeFile := ,
143 | NormalPollGroupSize := 0,
144 | PriorityPollNodeFile := ,
145 | ActiveStationFile := ,
146 | SlavePollTimeout := 3000,
147 | EOTSuppression := 0,
148 | MaxStationAddress := 31,
149 | TokenHoldFactor := 1) END_CONFIG
150 |
151 | CONFIG ExtendedDevice END_CONFIG
152 |
153 | CONFIG FaultLog END_CONFIG
154 |
155 | CONFIG FileManager END_CONFIG
156 |
157 | CONFIG ICP END_CONFIG
158 |
159 | CONFIG PCCC END_CONFIG
160 |
161 | CONFIG Redundancy END_CONFIG
162 |
163 | CONFIG SerialPort(BaudRate := 19200,
164 | Parity := No Parity,
165 | DataBits := 8 Bits of Data,
166 | StopBits := 1 Stop Bit,
167 | ComDriverId := DF1,
168 | PendingComDriverId := DF1,
169 | RTSOffDelay := 0,
170 | RTSSendDelay := 0,
171 | ControlLine := No Handshake,
172 | PendingControlLine := No Handshake,
173 | RemoteModeChangeFlag := 0,
174 | PendingRemoteModeChangeFlag := 0,
175 | ModeChangeAttentionChar := 27,
176 | PendingModeChangeAttentionChar := 27,
177 | SystemModeCharacter := 83,
178 | PendingSystemModeCharacter := 83,
179 | UserModeCharacter := 85,
180 | PendingUserModeCharacter := 85) END_CONFIG
181 |
182 | CONFIG UserMemory END_CONFIG
183 |
184 | CONFIG WallClockTime(LocalTimeAdjustment := 0,
185 | TimeZone := 0) END_CONFIG
186 |
187 | END_CONTROLLER
188 |
189 |
--------------------------------------------------------------------------------
/testether_ipApp/edm/test_db.edl:
--------------------------------------------------------------------------------
1 | 4 0 1
2 | beginScreenProperties
3 | major 4
4 | minor 0
5 | release 1
6 | x 1651
7 | y 131
8 | w 1013
9 | h 826
10 | font "helvetica-medium-r-18.0"
11 | ctlFont "helvetica-medium-r-18.0"
12 | btnFont "helvetica-medium-r-18.0"
13 | fgColor index 14
14 | bgColor index 50
15 | textColor index 5
16 | ctlFgColor1 index 0
17 | ctlFgColor2 index 34
18 | ctlBgColor1 index 38
19 | ctlBgColor2 index 17
20 | topShadowColor index 38
21 | botShadowColor index 0
22 | showGrid
23 | snapToGrid
24 | endScreenProperties
25 |
26 | # (Textupdate)
27 | object TextupdateClass
28 | beginObjectProperties
29 | major 10
30 | minor 0
31 | release 0
32 | x 90
33 | y 30
34 | w 60
35 | h 30
36 | controlPv "$(IOC):aiREAL"
37 | fgColor index 15
38 | fgAlarm
39 | bgColor index 10
40 | fill
41 | font "helvetica-medium-r-14.0"
42 | endObjectProperties
43 |
44 | # (X-Y Graph)
45 | object xyGraphClass
46 | beginObjectProperties
47 | major 4
48 | minor 1
49 | release 0
50 | # Geometry
51 | x 110
52 | y 500
53 | w 750
54 | h 270
55 | # Appearance
56 | border
57 | fgColor index 112
58 | bgColor index 133
59 | gridColor index 112
60 | font "helvetica-medium-r-18.0"
61 | # Operating Modes
62 | nPts 1
63 | # X axis properties
64 | showXAxis
65 | xAxisSrc "AutoScale"
66 | xMax 1
67 | # Y axis properties
68 | showYAxis
69 | yAxisSrc "AutoScale"
70 | yMax 1
71 | # Y2 axis properties
72 | y2AxisSrc "AutoScale"
73 | y2Max 1
74 | # Trace Properties
75 | numTraces 2
76 | yPv {
77 | 0 "$(IOC):REALwf"
78 | 1 "$(IOC):DINTLwf"
79 | }
80 | opMode {
81 | 0 "plot"
82 | }
83 | plotColor {
84 | 0 index 21
85 | 1 index 26
86 | }
87 | endObjectProperties
88 |
89 | # (Static Text)
90 | object activeXTextClass
91 | beginObjectProperties
92 | major 4
93 | minor 1
94 | release 0
95 | x 10
96 | y 40
97 | w 37
98 | h 16
99 | font "helvetica-medium-r-14.0"
100 | fontAlign "right"
101 | fgColor index 112
102 | bgColor index 133
103 | useDisplayBg
104 | value {
105 | "REAL"
106 | }
107 | endObjectProperties
108 |
109 | # (Static Text)
110 | object activeXTextClass
111 | beginObjectProperties
112 | major 4
113 | minor 1
114 | release 0
115 | x 10
116 | y 120
117 | w 61
118 | h 16
119 | font "helvetica-medium-r-14.0"
120 | fontAlign "right"
121 | fgColor index 112
122 | bgColor index 133
123 | useDisplayBg
124 | value {
125 | "REALs[5]"
126 | }
127 | endObjectProperties
128 |
129 | # (Textupdate)
130 | object TextupdateClass
131 | beginObjectProperties
132 | major 10
133 | minor 0
134 | release 0
135 | x 90
136 | y 110
137 | w 60
138 | h 30
139 | controlPv "$(IOC):aiREALs5"
140 | fgColor index 15
141 | fgAlarm
142 | bgColor index 10
143 | fill
144 | font "helvetica-medium-r-14.0"
145 | endObjectProperties
146 |
147 | # (Textupdate)
148 | object TextupdateClass
149 | beginObjectProperties
150 | major 10
151 | minor 0
152 | release 0
153 | x 90
154 | y 150
155 | w 60
156 | h 30
157 | controlPv "$(IOC):aiREALs39"
158 | fgColor index 15
159 | fgAlarm
160 | bgColor index 10
161 | fill
162 | font "helvetica-medium-r-14.0"
163 | endObjectProperties
164 |
165 | # (Static Text)
166 | object activeXTextClass
167 | beginObjectProperties
168 | major 4
169 | minor 1
170 | release 0
171 | x 10
172 | y 160
173 | w 70
174 | h 20
175 | font "helvetica-medium-r-14.0"
176 | fontAlign "right"
177 | fgColor index 112
178 | bgColor index 133
179 | useDisplayBg
180 | value {
181 | "REALs[39]"
182 | }
183 | endObjectProperties
184 |
185 | # (Textupdate)
186 | object TextupdateClass
187 | beginObjectProperties
188 | major 10
189 | minor 0
190 | release 0
191 | x 90
192 | y 230
193 | w 60
194 | h 30
195 | controlPv "$(IOC):aiDINTs1"
196 | fgColor index 15
197 | fgAlarm
198 | bgColor index 10
199 | fill
200 | font "helvetica-medium-r-14.0"
201 | endObjectProperties
202 |
203 | # (Static Text)
204 | object activeXTextClass
205 | beginObjectProperties
206 | major 4
207 | minor 1
208 | release 0
209 | x 10
210 | y 200
211 | w 34
212 | h 16
213 | font "helvetica-medium-r-14.0"
214 | fontAlign "right"
215 | fgColor index 112
216 | bgColor index 133
217 | useDisplayBg
218 | value {
219 | "DINT"
220 | }
221 | autoSize
222 | endObjectProperties
223 |
224 | # (Static Text)
225 | object activeXTextClass
226 | beginObjectProperties
227 | major 4
228 | minor 1
229 | release 0
230 | x 10
231 | y 400
232 | w 61
233 | h 16
234 | font "helvetica-medium-r-14.0"
235 | fontAlign "right"
236 | fgColor index 112
237 | bgColor index 133
238 | useDisplayBg
239 | value {
240 | "INTs[3]"
241 | }
242 | endObjectProperties
243 |
244 | # (Textupdate)
245 | object TextupdateClass
246 | beginObjectProperties
247 | major 10
248 | minor 0
249 | release 0
250 | x 90
251 | y 390
252 | w 60
253 | h 30
254 | controlPv "$(IOC):aiINTs3"
255 | fgColor index 15
256 | fgAlarm
257 | bgColor index 10
258 | fill
259 | font "helvetica-medium-r-14.0"
260 | endObjectProperties
261 |
262 | # (Textentry)
263 | object TextentryClass
264 | beginObjectProperties
265 | major 10
266 | minor 0
267 | release 0
268 | x 160
269 | y 70
270 | w 70
271 | h 40
272 | controlPv "$(IOC):aoREALs2"
273 | fgColor index 25
274 | fgAlarm
275 | bgColor index 5
276 | fill
277 | font "helvetica-medium-r-14.0"
278 | endObjectProperties
279 |
280 | # (Textentry)
281 | object TextentryClass
282 | beginObjectProperties
283 | major 10
284 | minor 0
285 | release 0
286 | x 160
287 | y 270
288 | w 70
289 | h 40
290 | controlPv "$(IOC):aoDINTs2"
291 | fgColor index 25
292 | fgAlarm
293 | bgColor index 5
294 | fill
295 | font "helvetica-medium-r-14.0"
296 | endObjectProperties
297 |
298 | # (Static Text)
299 | object activeXTextClass
300 | beginObjectProperties
301 | major 4
302 | minor 1
303 | release 0
304 | x 730
305 | y 770
306 | w 70
307 | h 20
308 | font "helvetica-medium-r-14.0"
309 | fontAlign "right"
310 | fgColor index 126
311 | bgColor index 133
312 | useDisplayBg
313 | value {
314 | "REALs"
315 | }
316 | endObjectProperties
317 |
318 | # (Static Text)
319 | object activeXTextClass
320 | beginObjectProperties
321 | major 4
322 | minor 1
323 | release 0
324 | x 810
325 | y 770
326 | w 50
327 | h 20
328 | font "helvetica-medium-r-14.0"
329 | fgColor index 130
330 | bgColor index 133
331 | useDisplayBg
332 | value {
333 | "DINTs"
334 | }
335 | endObjectProperties
336 |
337 | # (Textupdate)
338 | object TextupdateClass
339 | beginObjectProperties
340 | major 10
341 | minor 0
342 | release 0
343 | x 330
344 | y 30
345 | w 80
346 | h 30
347 | controlPv "$(IOC):biBOOL"
348 | fgColor index 15
349 | fgAlarm
350 | bgColor index 10
351 | fill
352 | font "helvetica-medium-r-14.0"
353 | endObjectProperties
354 |
355 | # (Static Text)
356 | object activeXTextClass
357 | beginObjectProperties
358 | major 4
359 | minor 1
360 | release 0
361 | x 260
362 | y 40
363 | w 57
364 | h 16
365 | font "helvetica-medium-r-14.0"
366 | fontAlign "right"
367 | fgColor index 112
368 | bgColor index 133
369 | useDisplayBg
370 | value {
371 | "bi, BOOL"
372 | }
373 | autoSize
374 | endObjectProperties
375 |
376 | # (Static Text)
377 | object activeXTextClass
378 | beginObjectProperties
379 | major 4
380 | minor 1
381 | release 0
382 | x 10
383 | y 10
384 | w 77
385 | h 16
386 | font "helvetica-bold-r-14.0"
387 | fgColor index 112
388 | bgColor index 133
389 | useDisplayBg
390 | value {
391 | "AI Records"
392 | }
393 | autoSize
394 | endObjectProperties
395 |
396 | # (Static Text)
397 | object activeXTextClass
398 | beginObjectProperties
399 | major 4
400 | minor 1
401 | release 0
402 | x 260
403 | y 10
404 | w 108
405 | h 16
406 | font "helvetica-bold-r-14.0"
407 | fgColor index 112
408 | bgColor index 133
409 | useDisplayBg
410 | value {
411 | "Binary Records"
412 | }
413 | autoSize
414 | endObjectProperties
415 |
416 | # (Textupdate)
417 | object TextupdateClass
418 | beginObjectProperties
419 | major 10
420 | minor 0
421 | release 0
422 | x 330
423 | y 70
424 | w 80
425 | h 30
426 | controlPv "$(IOC):biDINT"
427 | fgColor index 15
428 | fgAlarm
429 | bgColor index 10
430 | fill
431 | font "helvetica-medium-r-14.0"
432 | endObjectProperties
433 |
434 | # (Static Text)
435 | object activeXTextClass
436 | beginObjectProperties
437 | major 4
438 | minor 1
439 | release 0
440 | x 260
441 | y 80
442 | w 34
443 | h 16
444 | font "helvetica-medium-r-14.0"
445 | fontAlign "right"
446 | fgColor index 112
447 | bgColor index 133
448 | useDisplayBg
449 | value {
450 | "DINT"
451 | }
452 | autoSize
453 | endObjectProperties
454 |
455 | # (Static Text)
456 | object activeXTextClass
457 | beginObjectProperties
458 | major 4
459 | minor 1
460 | release 0
461 | x 260
462 | y 160
463 | w 63
464 | h 16
465 | font "helvetica-medium-r-14.0"
466 | fontAlign "right"
467 | fgColor index 112
468 | bgColor index 133
469 | useDisplayBg
470 | value {
471 | "BOOLs[5]"
472 | }
473 | autoSize
474 | endObjectProperties
475 |
476 | # (Textupdate)
477 | object TextupdateClass
478 | beginObjectProperties
479 | major 10
480 | minor 0
481 | release 0
482 | x 330
483 | y 150
484 | w 80
485 | h 30
486 | controlPv "$(IOC):biBOOLs5"
487 | fgColor index 15
488 | fgAlarm
489 | bgColor index 10
490 | fill
491 | font "helvetica-medium-r-14.0"
492 | endObjectProperties
493 |
494 | # (Textupdate)
495 | object TextupdateClass
496 | beginObjectProperties
497 | major 10
498 | minor 0
499 | release 0
500 | x 360
501 | y 340
502 | w 134
503 | h 30
504 | controlPv "$(IOC):mbbiBOOLs300"
505 | fgColor index 15
506 | fgAlarm
507 | bgColor index 10
508 | fill
509 | font "helvetica-medium-r-14.0"
510 | endObjectProperties
511 |
512 | # (Static Text)
513 | object activeXTextClass
514 | beginObjectProperties
515 | major 4
516 | minor 1
517 | release 0
518 | x 260
519 | y 340
520 | w 90
521 | h 40
522 | font "helvetica-medium-r-14.0"
523 | fontAlign "right"
524 | fgColor index 112
525 | bgColor index 133
526 | useDisplayBg
527 | value {
528 | "BOOLs[300], "
529 | "2 bits"
530 | }
531 | endObjectProperties
532 |
533 | # (Radio Box)
534 | object activeRadioButtonClass
535 | beginObjectProperties
536 | major 4
537 | minor 0
538 | release 0
539 | x 540
540 | y 300
541 | w 110
542 | h 120
543 | fgColor index 112
544 | bgColor index 50
545 | buttonColor index 133
546 | selectColor index 133
547 | topShadowColor index 107
548 | botShadowColor index 109
549 | controlPv "$(IOC):mbboBOOLs300"
550 | font "helvetica-medium-r-14.0"
551 | endObjectProperties
552 |
553 | # (Textupdate)
554 | object TextupdateClass
555 | beginObjectProperties
556 | major 10
557 | minor 0
558 | release 0
559 | x 820
560 | y 330
561 | w 134
562 | h 30
563 | controlPv "$(IOC):biDINTs8_5"
564 | fgColor index 15
565 | fgAlarm
566 | bgColor index 10
567 | fill
568 | font "helvetica-medium-r-14.0"
569 | endObjectProperties
570 |
571 | # (Static Text)
572 | object activeXTextClass
573 | beginObjectProperties
574 | major 4
575 | minor 1
576 | release 0
577 | x 720
578 | y 340
579 | w 90
580 | h 20
581 | font "helvetica-medium-r-14.0"
582 | fontAlign "right"
583 | fgColor index 112
584 | bgColor index 133
585 | useDisplayBg
586 | value {
587 | "DINTs[8].5"
588 | }
589 | endObjectProperties
590 |
591 | # (Static Text)
592 | object activeXTextClass
593 | beginObjectProperties
594 | major 4
595 | minor 1
596 | release 0
597 | x 720
598 | y 380
599 | w 90
600 | h 40
601 | font "helvetica-medium-r-14.0"
602 | fontAlign "right"
603 | fgColor index 112
604 | bgColor index 133
605 | useDisplayBg
606 | value {
607 | "INTs[2],"
608 | "bits 15&14"
609 | }
610 | endObjectProperties
611 |
612 | # (Menu Button)
613 | object activeMenuButtonClass
614 | beginObjectProperties
615 | major 4
616 | minor 0
617 | release 0
618 | x 820
619 | y 380
620 | w 130
621 | h 30
622 | fgColor index 25
623 | bgColor index 5
624 | inconsistentColor index 20
625 | topShadowColor index 107
626 | botShadowColor index 109
627 | controlPv "$(IOC):mbboINTs2_14"
628 | font "helvetica-medium-r-14.0"
629 | endObjectProperties
630 |
631 | # (Static Text)
632 | object activeXTextClass
633 | beginObjectProperties
634 | major 4
635 | minor 1
636 | release 0
637 | x 80
638 | y 470
639 | w 61
640 | h 16
641 | font "helvetica-medium-r-14.0"
642 | fontAlign "right"
643 | fgColor index 112
644 | bgColor index 133
645 | useDisplayBg
646 | value {
647 | "STRING"
648 | }
649 | endObjectProperties
650 |
651 | # (Textupdate)
652 | object TextupdateClass
653 | beginObjectProperties
654 | major 10
655 | minor 0
656 | release 0
657 | x 150
658 | y 460
659 | w 134
660 | h 30
661 | controlPv "$(IOC):string"
662 | fgColor index 15
663 | fgAlarm
664 | bgColor index 10
665 | fill
666 | font "helvetica-medium-r-14.0"
667 | endObjectProperties
668 |
669 | # (Static Text)
670 | object activeXTextClass
671 | beginObjectProperties
672 | major 4
673 | minor 1
674 | release 0
675 | x 70
676 | y 440
677 | w 160
678 | h 20
679 | font "helvetica-bold-r-14.0"
680 | fgColor index 112
681 | bgColor index 133
682 | useDisplayBg
683 | value {
684 | "Other Records"
685 | }
686 | endObjectProperties
687 |
688 | # (Static Text)
689 | object activeXTextClass
690 | beginObjectProperties
691 | major 4
692 | minor 1
693 | release 0
694 | x 160
695 | y 10
696 | w 85
697 | h 16
698 | font "helvetica-bold-r-14.0"
699 | fgColor index 112
700 | bgColor index 133
701 | useDisplayBg
702 | value {
703 | "AO Records"
704 | }
705 | autoSize
706 | endObjectProperties
707 |
708 | # (Textentry)
709 | object TextentryClass
710 | beginObjectProperties
711 | major 10
712 | minor 0
713 | release 0
714 | x 160
715 | y 30
716 | w 70
717 | h 40
718 | controlPv "$(IOC):aoREAL"
719 | fgColor index 25
720 | fgAlarm
721 | bgColor index 5
722 | fill
723 | font "helvetica-medium-r-14.0"
724 | endObjectProperties
725 |
726 | # (Textupdate)
727 | object TextupdateClass
728 | beginObjectProperties
729 | major 10
730 | minor 0
731 | release 0
732 | x 90
733 | y 70
734 | w 60
735 | h 30
736 | controlPv "$(IOC):aiREALs2"
737 | fgColor index 15
738 | fgAlarm
739 | bgColor index 10
740 | fill
741 | font "helvetica-medium-r-14.0"
742 | endObjectProperties
743 |
744 | # (Static Text)
745 | object activeXTextClass
746 | beginObjectProperties
747 | major 4
748 | minor 1
749 | release 0
750 | x 10
751 | y 80
752 | w 61
753 | h 16
754 | font "helvetica-medium-r-14.0"
755 | fontAlign "right"
756 | fgColor index 112
757 | bgColor index 133
758 | useDisplayBg
759 | value {
760 | "REALs[2]"
761 | }
762 | endObjectProperties
763 |
764 | # (Textupdate)
765 | object TextupdateClass
766 | beginObjectProperties
767 | major 10
768 | minor 0
769 | release 0
770 | x 90
771 | y 190
772 | w 60
773 | h 30
774 | controlPv "$(IOC):aiDINT"
775 | fgColor index 15
776 | fgAlarm
777 | bgColor index 10
778 | fill
779 | font "helvetica-medium-r-14.0"
780 | endObjectProperties
781 |
782 | # (Static Text)
783 | object activeXTextClass
784 | beginObjectProperties
785 | major 4
786 | minor 1
787 | release 0
788 | x 10
789 | y 240
790 | w 50
791 | h 16
792 | font "helvetica-medium-r-14.0"
793 | fontAlign "right"
794 | fgColor index 112
795 | bgColor index 133
796 | useDisplayBg
797 | value {
798 | "DINTs1"
799 | }
800 | autoSize
801 | endObjectProperties
802 |
803 | # (Static Text)
804 | object activeXTextClass
805 | beginObjectProperties
806 | major 4
807 | minor 1
808 | release 0
809 | x 10
810 | y 280
811 | w 50
812 | h 16
813 | font "helvetica-medium-r-14.0"
814 | fontAlign "right"
815 | fgColor index 112
816 | bgColor index 133
817 | useDisplayBg
818 | value {
819 | "DINTs2"
820 | }
821 | autoSize
822 | endObjectProperties
823 |
824 | # (Static Text)
825 | object activeXTextClass
826 | beginObjectProperties
827 | major 4
828 | minor 1
829 | release 0
830 | x 10
831 | y 320
832 | w 50
833 | h 16
834 | font "helvetica-medium-r-14.0"
835 | fontAlign "right"
836 | fgColor index 112
837 | bgColor index 133
838 | useDisplayBg
839 | value {
840 | "DINTs3"
841 | }
842 | autoSize
843 | endObjectProperties
844 |
845 | # (Textupdate)
846 | object TextupdateClass
847 | beginObjectProperties
848 | major 10
849 | minor 0
850 | release 0
851 | x 90
852 | y 270
853 | w 60
854 | h 30
855 | controlPv "$(IOC):aiDINTs2"
856 | fgColor index 15
857 | fgAlarm
858 | bgColor index 10
859 | fill
860 | font "helvetica-medium-r-14.0"
861 | endObjectProperties
862 |
863 | # (Textupdate)
864 | object TextupdateClass
865 | beginObjectProperties
866 | major 10
867 | minor 0
868 | release 0
869 | x 90
870 | y 310
871 | w 60
872 | h 30
873 | controlPv "$(IOC):aiDINTs3"
874 | fgColor index 15
875 | fgAlarm
876 | bgColor index 10
877 | fill
878 | font "helvetica-medium-r-14.0"
879 | endObjectProperties
880 |
881 | # (Textentry)
882 | object TextentryClass
883 | beginObjectProperties
884 | major 10
885 | minor 0
886 | release 0
887 | x 160
888 | y 190
889 | w 70
890 | h 40
891 | controlPv "$(IOC):aoDINT"
892 | fgColor index 25
893 | fgAlarm
894 | bgColor index 5
895 | fill
896 | font "helvetica-medium-r-14.0"
897 | endObjectProperties
898 |
899 | # (Textentry)
900 | object TextentryClass
901 | beginObjectProperties
902 | major 10
903 | minor 0
904 | release 0
905 | x 160
906 | y 390
907 | w 70
908 | h 40
909 | controlPv "$(IOC):aoINTs3"
910 | fgColor index 25
911 | fgAlarm
912 | bgColor index 5
913 | fill
914 | font "helvetica-medium-r-14.0"
915 | endObjectProperties
916 |
917 | # (Button)
918 | object activeButtonClass
919 | beginObjectProperties
920 | major 4
921 | minor 0
922 | release 0
923 | x 420
924 | y 30
925 | w 80
926 | h 30
927 | fgColor index 25
928 | onColor index 5
929 | offColor index 5
930 | inconsistentColor index 17
931 | topShadowColor index 107
932 | botShadowColor index 109
933 | controlPv "$(IOC):boBOOL"
934 | labelType "pvState"
935 | 3d
936 | font "helvetica-medium-r-12.0"
937 | objType "controls"
938 | endObjectProperties
939 |
940 | # (Textupdate)
941 | object TextupdateClass
942 | beginObjectProperties
943 | major 10
944 | minor 0
945 | release 0
946 | x 330
947 | y 110
948 | w 80
949 | h 30
950 | controlPv "$(IOC):biDINT_3"
951 | fgColor index 15
952 | fgAlarm
953 | bgColor index 10
954 | fill
955 | font "helvetica-medium-r-14.0"
956 | endObjectProperties
957 |
958 | # (Static Text)
959 | object activeXTextClass
960 | beginObjectProperties
961 | major 4
962 | minor 1
963 | release 0
964 | x 260
965 | y 120
966 | w 45
967 | h 16
968 | font "helvetica-medium-r-14.0"
969 | fontAlign "right"
970 | fgColor index 112
971 | bgColor index 133
972 | useDisplayBg
973 | value {
974 | "DINT.3"
975 | }
976 | autoSize
977 | endObjectProperties
978 |
979 | # (Button)
980 | object activeButtonClass
981 | beginObjectProperties
982 | major 4
983 | minor 0
984 | release 0
985 | x 420
986 | y 150
987 | w 80
988 | h 30
989 | fgColor index 25
990 | onColor index 5
991 | offColor index 5
992 | inconsistentColor index 17
993 | topShadowColor index 107
994 | botShadowColor index 109
995 | controlPv "$(IOC):boBOOLs5"
996 | labelType "pvState"
997 | 3d
998 | font "helvetica-medium-r-12.0"
999 | objType "controls"
1000 | endObjectProperties
1001 |
1002 | # (Static Text)
1003 | object activeXTextClass
1004 | beginObjectProperties
1005 | major 4
1006 | minor 1
1007 | release 0
1008 | x 260
1009 | y 320
1010 | w 175
1011 | h 16
1012 | font "helvetica-bold-r-14.0"
1013 | fgColor index 112
1014 | bgColor index 133
1015 | useDisplayBg
1016 | value {
1017 | "Multi-Bit Binary Records"
1018 | }
1019 | autoSize
1020 | endObjectProperties
1021 |
1022 | # (Textupdate)
1023 | object TextupdateClass
1024 | beginObjectProperties
1025 | major 10
1026 | minor 0
1027 | release 0
1028 | x 360
1029 | y 380
1030 | w 134
1031 | h 30
1032 | controlPv "$(IOC):mbbiDINTs2_3"
1033 | fgColor index 15
1034 | fgAlarm
1035 | bgColor index 10
1036 | fill
1037 | font "helvetica-medium-r-14.0"
1038 | endObjectProperties
1039 |
1040 | # (Static Text)
1041 | object activeXTextClass
1042 | beginObjectProperties
1043 | major 4
1044 | minor 1
1045 | release 0
1046 | x 260
1047 | y 380
1048 | w 90
1049 | h 40
1050 | font "helvetica-medium-r-14.0"
1051 | fontAlign "right"
1052 | fgColor index 112
1053 | bgColor index 133
1054 | useDisplayBg
1055 | value {
1056 | "DINTs[2].3 "
1057 | "2 bits"
1058 | }
1059 | endObjectProperties
1060 |
1061 | # (Lines)
1062 | object activeLineClass
1063 | beginObjectProperties
1064 | major 4
1065 | minor 0
1066 | release 0
1067 | x 500
1068 | y 360
1069 | w 30
1070 | h 0
1071 | lineColor index 112
1072 | fillColor index 133
1073 | lineWidth 2
1074 | arrows "from"
1075 | numPoints 2
1076 | xPoints {
1077 | 0 500
1078 | 1 530
1079 | }
1080 | yPoints {
1081 | 0 360
1082 | 1 360
1083 | }
1084 | endObjectProperties
1085 |
1086 | # (Textupdate)
1087 | object TextupdateClass
1088 | beginObjectProperties
1089 | major 10
1090 | minor 0
1091 | release 0
1092 | x 330
1093 | y 190
1094 | w 80
1095 | h 30
1096 | controlPv "$(IOC):biDINTs40_error"
1097 | fgColor index 15
1098 | fgAlarm
1099 | bgColor index 10
1100 | fill
1101 | font "helvetica-medium-r-14.0"
1102 | endObjectProperties
1103 |
1104 | # (Static Text)
1105 | object activeXTextClass
1106 | beginObjectProperties
1107 | major 4
1108 | minor 1
1109 | release 0
1110 | x 250
1111 | y 200
1112 | w 69
1113 | h 16
1114 | font "helvetica-medium-r-14.0"
1115 | fontAlign "right"
1116 | fgColor index 112
1117 | bgColor index 133
1118 | useDisplayBg
1119 | value {
1120 | "DINTs[1].8"
1121 | }
1122 | autoSize
1123 | endObjectProperties
1124 |
1125 | # (Textupdate)
1126 | object TextupdateClass
1127 | beginObjectProperties
1128 | major 10
1129 | minor 0
1130 | release 0
1131 | x 330
1132 | y 230
1133 | w 80
1134 | h 30
1135 | controlPv "$(IOC):biDINTs8_5"
1136 | fgColor index 15
1137 | fgAlarm
1138 | bgColor index 10
1139 | fill
1140 | font "helvetica-medium-r-14.0"
1141 | endObjectProperties
1142 |
1143 | # (Static Text)
1144 | object activeXTextClass
1145 | beginObjectProperties
1146 | major 4
1147 | minor 1
1148 | release 0
1149 | x 250
1150 | y 240
1151 | w 69
1152 | h 16
1153 | font "helvetica-medium-r-14.0"
1154 | fontAlign "right"
1155 | fgColor index 112
1156 | bgColor index 133
1157 | useDisplayBg
1158 | value {
1159 | "DINTs[8].5"
1160 | }
1161 | autoSize
1162 | endObjectProperties
1163 |
1164 | # (Button)
1165 | object activeButtonClass
1166 | beginObjectProperties
1167 | major 4
1168 | minor 0
1169 | release 0
1170 | x 420
1171 | y 270
1172 | w 80
1173 | h 30
1174 | fgColor index 25
1175 | onColor index 5
1176 | offColor index 5
1177 | inconsistentColor index 17
1178 | topShadowColor index 107
1179 | botShadowColor index 109
1180 | controlPv "$(IOC):boINTs3_2"
1181 | labelType "pvState"
1182 | 3d
1183 | font "helvetica-medium-r-12.0"
1184 | objType "controls"
1185 | endObjectProperties
1186 |
1187 | # (Static Text)
1188 | object activeXTextClass
1189 | beginObjectProperties
1190 | major 4
1191 | minor 1
1192 | release 0
1193 | x 350
1194 | y 280
1195 | w 59
1196 | h 16
1197 | font "helvetica-medium-r-14.0"
1198 | fontAlign "right"
1199 | fgColor index 112
1200 | bgColor index 133
1201 | useDisplayBg
1202 | value {
1203 | "INTs[3].2"
1204 | }
1205 | autoSize
1206 | endObjectProperties
1207 |
1208 | # (Textupdate)
1209 | object TextupdateClass
1210 | beginObjectProperties
1211 | major 10
1212 | minor 0
1213 | release 0
1214 | x 90
1215 | y 350
1216 | w 60
1217 | h 30
1218 | controlPv "$(IOC):aiINTs2"
1219 | fgColor index 15
1220 | fgAlarm
1221 | bgColor index 10
1222 | fill
1223 | font "helvetica-medium-r-14.0"
1224 | endObjectProperties
1225 |
1226 | # (Static Text)
1227 | object activeXTextClass
1228 | beginObjectProperties
1229 | major 4
1230 | minor 1
1231 | release 0
1232 | x 10
1233 | y 360
1234 | w 61
1235 | h 16
1236 | font "helvetica-medium-r-14.0"
1237 | fontAlign "right"
1238 | fgColor index 112
1239 | bgColor index 133
1240 | useDisplayBg
1241 | value {
1242 | "INTs[2]"
1243 | }
1244 | endObjectProperties
1245 |
1246 |
--------------------------------------------------------------------------------
/testether_ipApp/opi/EtherIPStats.bob:
--------------------------------------------------------------------------------
1 |
2 |
3 | Display
4 |
5 | Label
6 | TITLE
7 | Ether IP Stats
8 | 0
9 | 0
10 | 550
11 | 31
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | true
21 |
22 |
23 | Label_1
24 | PLC Errors:
25 | 50
26 |
27 |
28 | Text Update
29 | $(S=test):PLC_ERRORS
30 | 110
31 | 50
32 |
33 |
34 | Label_3
35 | List Scan Time:
36 | 80
37 |
38 |
39 | Text Update_1
40 | $(S=test):LIST_SCAN_TIME
41 | 110
42 | 80
43 |
44 |
45 | Label_4
46 | Min. Scan Time:
47 | 110
48 | 110
49 |
50 |
51 | Text Update_2
52 | $(S=test):LIST_MIN_SCAN_TIME
53 | 110
54 | 110
55 |
56 |
57 | Label_5
58 | Max Scan Time:
59 | 140
60 | 110
61 |
62 |
63 | Text Update_3
64 | $(S=test):LIST_MAX_SCAN_TIME
65 | 110
66 | 140
67 |
68 |
69 | Label_6
70 | Slow Transfers:
71 | 170
72 | 110
73 |
74 |
75 | Text Update_4
76 | $(S=test):PLC_TASK_SLOW
77 | 110
78 | 170
79 |
80 |
81 | Boolean Button
82 | $(S=test):RESET_PLC_STATS
83 | 110
84 | 200
85 | 90
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | false
95 | true
96 | 1
97 |
98 |
99 |
--------------------------------------------------------------------------------
/testether_ipApp/src/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile
2 | TOP = ../..
3 |
4 | include $(TOP)/configure/CONFIG
5 | #----------------------------------------
6 | # ADD MACRO DEFINITIONS AFTER THIS LINE
7 |
8 | # Since base 3_15, on Linux 64 and Mac, support LINT
9 | ifdef BASE_3_15
10 | ifeq ($(EPICS_HOST_ARCH),linux-x86_64)
11 | USR_CFLAGS += -DSUPPORT_LINT
12 | USR_CPPFLAGS += -DSUPPORT_LINT
13 | else ifeq ($(EPICS_HOST_ARCH),darwin-x86)
14 | USR_CFLAGS += -DSUPPORT_LINT
15 | USR_CPPFLAGS += -DSUPPORT_LINT
16 | else ifeq ($(EPICS_HOST_ARCH),darwin-aarch64)
17 | USR_CFLAGS += -DSUPPORT_LINT
18 | USR_CPPFLAGS += -DSUPPORT_LINT
19 | endif
20 | endif
21 |
22 | # .dbd will be created from Include.dbd
23 | DBD += eipIoc.dbd
24 |
25 | eipIoc_DBD += base.dbd
26 | eipIoc_DBD += ether_ip.dbd
27 |
28 | # Hard-code location of DBD in product
29 | FINAL_LOCATION = $(shell $(PERL) $(TOOLS)/fullPathName.pl $(INSTALL_LOCATION))
30 | EIP_DBD = $(FINAL_LOCATION)/dbd/eipIoc.dbd
31 | USR_CPPFLAGS += -DEIP_DBD=\"$(EIP_DBD)\"
32 |
33 | PROD_IOC = eipIoc
34 |
35 | # _registerRecordDeviceDriver.cpp will be created from .dbd
36 | eipIoc_SRCS += eipIoc_registerRecordDeviceDriver.cpp
37 | eipIoc_SRCS_DEFAULT += eipIocMain.cpp
38 | eipIoc_SRCS_vxWorks += -nil-
39 |
40 | USR_CXXFLAGS += -DUSE_TYPED_RSET
41 |
42 | eipIoc_LIBS += ether_ip
43 |
44 | # Add PVA if available
45 | ifdef EPICS_QSRV_MAJOR_VERSION
46 | eipIoc_DBD += PVAServerRegister.dbd
47 | eipIoc_DBD += qsrv.dbd
48 | eipIoc_LIBS += qsrv
49 | eipIoc_LIBS += $(EPICS_BASE_PVA_CORE_LIBS)
50 | endif
51 |
52 | ether_ip_DIR = $(INSTALL_LIB)
53 |
54 | eipIoc_LIBS += $(EPICS_BASE_IOC_LIBS)
55 |
56 | include $(TOP)/configure/RULES
57 |
--------------------------------------------------------------------------------
/testether_ipApp/src/eipIocMain.cpp:
--------------------------------------------------------------------------------
1 | /* eipIocMain.cpp
2 | * kasemirk@ornl.gov
3 | */
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | #include "drvEtherIP.h"
21 |
22 | #ifndef EIP_DBD
23 | #error This needs to be compiled with -DEIP_DBD=/path/to/installed/eip.dbd
24 | #endif
25 |
26 | extern "C"
27 | {
28 | extern void eipIoc_registerRecordDeviceDriver(struct dbBase *);
29 | }
30 |
31 | static void usage()
32 | {
33 | printf("Usage:\n");
34 | printf(" eipIoc st.cmd\n");
35 | printf("or\n");
36 | printf(" eipIoc -p Plc1=IP,slot [-m macro=value] -d database.db [-d another.db]\n");
37 | printf("\n");
38 | printf("In the first case, this program acts as an ordinary IOC, executing a startup file\n");
39 | printf("\n");
40 | printf("The second invocation is for a command-line mode similar to the 'softIoc' from EPICS base,\n");
41 | printf("extended with options to communicate via etherIp.\n");
42 | }
43 |
44 | static bool definePlc(const char *def)
45 | {
46 | // Create modifyable copy
47 | char *copy = strdup(def);
48 |
49 | // Optional slot in "Plc1=IP,slot"
50 | int slot = 0;
51 | char *c = strrchr(copy, ',');
52 | if (c)
53 | {
54 | slot = atoi(c+1);
55 | *c = '\0';
56 | }
57 |
58 | // Split "Plc1=IP" at '='
59 | c = strrchr(copy, '=');
60 | if (! c)
61 | {
62 | free(copy);
63 | fprintf(stderr, "Missing '=' in PLC definition '%s'\n", def);
64 | return false;
65 | }
66 | *c = '\0';
67 | const char *plc = copy;
68 | const char *ip = c+1;
69 |
70 | printf("drvEtherIP_define_PLC(\"%s\", \"%s\", %d);\n", plc, ip, slot);
71 | drvEtherIP_define_PLC(plc, ip, slot);
72 | free(copy);
73 |
74 | return true;
75 | }
76 |
77 | int main(int argc,char *argv[])
78 | {
79 | const char *dbd_file = EIP_DBD;
80 | char *macros = strdup("");
81 |
82 | if (argc == 1)
83 | {
84 | usage();
85 | return 0;
86 | }
87 | else if (argc == 2 && argv[1][0] != '-')
88 | {
89 | iocsh(argv[1]);
90 | epicsThreadSleep(.2);
91 | }
92 | else
93 | {
94 | printf("# Command-line mode\n");
95 | printf("#\n");
96 | printf("# The following commands are executed from cmdline options\n");
97 | printf("\n");
98 | printf("dbLoadDatabase(\"%s\")\n", dbd_file);
99 | dbLoadDatabase((char *)dbd_file, NULL, NULL);
100 |
101 | printf("eipIoc_registerRecordDeviceDriver(pdbbase)\n");
102 | eipIoc_registerRecordDeviceDriver(pdbbase);
103 | printf("drvEtherIP_init()\n");
104 | drvEtherIP_init();
105 |
106 | int ch;
107 | while ( (ch = getopt(argc, argv, "p:m:d:h")) != -1)
108 | {
109 | switch (ch)
110 | {
111 | case 'h':
112 | usage();
113 | return 0;
114 | case 'p':
115 | if (! definePlc(optarg))
116 | return -2;
117 | break;
118 | case 'm':
119 | free(macros);
120 | macros = strdup(optarg);
121 | break;
122 | case 'd':
123 | printf("dbLoadRecords(\"%s\", \"%s\");\n", optarg, macros);
124 | dbLoadRecords(optarg, macros);
125 | break;
126 | default:
127 | usage();
128 | return -1;
129 | }
130 | }
131 | printf("iocInit()\n");
132 |
133 | printf("\n");
134 | printf("#\n");
135 | printf("# End of command-line options, entering IOC shell\n");
136 | printf("#\n");
137 | printf("\n");
138 |
139 | iocInit();
140 | epicsThreadSleep(0.5);
141 | }
142 |
143 | iocsh(NULL);
144 |
145 | return 0;
146 | }
147 |
--------------------------------------------------------------------------------