Giter Site home page Giter Site logo

ads-ioc's Introduction

ADS IOC

ads-ioc is an IOC template for Beckhoff TwinCAT ADS-based deployments in the LCLS PCDS group at SLAC.

That fork contains support for communicating with specifically structured TwinCAT projects using the ADS protocol.

This is set up to build on the LCLS PCDS NFS-accessible machines. This will not build on older operating systems such as rhel5 and rhel6. It does not need any specific environment variable set, just type make. You can probably get it to build in other environments by modifying the RELEASE_SITE file appropriately.

Dependencies

Logging

Logging configuration is handled externally by way of the shared pre_linux.cmd (i.e., pre-iocInit) script:

# Send log messages to logstash:
epicsEnvSet("EPICS_IOC_LOG_INET", "ctl-logsrv01.pcdsn")
epicsEnvSet("EPICS_IOC_LOG_PORT", "7004")

# The following prefix is *required* for logstash to know which IOC is sending
# the message.  This *cannot* be modified without changes to the logstash
# configuration.
iocLogPrefix("IOC=${IOC} ")

# Send caPutLog messages to logstash:
epicsEnvSet("EPICS_CAPUTLOG_HOST", "ctl-logsrv01.pcdsn")
epicsEnvSet("EPICS_CAPUTLOG_PORT", "7011")

For now, post-init settings are handled on a per-IOC basis. However, a similar change may be used in the future for a post-iocInit() script which would enable logging outside of ads-ioc:

# Enable logging
iocLogInit()

# Configure and start the caPutLogger after iocInit
epicsEnvSet(EPICS_AS_PUT_LOG_PV, "${IOC}:caPutLog:Last")

# caPutLogInit("HOST:PORT", config)
# config options:
#       caPutLogNone       -1: no logging (disable)
#       caPutLogOnChange    0: log only on value change
#       caPutLogAll         1: log all puts
#       caPutLogAllNoFilter 2: log all puts no filtering on same PV
caPutLogInit("${EPICS_CAPUTLOG_HOST}:${EPICS_CAPUTLOG_PORT}", 0)

Related tools

ads-ioc's People

Contributors

ghalym avatar klauer avatar mcb64 avatar zllentz avatar zrylettc avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

ads-ioc's Issues

`make` control function "error" is nice for users but breaks introspection of dependencies

Lines such as this that employ the "control function" error defined by GNU make:

$(error Invalid EPICS_BASE: $(EPICS_BASE)/include)

Are useful for debugging when trying to build ads-ioc and having a missing dependency.
However, it breaks introspection of dependencies via tools such as whatrecord deps (or epics-sumo, presumably) if dependencies are missing.

I think it may be useful to introduce a convention wherein:

  • DEPENDENCY_CHECKER gets set to 1 by tools like whatrecord (ร  la typing.TYPE_CHECKING)
  • If unset (DEPENDENCY_CHECKER=0), $(error) get called as usual
  • If set (DEPENDENCY_CHECKER=1), either no output or some warning text could take place of $(error):
    • Warnings could be picked up by the tool or dropped

This could look like:

_DEPENDENCY_CHECKER ?= 0

ifneq ($(_DEPENDENCY_CHECKER),1)

# Check for valid EPICS_BASE
ifeq ($(wildcard $(EPICS_BASE)/include),)
$(error Invalid EPICS_BASE: $(EPICS_BASE)/include)
endif

endif

Add alternative method for specifying PLC IP address

Goal

  • Allow a PLC to be relocated to a different hutch with a change of IP address via netconfig
  • Do not require the AMS Net ID of the PLC to be reconfigured for this move

st.cmd location

epicsEnvSet("IPADDR", "{{plc_ip}}")

pytmc source

We still don't have a way to get the PLC hostname directly from the project. All that's stored is the AMS Net ID in the project, from which we guess the IP:

https://github.com/pcdshub/pytmc/blob/233acfb6da27162d34db8de7658684d203a4caad/pytmc/parser.py#L510-L518

Options

An override?

Add an override to pytmc stcmd for the IP address:

# IOC Makefile
PLC_IP_ADDRESS:=1.2.3.4

# ads-ioc Makefile.base (pseudo make syntax because it's complicated)
st.cmd: _check_versions
	@echo "Executing pytmc stcmd: creating st.cmd..."
	cd "$(BUILD_PATH)" && \
		pytmc stcmd \
		--name "$(IOC_NAME)" \
		--plc "$(PLC)" \
		--template-path "$(TEMPLATE_PATH)" \
		--template "$(STCMD_TEMPLATE)" \
		--hashbang "$(BINARY_PATH)" \
		--force-ip "$(PLC_IP_ADDRESS)" \
		--only-motor \
		-p "$(PREFIX)" \
		$(PYTMC_OPTS) \
		"$(call pyabspath,$(PROJECT_PATH))" > st.cmd

May be worth jumping to pytmc template as it's been planned for a while pcdshub/pytmc#209

A second sed step?

# IOC Makefile
PLC_IP_ADDRESS:=1.2.3.4

# ads-ioc Makefile.base (pseudo make syntax)
build:
    ... normal build step
    if PLC_IP_ADDRESS:
        sed -i -e "s/{{ pytmc_ip }}/$PLC_IP_ADDRESS/g" st.cmd

ADS deploy does not make in linux. (sourcing pcds_conda)

(pcds-3.1.0) [adpai@psbuild-rhel7-01 ioc-plc-lfe-vac]$ make
-----------------------------------------------------------
Build path: /reg/g/pcds/epics-dev/adpai/lcls-plc-lfe-vac/plc_lfe_vac/iocBoot/ioc-plc-lfe-vac/.pytmc_build
PLC: plc_lfe_vac
IOC name: ioc-plc-lfe-vac
PYTMC_OPTS:
PROJECT_PATH: ../../plc_lfe_vac/plc_lfe_vac.tsproj
Absolute project path:  /reg/g/pcds/epics-dev/adpai/lcls-plc-lfe-vac/plc_lfe_vac/plc_lfe_vac/plc_lfe_vac.tsproj
-----------------------------------------------------------


mkdir -p "/reg/g/pcds/epics-dev/adpai/lcls-plc-lfe-vac/plc_lfe_vac/iocBoot/ioc-plc-lfe-vac/.pytmc_build"
make[1]: Entering directory `/reg/g/pcds/epics-dev/adpai/lcls-plc-lfe-vac/plc_lfe_vac/iocBoot/ioc-plc-lfe-vac'
Executing pytmc stcmd: creating st.cmd...
cd "/reg/g/pcds/epics-dev/adpai/lcls-plc-lfe-vac/plc_lfe_vac/iocBoot/ioc-plc-lfe-vac/.pytmc_build" && \
        pytmc stcmd \
        --name "ioc-plc-lfe-vac" \
        --plc "plc_lfe_vac" \
        --template-path "/reg/g/pcds/epics/ioc/common/ads-ioc/R0.2.0/iocBoot/templates" \
        --template "st.cmd.template" \
        --hashbang "/reg/g/pcds/epics/ioc/common/ads-ioc/R0.2.0/bin/rhel7-x86_64/adsIoc" \
        --only-motor \
        -p "PREFIX" \
         \
        "/reg/g/pcds/epics-dev/adpai/lcls-plc-lfe-vac/plc_lfe_vac/plc_lfe_vac/plc_lfe_vac.tsproj" > st.cmd
Traceback (most recent call last):
  File "/reg/g/pcds/pyps/conda/py36/envs/pcds-3.1.0/bin/pytmc", line 11, in <module>
    load_entry_point('pytmc==2.5.0', 'console_scripts', 'pytmc')()
  File "/reg/g/pcds/pyps/conda/py36/envs/pcds-3.1.0/lib/python3.6/site-packages/pytmc/bin/pytmc.py", line 92, in main
    func(**kwargs)
  File "/reg/g/pcds/pyps/conda/py36/envs/pcds-3.1.0/lib/python3.6/site-packages/pytmc/bin/stcmd.py", line 215, in main
    project = parse(tsproj_project)
  File "/reg/g/pcds/pyps/conda/py36/envs/pcds-3.1.0/lib/python3.6/site-packages/pytmc/parser.py", line 38, in parse
    tree = lxml.etree.parse(f)
  File "src/lxml/etree.pyx", line 3519, in lxml.etree.parse
  File "src/lxml/parser.pxi", line 1860, in lxml.etree._parseDocument
  File "src/lxml/parser.pxi", line 1880, in lxml.etree._parseFilelikeDocument
  File "src/lxml/parser.pxi", line 1775, in lxml.etree._parseDocFromFilelike
  File "src/lxml/parser.pxi", line 1187, in lxml.etree._BaseParser._parseDocFromFilelike
  File "src/lxml/parser.pxi", line 601, in lxml.etree._ParserContext._handleParseResultDoc
  File "src/lxml/parser.pxi", line 711, in lxml.etree._handleParseResult
  File "src/lxml/parser.pxi", line 640, in lxml.etree._raiseParseError
  File "/reg/g/pcds/epics-dev/adpai/lcls-plc-lfe-vac/plc_lfe_vac/plc_lfe_vac/plc_lfe_vac.tsproj", line 1
lxml.etree.XMLSyntaxError: Document is empty, line 1, column 1
make[1]: *** [st.cmd] Error 1
make[1]: Leaving directory `/reg/g/pcds/epics-dev/adpai/lcls-plc-lfe-vac/plc_lfe_vac/iocBoot/ioc-plc-lfe-vac'
make: *** [build] Error 2
(pcds-3.1.0) [adpai@psbuild-rhel7-01 ioc-plc-lfe-vac]$

Sum read errors -> set alarm severity?

ioc-HOMS-XRT-PLC was reporting: Sum read 0 failed: status 1861

This is: 0x74518610x9811 0745ADSERR_CLIENT_SYNCTIMEOUTTimeout has occurred โ€“ the remote terminal is not responding in the specified ADS timeout. The route setting of the remote terminal may be configured incorrectly.

I think the associated records may not have gotten an alarm severity set - or, our clients (PyDM/typhos/PMPS diagnostic) were not appropriately rendering alarm severity widget outlines.

Technically an issue for https://github.com/pcdshub/twincat-ads ; will link it there as well.

Message spam in IOC shell

I came back from lunch to see a large wall in my terminal:

../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''
../motorRecord.cc:1628 ST1K1:ZOS:MMS mipSetVal old='' new=''

IOC name inconsistencies with IOC manager

There have been several cases to my knowledge of mismatched $(IOC) name compared to what IOC Manager has assigned as its ID.

This is a big problem since:

  • IOC manager will write log files and things to one directory
  • And ads-ioc will assume things are in another directory

This leads to confusion and potentially incorrect behavior in the end.

This is set here: https://github.com/pcdshub/IocManager/blob/fabc34c31e4fbb14c9d3b746474f42b3ef9e3688/startProc#L24
As part of the full process: https://confluence.slac.stanford.edu/display/PCDS/Detailed+Soft+IOC+boot+process#DetailedSoftIOCbootprocess-startProc

So we should be able to rely on $(IOC) being set for us externally. We could instead do:
epicsEnvSet("IOC", "$(IOC=iocname)")
to set a default in case it's being run without iocmanager (which can be useful in development/testing situations).

epics> epicsEnvShow GITHUB_USER
GITHUB_USER=klauer
epics> epicsEnvSet("GITHUB_USER", "$(GITHUB_USER=asdf)")
epics> epicsEnvShow GITHUB_USER
GITHUB_USER=klauer

and

epics> epicsEnvShow GITHUB_USER_A
GITHUB_USER_A is not an environment variable.
epics> epicsEnvSet("GITHUB_USER_A", "$(GITHUB_USER_A=asdf)")
epics> epicsEnvShow GITHUB_USER_A
GITHUB_USER_A=asdf

.archive file should have macros expanded

In my btps IOC, there is the following line:
$(BTPS):DEST:07:SRC:04:FFCenterY:InRange_RBV.VAL 1 scan
Which will not work appropriately with the archiver.
This should be expanded with DB_PARAMETERS from the Makefile.

Minimum velocity (VBAS) for motor records

Default velocity of 0 will not request a motion from the PLC, but confusingly go through retries and fail:

ioc-lfe-optics> ../motorRecord.cc:1789 MR1L0:HOMS:MMS:PITCH doRetryOrDone dval=300.000000 rdbd=2.000000 spdb=0.000100 udf=0 stat=0 rcnt=0 preferred_dir=1 relpos=300.051265 relbpo
s=300.051265 drbv=-0.051265
../motorRecord.cc:1810 MR1L0:HOMS:MMS:PITCH mipSetBit 'Mo' old='' new='Mo'
../motorRecord.cc:1532 MR1L0:HOMS:MMS:PITCH motor has stopped drbv=-0.008380 pp=0 udf=0 stat=0 nsta=0 mip=0x20('Mo') msta=0x4103
../motorRecord.cc:1186 MR1L0:HOMS:MMS:PITCH maybeRetry: not close enough rdbd=2.000000 diff=300.008380 rcnt=0 mip=0x20('Mo')
../motorRecord.cc:1215 MR1L0:HOMS:MMS:PITCH mipSetVal old='Mo' new='Ry'
../motorRecord.cc:1670 MR1L0:HOMS:MMS:PITCH mipSetBit 'Dr' old='Ry' new='Ry Dr'
../motorRecord.cc:1673 MR1L0:HOMS:MMS:PITCH callbackRequestDelayed() called

Seems to indicate we should have a non-zero base velocity specified.

Create .pvlist file in correct path

(Need to verify it's not being done already in the common post-startup script)

/reg/d/iocData/%s/iocInfo/IOC.pvlist should be created for channelfinder (or whatever the PCDS equivalent is).

Clarify primary repositories

There's (understandable) confusion with all of our repositories, which can of course lead to synchronization issues.

On pcdshub (public):

On slac-epics (public):

On afs $GIT_TOP (SLAC private):

  • /afs/slac/g/cd/swe/git/repos/package/epics/modules/twincat-ads.git
  • /afs/slac/g/cd/swe/git/repos/package/epics/modules/ethercatmc.git
  • /afs/slac/g/cd/swe/git/repos/package/epics/ioc/common/ads-ioc.git

My opinion is that pcdshub should remain our primary development platform (point of collaboration, where issues and pull requests go), slac-epics should remain our module repository mirror (everything in one place).

Though it may differ from normal workflows, the above also means that GIT_TOP becomes a mirror of pcdshub for these respective repositories.

What can we do from here - open-ended ideas/thoughts:

  • For slac-epics, perhaps we can recreate the repositories and make them forks of pcdshub?
  • For GIT_TOP, I'm not sure we can do anything to keep people from pushing to it directly
  • Keep the repository names consistent (ethercatmc / m-epics-ethercatmc?)

Investigate PINI/Autosave behavior

As reported in pcdshub/pytmc#235, we are seeing strange interactions in the record initialization process using autosave.

Autosave pass0 + PINI=0 => No value sent to PLC (Expected)
Autosave pass0 + PINI=1 => No value sent to PLC (Surprised!)
Autosave pass1 + PINI=0 => No value sent to PLC (Surprised!)
Autosave pass1 + PINI=1 => Yes value sent to PLC (Expected)

Add new makefile target for database linting

With pytmc/pyPDB, we can lint the database to find invalid fields for given record types. Currently, we don't default to doing this as pyPDB marks some inconsequential stuff as failures - we'll need to rectify that.

In the meantime, we can add another makefile target that does a "strict" lint - or dbd-based lint - of the database file to catch these errors prior to running the IOC.

ref https://github.com/pcdshub/lcls2-cc-lib/issues/15

Logfile inconsistencies in dev mode

In dev mode, the ioc still tries to write the logfiles to the /reg/d/iocData directory instead of the user's home area, and with a different ioc name. Compare the following directories:
~jjoshi/iocData/ioc-plc-kfe-rix-vac
/reg/d/iocData/ioc-kfe-rix-vac

Motor record does not process autosaved DIR/OFF properly on startup

This is usually not noticed, but causes a big issue if you've autosaved values for .DIR and .OFF.

What happens is that the displayed value is the unmodified raw value from the PLC after a boot. Your .DIR and .OFF fields display the autosaved values, but they are not applied to the .RBV field until the first record process. There are a few ways to process the record:

  • Request a move
  • Set a new (or the same) value to the .OFF field
  • Set 1 to the .PROC field

The first of which (request a move) results in very alarming behavior, where the motor position suddenly jumps in an instant!

I did a hacky fix at the bottom of ioc-lamp-motion's st.cmd for Adam:

dbpf("TMO:LAMP:MMS:01.PROC","1")
dbpf("TMO:LAMP:MMS:02.PROC","1")
dbpf("TMO:LAMP:MMS:03.PROC","1")
dbpf("TMO:LAMP:MMS:04.PROC","1")
dbpf("TMO:LAMP:MMS:05.PROC","1")
dbpf("TMO:LAMP:MMS:06.PROC","1")
dbpf("TMO:LAMP:MMS:10.PROC","1")

Improve error message when PLC project name misspelled

Vincent found that having his PLC project named incorrectly meant that the startup script didn't get created and this weird exception was thrown:

Traceback (most recent call last):
  File "/cds/group/pcds/pyps/conda/py39/envs/pcds-5.6.0/bin/pytmc", line 10, in <module>
    sys.exit(main())
  File "/cds/group/pcds/pyps/conda/py39/envs/pcds-5.6.0/lib/python3.9/site-packages/pytmc/bin/pytmc.py", line 91, in main
    func(**kwargs)
  File "/cds/group/pcds/pyps/conda/py39/envs/pcds-5.6.0/lib/python3.9/site-packages/pytmc/bin/template.py", line 742, in main
    raise stashed_exception
  File "/cds/group/pcds/pyps/conda/py39/envs/pcds-5.6.0/lib/python3.9/site-packages/pytmc/bin/template.py", line 735, in main
    rendered = render_template(template_text, template_args)
  File "/cds/group/pcds/pyps/conda/py39/envs/pcds-5.6.0/lib/python3.9/site-packages/pytmc/bin/template.py", line 621, in render_template
    return env.get_template('template').render(context)
  File "/cds/group/pcds/pyps/conda/py39/envs/pcds-5.6.0/lib/python3.9/site-packages/jinja2/environment.py", line 1291, in render
    self.environment.handle_exception()
  File "/cds/group/pcds/pyps/conda/py39/envs/pcds-5.6.0/lib/python3.9/site-packages/jinja2/environment.py", line 925, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "<template>", line 8, in top-level template code
  File "/cds/group/pcds/pyps/conda/py39/envs/pcds-5.6.0/lib/python3.9/site-packages/jinja2/environment.py", line 474, in getattr
    return getattr(obj, attribute)
jinja2.exceptions.UndefinedError: 'None' has no attribute 'filename'
make[1]: *** [st.cmd] Error 1
make[1]: Leaving directory `/cds/group/pcds/epics-dev/espov/ioc/mfx/lcls-plc-mfx-motion/iocBoot/ioc-mfx-motion'
make: *** [build] Error 2

This could be improved in the template by checking for a None plc and reporting an error/exiting somehow

autosave request file directory is probably in a bad location

set_requestfile_path( "$(IOC_TOP)/autosave" )

I saw for ioc-kfe-vac that /reg/g/pcds/epics-dev/ioc/kfe/lcls-plc-kfe-vac/ioc/ioc-kfe-vac/autosave was not writable by the IOC, which it needs to be for makeAutosaveFiles. This means I needed to make it writable for ps-ioc, which I think is probably undesirable.

Options, in order of preference:

  1. Make the request directory $IOC_DATA as well
  2. Adjust the Makefile to chown $USER:ps-ioc autosave. This would require the IOC builder to be part of the ps-ioc group
    ...
    ...
  3. Adjust the Makefile to set very relaxed permissions on autosave

Decide on Autosave path

$(IOC_INSTANCE_PATH)/autosave seems weird, especially since ${IOC_DATA_PATH}/${IOC_NAME}/autosave already exists.

Should we switch over? I think it was only the above for my testing, but I can't recall...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.