From 5a4db8d1925ccb306bf2802ad27c6de9c21b3886 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Fri, 8 Jul 2022 15:49:38 -0700 Subject: [PATCH 01/35] REF: use pytmc template to generate everything --- iocBoot/templates/Makefile.base | 48 +++++++++++++------------- iocBoot/templates/st.cmd.template | 57 ++++++++++++++++++++++++------- 2 files changed, 68 insertions(+), 37 deletions(-) diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index 999ba37..9427578 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -13,6 +13,7 @@ SHELL = /bin/bash # Set defaults: PYTMC_OPTS ?= +PYTMC_STCMD_OPTS ?= PYTMC_DB_OPTS ?= PREFIX ?= HOST_ARCH ?= rhel7-x86_64 @@ -23,7 +24,14 @@ TEMPLATE_PATH ?= $(IOC_TOP)/iocBoot/templates STCMD_TEMPLATE ?= st.cmd.template IOC_NAME := $(shell basename "$(IOC_INSTANCE_PATH)") PRODUCTION_IOC ?= 0 -PYTMC_MIN_VERSION ?= 2.7.7 +PYTMC_MIN_VERSION ?= 2.13.0 # <-- TODO update before merging +# The minimum callback queue size for EPICS IOCs: +QUEUE_SIZE_BASE ?= 2000 +# Additional records generated from the PLC project will increase the callback +# queue size, scaled by this number: +QUEUE_SIZE_SCALE ?= 2 +# The separator for PV names: +PV_DELIMITER ?= ':' ifeq ($(PRODUCTION_IOC), 1) IOC_DATA_PATH ?= /reg/d/iocData @@ -63,17 +71,21 @@ _check_versions: @python -c "import sys, pytmc, distutils.version; print('* Found pytmc v', pytmc.__version__); sys.exit(not (distutils.version.LooseVersion(pytmc.__version__) >= distutils.version.LooseVersion('$(PYTMC_MIN_VERSION)')))" || (echo "A newer pytmc is required: >= $(PYTMC_MIN_VERSION)" && exit 1) st.cmd: _check_versions - @echo "Executing pytmc stcmd: creating st.cmd..." + @echo "Executing pytmc stcmd: creating st.cmd and database files..." cd "$(BUILD_PATH)" && \ - pytmc stcmd \ - --name "$(IOC_NAME)" \ - --plc "$(PLC)" \ - --template-path "$(TEMPLATE_PATH)" \ - --template "$(STCMD_TEMPLATE)" \ - --hashbang "$(BINARY_PATH)" \ - --only-motor \ - -p "$(PREFIX)" \ + pytmc template \ + --macro ioc_name="$(IOC_NAME)" \ + --macro user="$(USER)" \ + --macro prefix="$(PREFIX)" \ + --macro plc="$(PLC)" \ + --macro hashbang="$(BINARY_PATH)" \ + --macro db_parameters=$(DB_PARAMETERS) \ + --macro queue_size_base=$(QUEUE_SIZE_BASE) \ + --macro queue_size_scale=$(QUEUE_SIZE_SCALE) \ + --macro pv_delimiter=$(PV_DELIMITER) \ + --template "$(TEMPLATE_PATH)/$(STCMD_TEMPLATE)" \ $(PYTMC_OPTS) \ + $(PYTMC_STCMD_OPTS) \ "$(call pyabspath,$(PROJECT_PATH))" > st.cmd db: _check_versions @@ -102,27 +114,17 @@ install: fi @if test -n "`shopt -s nullglob; echo "$(BUILD_PATH)"/*.db`"; then \ - echo "* Found database files to install; creating load_plc_databases.cmd..."; \ - find "$(BUILD_PATH)" -name '*.db' -print0 | \ - PREFIX=$(PREFIX) DELIM=":" DB_PARAMETERS=$(DB_PARAMETERS) \ - python $(TEMPLATE_PATH)/dbloads.py \ - > "$(BUILD_PATH)/load_plc_databases.cmd"; \ - \ + echo "* Found database files to install..."; \ for filename in "$(BUILD_PATH)"/*.db; \ do \ echo "* Installing: $$(basename $$filename)"; \ install -p -m 0444 "$$filename" "$(IOC_INSTANCE_PATH)"; \ done \ - else \ - touch "$(BUILD_PATH)/load_plc_databases.cmd"; \ fi @echo "* Installing: st.cmd" install -p -m 0555 "$(BUILD_PATH)/st.cmd" "$(IOC_INSTANCE_PATH)"; - @echo "* Installing: load_plc_databases.cmd" - install -p -m 0444 "$(BUILD_PATH)/load_plc_databases.cmd" "$(IOC_INSTANCE_PATH)"; - @shopt -s nullglob; \ for filename in "$(BUILD_PATH)"/*.archive; \ do \ @@ -155,7 +157,6 @@ build: mkdir -p "$(BUILD_PATH)" @$(MAKE) st.cmd - @$(MAKE) db @$(MAKE) envPaths @$(MAKE) install @@ -168,8 +169,7 @@ clean: @echo "* Cleaning..." @if [ -d "$(BUILD_PATH)" ]; then \ shopt -s nullglob; \ - rm -f "$(BUILD_PATH)"/st.cmd "$(BUILD_PATH)"/load_plc_databases.cmd \ - "$(BUILD_PATH)"/*.db "$(BUILD_PATH)"/*.archive; \ + rm -f "$(BUILD_PATH)"/st.cmd "$(BUILD_PATH)"/*.db "$(BUILD_PATH)"/*.archive; \ rmdir "$(BUILD_PATH)"; \ fi @echo "Done" diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index 2d3c53d..156e3fa 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -1,5 +1,22 @@ #!{{hashbang}} -###### AUTO-GENERATED DO NOT EDIT ############## +################### AUTO-GENERATED DO NOT EDIT ################### +{% set project, plc = get_plc_by_name(projects, plc) -%} +# Project name: {{ project.name }} ({{ plc.link_name }}) +# PLC name: {{ plc.name }} +# Generated using: pytmc {{ pytmc_version}} +# Project version: {{ project.git_info.describe }} +# Project hash: {{ project.git_info.sha }} +# +# Libraries: +{% for library, info in get_library_versions(plc) | dictsort %} +{% if "PlaceholderReference" in info and "PlaceholderResolution" in info %} +# {{ library }}: {{ info.PlaceholderReference.version }} -> {{ info.PlaceholderResolution.version }} ({{ info.PlaceholderResolution.vendor }}) +{% elif "PlaceholderReference" in info %} +# {{ library }}: {{ info.PlaceholderReference.version }} ({{ info.PlaceholderReference.vendor }}) +{% endif %} +{% endfor %} +# +################### AUTO-GENERATED DO NOT EDIT ################### < envPaths @@ -17,10 +34,10 @@ epicsEnvSet("ACF_FILE", "$(ADS_IOC_TOP)/iocBoot/templates/unrestricted.acf") dbLoadDatabase("$(ADS_IOC_TOP)/dbd/adsIoc.dbd") adsIoc_registerRecordDeviceDriver(pdbbase) -epicsEnvSet("ASYN_PORT", "{{asyn_port}}") -epicsEnvSet("IPADDR", "{{plc_ip}}") -epicsEnvSet("AMSID", "{{plc_ams_id}}") -epicsEnvSet("AMS_PORT", "{{plc_ads_port}}") +epicsEnvSet("ASYN_PORT", "ASYN_PLC") +epicsEnvSet("IPADDR", "{{plc.target_ip}}") +epicsEnvSet("AMSID", "{{plc.ams_id}}") +epicsEnvSet("AMS_PORT", "{{plc.ads_port}}") epicsEnvSet("ADS_MAX_PARAMS", "10000") epicsEnvSet("ADS_SAMPLE_MS", "50") epicsEnvSet("ADS_MAX_DELAY_MS", "100") @@ -54,10 +71,12 @@ adsAsynPortDriverConfigure("$(ASYN_PORT)", "$(IPADDR)", "$(AMSID)", "$(AMS_PORT) cd "$(ADS_IOC_TOP)/db" +{% set motors = get_motors(plc) %} {% if motors %} +{%- set nc = get_nc(project) %} -epicsEnvSet("MOTOR_PORT", "{{motor_port}}") -epicsEnvSet("PREFIX", "{{prefix}}{{delim}}") +epicsEnvSet("MOTOR_PORT", "PLC_ADS") +epicsEnvSet("PREFIX", "{{prefix}}{{pv_delimiter}}") epicsEnvSet("NUMAXES", "{{nc.axis_by_id|max}}") epicsEnvSet("MOVE_POLL_RATE", "200") epicsEnvSet("IDLE_POLL_RATE", "1000") @@ -109,21 +128,33 @@ dbLoadRecords("EthercatMCdebug.template", "PREFIX=$(MOTOR_PREFIX), MOTOR_NAME=$( {% endif %} dbLoadRecords("iocSoft.db", "IOC={{prefix}}") -dbLoadRecords("save_restoreStatus.db", "P={{prefix}}{{delim}}") +dbLoadRecords("save_restoreStatus.db", "P={{prefix}}{{pv_delimiter}}") dbLoadRecords("caPutLog.db", "IOC=${IOC}") ## TwinCat System Databse files ## -dbLoadRecords("TwinCAT_TaskInfo.db", "PORT={{ asyn_port }}, PREFIX={{prefix}}") -dbLoadRecords("TwinCAT_AppInfo.db", "PORT={{ asyn_port }}, PREFIX={{prefix}}") +dbLoadRecords("TwinCAT_TaskInfo.db", "PORT=${ASYN_PORT}, PREFIX={{prefix}}") +dbLoadRecords("TwinCAT_AppInfo.db", "PORT=${ASYN_PORT}, PREFIX={{prefix}}") cd "$(IOC_TOP)" ## Database files ## -< "$(IOC_TOP)/load_plc_databases.cmd" +{% if plc.tmc %} +{% set db_filenames, records = generate_records(plc) %} +{% for db in db_filenames %} +dbLoadRecords("{{ db }}", "PORT={{ asyn_port }},{{ db_parameters }}") +{% endfor %} +{%- set num_records = records | length %} +{%- set queue_size_base = queue_size_base | int %} +{%- set queue_size_scale = queue_size_scale | int %} +{%- set callback_queue_size = queue_size_base + queue_size_scale * num_records %} + +# Total records: {{ records | length }} +callbackSetQueueSize({{ callback_queue_size }}) +{% endif %} {% if additional_db_files %} {% for db in additional_db_files %} -dbLoadRecords("{{ db.file }}", "PORT={{ asyn_port }},PREFIX={{prefix}}{{delim}},IOCNAME=$(IOC),{{ db.macros }}") +dbLoadRecords("{{ db.file }}", "PORT={{ asyn_port }},PREFIX={{prefix}}{{pv_delimiter}},IOCNAME=$(IOC),{{ db.macros }}") {% endfor %} {% endif %} @@ -132,7 +163,7 @@ dbLoadRecords("{{ db.file }}", "PORT={{ asyn_port }},PREFIX={{prefix}}{{delim}}, set_savefile_path( "$(IOC_DATA)/$(IOC)/autosave" ) set_requestfile_path( "$(IOC_TOP)/autosave" ) -save_restoreSet_status_prefix( "{{prefix}}{{delim}}" ) +save_restoreSet_status_prefix( "{{prefix}}{{pv_delimiter}}" ) save_restoreSet_IncompleteSetsOk( 1 ) save_restoreSet_DatedBackupFiles( 1 ) set_pass0_restoreFile( "info_positions.sav" ) From b05e9261d19aec4804da8e0a539327f173abe05c Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Fri, 8 Jul 2022 15:54:05 -0700 Subject: [PATCH 02/35] MNT: consistent macro styling --- iocBoot/templates/st.cmd.template | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index 156e3fa..7c9efd7 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -129,15 +129,15 @@ dbLoadRecords("EthercatMCdebug.template", "PREFIX=$(MOTOR_PREFIX), MOTOR_NAME=$( dbLoadRecords("iocSoft.db", "IOC={{prefix}}") dbLoadRecords("save_restoreStatus.db", "P={{prefix}}{{pv_delimiter}}") -dbLoadRecords("caPutLog.db", "IOC=${IOC}") +dbLoadRecords("caPutLog.db", "IOC=$(IOC)") -## TwinCat System Databse files ## -dbLoadRecords("TwinCAT_TaskInfo.db", "PORT=${ASYN_PORT}, PREFIX={{prefix}}") -dbLoadRecords("TwinCAT_AppInfo.db", "PORT=${ASYN_PORT}, PREFIX={{prefix}}") +## TwinCAT task and application databases ## +dbLoadRecords("TwinCAT_TaskInfo.db", "PORT=$(ASYN_PORT), PREFIX={{prefix}}") +dbLoadRecords("TwinCAT_AppInfo.db", "PORT=$(ASYN_PORT), PREFIX={{prefix}}") cd "$(IOC_TOP)" -## Database files ## +## PLC Project Database files ## {% if plc.tmc %} {% set db_filenames, records = generate_records(plc) %} {% for db in db_filenames %} @@ -186,7 +186,7 @@ iocInit() iocLogInit() # Configure and start the caPutLogger after iocInit -epicsEnvSet(EPICS_AS_PUT_LOG_PV, "${IOC}:caPutLog:Last") +epicsEnvSet(EPICS_AS_PUT_LOG_PV, "$(IOC):caPutLog:Last") # caPutLogInit("HOST:PORT", config) # config options: @@ -194,7 +194,7 @@ epicsEnvSet(EPICS_AS_PUT_LOG_PV, "${IOC}:caPutLog:Last") # 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) +caPutLogInit("$(EPICS_CAPUTLOG_HOST):$(EPICS_CAPUTLOG_PORT)", 0) # Start autosave backups create_monitor_set( "info_positions.req", 10, "" ) From df9076953ae51242360aeed0b3776f375cff0bd0 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Fri, 8 Jul 2022 16:00:13 -0700 Subject: [PATCH 03/35] FIX: ads port is from the tmc file --- iocBoot/templates/st.cmd.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index 7c9efd7..0977795 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -37,7 +37,7 @@ adsIoc_registerRecordDeviceDriver(pdbbase) epicsEnvSet("ASYN_PORT", "ASYN_PLC") epicsEnvSet("IPADDR", "{{plc.target_ip}}") epicsEnvSet("AMSID", "{{plc.ams_id}}") -epicsEnvSet("AMS_PORT", "{{plc.ads_port}}") +epicsEnvSet("AMS_PORT", "{{plc.tmc.ads_port}}") epicsEnvSet("ADS_MAX_PARAMS", "10000") epicsEnvSet("ADS_SAMPLE_MS", "50") epicsEnvSet("ADS_MAX_DELAY_MS", "100") From 584951d8f15cb22361b21215b2d6ff537de40e14 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Fri, 8 Jul 2022 16:14:41 -0700 Subject: [PATCH 04/35] ENH: add PLC hostname override + fix ads port --- iocBoot/templates/Makefile.base | 7 +++++-- iocBoot/templates/Makefile.ioc | 6 +++++- iocBoot/templates/st.cmd.template | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index 9427578..9aee7ca 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -32,6 +32,8 @@ QUEUE_SIZE_BASE ?= 2000 QUEUE_SIZE_SCALE ?= 2 # The separator for PV names: PV_DELIMITER ?= ':' +# The PLC hostname which can be used in place of the auto-detected IP address: +PLC_HOSTNAME ?= ifeq ($(PRODUCTION_IOC), 1) IOC_DATA_PATH ?= /reg/d/iocData @@ -74,15 +76,16 @@ st.cmd: _check_versions @echo "Executing pytmc stcmd: creating st.cmd and database files..." cd "$(BUILD_PATH)" && \ pytmc template \ - --macro ioc_name="$(IOC_NAME)" \ - --macro user="$(USER)" \ --macro prefix="$(PREFIX)" \ --macro plc="$(PLC)" \ + --macro ioc_name="$(IOC_NAME)" \ + --macro user="$(USER)" \ --macro hashbang="$(BINARY_PATH)" \ --macro db_parameters=$(DB_PARAMETERS) \ --macro queue_size_base=$(QUEUE_SIZE_BASE) \ --macro queue_size_scale=$(QUEUE_SIZE_SCALE) \ --macro pv_delimiter=$(PV_DELIMITER) \ + --macro plc_hostname_override='$(PLC_HOSTNAME)' \ --template "$(TEMPLATE_PATH)/$(STCMD_TEMPLATE)" \ $(PYTMC_OPTS) \ $(PYTMC_STCMD_OPTS) \ diff --git a/iocBoot/templates/Makefile.ioc b/iocBoot/templates/Makefile.ioc index 89ef18a..ec21e81 100644 --- a/iocBoot/templates/Makefile.ioc +++ b/iocBoot/templates/Makefile.ioc @@ -8,9 +8,13 @@ PROJECT_NAME := {{ project_name }} PROJECT_PATH := {{ tsproj_path }} PLC := {{ plc_name }} -PYTMC_OPTS := +PYTMC_OPTS := PREFIX := PLC:$(PLC) +# If you know the netconfig name of the PLC, enter it here. If specified, this +# will be used in place of the auto-detected IP address from the PLC project: +PLC_HOSTNAME := + # With two $$, as in $$(IOC) below, this will be expanded in the # environment of st.cmd: DB_PARAMETERS := 'PREFIX=$(PREFIX):,IOCNAME=$$(IOC),IOC=$$(IOC)' diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index 0977795..8f81012 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -35,9 +35,9 @@ dbLoadDatabase("$(ADS_IOC_TOP)/dbd/adsIoc.dbd") adsIoc_registerRecordDeviceDriver(pdbbase) epicsEnvSet("ASYN_PORT", "ASYN_PLC") -epicsEnvSet("IPADDR", "{{plc.target_ip}}") +epicsEnvSet("IPADDR", "{{plc_hostname_override or plc.target_ip}}") epicsEnvSet("AMSID", "{{plc.ams_id}}") -epicsEnvSet("AMS_PORT", "{{plc.tmc.ads_port}}") +epicsEnvSet("AMS_PORT", "{{plc.port}}") epicsEnvSet("ADS_MAX_PARAMS", "10000") epicsEnvSet("ADS_SAMPLE_MS", "50") epicsEnvSet("ADS_MAX_DELAY_MS", "100") From 911f1c02d5cd67983353c582b24898ac0e1330cb Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Fri, 8 Jul 2022 16:27:11 -0700 Subject: [PATCH 05/35] ENH: hook for ignoring linter errors easily --- iocBoot/templates/Makefile.base | 3 +++ iocBoot/templates/st.cmd.template | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index 9aee7ca..4c8781e 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -34,6 +34,8 @@ QUEUE_SIZE_SCALE ?= 2 PV_DELIMITER ?= ':' # The PLC hostname which can be used in place of the auto-detected IP address: PLC_HOSTNAME ?= +# Ignore linter errors, if possible. This is disabled by default. +IGNORE_LINTER_ERRORS ?= 0 ifeq ($(PRODUCTION_IOC), 1) IOC_DATA_PATH ?= /reg/d/iocData @@ -86,6 +88,7 @@ st.cmd: _check_versions --macro queue_size_scale=$(QUEUE_SIZE_SCALE) \ --macro pv_delimiter=$(PV_DELIMITER) \ --macro plc_hostname_override='$(PLC_HOSTNAME)' \ + --macro ignore_linter_errors='$(IGNORE_LINTER_ERRORS)' \ --template "$(TEMPLATE_PATH)/$(STCMD_TEMPLATE)" \ $(PYTMC_OPTS) \ $(PYTMC_STCMD_OPTS) \ diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index 8f81012..aa6b959 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -139,7 +139,8 @@ cd "$(IOC_TOP)" ## PLC Project Database files ## {% if plc.tmc %} -{% set db_filenames, records = generate_records(plc) %} +{% set allow_errors = ignore_linter_errors | int %} +{% set db_filenames, records = generate_records(plc, allow_errors=allow_errors) %} {% for db in db_filenames %} dbLoadRecords("{{ db }}", "PORT={{ asyn_port }},{{ db_parameters }}") {% endfor %} From 788c562430258bd06b516a470eba18594b56fcb6 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Fri, 8 Jul 2022 16:33:29 -0700 Subject: [PATCH 06/35] FIX: use filename for project --- iocBoot/templates/st.cmd.template | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index aa6b959..10d58f4 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -1,8 +1,9 @@ #!{{hashbang}} ################### AUTO-GENERATED DO NOT EDIT ################### {% set project, plc = get_plc_by_name(projects, plc) -%} -# Project name: {{ project.name }} ({{ plc.link_name }}) -# PLC name: {{ plc.name }} +# +# Project: {{ project.filename.name }} +# PLC name: {{ plc.name }} ({{ plc.link_name }}) # Generated using: pytmc {{ pytmc_version}} # Project version: {{ project.git_info.describe }} # Project hash: {{ project.git_info.sha }} From 6d016502f0f90e98a84a4f8d3cec9a4d58f90170 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Fri, 8 Jul 2022 16:54:38 -0700 Subject: [PATCH 07/35] REF: 'paths -> iocdata' update --- iocBoot/templates/Makefile.base | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index 4c8781e..8c5d956 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -49,14 +49,14 @@ DB_PARAMETERS ?= 'PREFIX=$(PREFIX):,IOCNAME=$$(IOC),IOC=$$(IOC)' # abspath is failing with spaces - falling back to Python here: pyabspath = $(shell python -c "import os, sys; print(os.path.abspath(os.path.expanduser(sys.argv[1])))" "$(1)" ) -all: build paths clean +all: build iocdata clean help: @echo "Available commands:" @echo " all: builds the IOC and cleans the temporary files" @echo " build: builds the st.cmd, databases, envPaths, etc." @echo " clean: cleans temporary pytmc files in $(BUILD_PATH)" - @echo " paths: make relevant directories (autosave, etc.)" + @echo " iocdata: create and/or update iocData directories (autosave, etc.)" @echo " lint: lint the pragmas" @echo " lintdb: lint the generated .db file against the IOC dbd" @echo " summary: tool shortcut - display a PLC project summary" @@ -72,7 +72,7 @@ help: _check_versions: - @python -c "import sys, pytmc, distutils.version; print('* Found pytmc v', pytmc.__version__); sys.exit(not (distutils.version.LooseVersion(pytmc.__version__) >= distutils.version.LooseVersion('$(PYTMC_MIN_VERSION)')))" || (echo "A newer pytmc is required: >= $(PYTMC_MIN_VERSION)" && exit 1) + @python -c "import sys, pytmc, distutils.version; print('* Found pytmc v', pytmc.__version__); sys.exit(not (distutils.version.LooseVersion(pytmc.__version__) >= distutils.version.LooseVersion('$(PYTMC_MIN_VERSION)')))" || (echo "A newer pytmc is required: >= $(PYTMC_MIN_VERSION)" 2> /dev/null && exit 1) st.cmd: _check_versions @echo "Executing pytmc stcmd: creating st.cmd and database files..." @@ -111,7 +111,7 @@ envPaths: @echo 'epicsEnvSet("IOC_TOP", "$(IOC_INSTANCE_PATH)")' >> "$(IOC_INSTANCE_PATH)"/envPaths @echo 'epicsEnvSet("IOC_DATA", "$(IOC_DATA_PATH)")' >> "$(IOC_INSTANCE_PATH)"/envPaths -install: +copy_build_output: @echo "" @echo "* Copying st.cmd and databases..." @ if [ -f "$(IOC_INSTANCE_PATH)"/st.cmd ]; then \ @@ -134,19 +134,11 @@ install: @shopt -s nullglob; \ for filename in "$(BUILD_PATH)"/*.archive; \ do \ - if [ -d "$(ARCHIVE_PATH)" ]; then \ - echo "* Installing archive file: $$(basename $$filename)"; \ - install -p -m 0444 "$$filename" "$(ARCHIVE_PATH)"; \ - else \ - echo "* Warning: ${ARCHIVE_PATH} does not exist;" \ - "copying archive file to the IOC instance path."; \ - install -p -m 0444 "$$filename" "$(IOC_INSTANCE_PATH)"; \ - fi; \ + install -p -m 0444 "$$filename" "$(IOC_INSTANCE_PATH)"; \ done @cd "$(IOC_INSTANCE_PATH)" - build: @echo "-----------------------------------------------------------" @echo "Build path: $(BUILD_PATH)" @@ -164,7 +156,7 @@ build: @$(MAKE) st.cmd @$(MAKE) envPaths - @$(MAKE) install + @$(MAKE) copy_build_output @echo "" @echo "Build complete." @@ -181,12 +173,19 @@ clean: @echo "Done" -paths: +iocdata: @echo "Creating IOC data directory" install --mode 0775 --group ps-ioc --directory $(IOC_DATA_PATH)/$(IOC_NAME)/{iocInfo,archive,logs,autosave} @echo "Creating autosave files directory" install --mode 0775 --group ps-ioc --directory $(IOC_INSTANCE_PATH)/autosave - + @shopt -s nullglob; \ + for filename in "$(IOC_INSTANCE_PATH)"/*.archive; \ + do \ + if [ -d "$(ARCHIVE_PATH)" ]; then \ + echo "* Installing archive file: $$(basename $$filename)"; \ + install -p -m 0444 "$$filename" "$(ARCHIVE_PATH)"; \ + fi; \ + done lint: _check_versions @echo "Linting the pytmc pragmas. Use \`make $@ PYTMC_OPTS=...\` to pass args to pytmc." > /dev/stderr @@ -226,4 +225,4 @@ types: _check_versions pytmc types "$(call pyabspath,$(PROJECT_PATH))" $(PYTMC_OPTS) -.PHONY: all _check_versions st.cmd db envPaths install build clean paths lint lintdb summary code outline debug types +.PHONY: all _check_versions st.cmd db envPaths copy_build_output build clean iocdata lint lintdb summary code outline debug types From 02507ad92f426e57051d7dc8ecde86ee99d4eba3 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Fri, 8 Jul 2022 16:55:52 -0700 Subject: [PATCH 08/35] FIX: setgid bit for directories --- iocBoot/templates/Makefile.base | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index 8c5d956..57e055d 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -175,9 +175,9 @@ clean: iocdata: @echo "Creating IOC data directory" - install --mode 0775 --group ps-ioc --directory $(IOC_DATA_PATH)/$(IOC_NAME)/{iocInfo,archive,logs,autosave} + install --mode 2775 --group ps-ioc --directory $(IOC_DATA_PATH)/$(IOC_NAME)/{iocInfo,archive,logs,autosave} @echo "Creating autosave files directory" - install --mode 0775 --group ps-ioc --directory $(IOC_INSTANCE_PATH)/autosave + install --mode 2775 --group ps-ioc --directory $(IOC_INSTANCE_PATH)/autosave @shopt -s nullglob; \ for filename in "$(IOC_INSTANCE_PATH)"/*.archive; \ do \ From 63ade1024c6387b8e836bf13a3b2803629c8e2cc Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Fri, 8 Jul 2022 16:59:31 -0700 Subject: [PATCH 09/35] FIX: use /cds/data instead of /reg/d --- iocBoot/templates/Makefile.base | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index 57e055d..b761ecf 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -38,7 +38,7 @@ PLC_HOSTNAME ?= IGNORE_LINTER_ERRORS ?= 0 ifeq ($(PRODUCTION_IOC), 1) - IOC_DATA_PATH ?= /reg/d/iocData + IOC_DATA_PATH ?= /cds/data/iocData else IOC_DATA_PATH ?= $(HOME)/iocData endif From 8fbd44bc1f1aa5d6f58403d8d3f980b29996484e Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Mon, 11 Jul 2022 10:51:11 -0700 Subject: [PATCH 10/35] REF: pytmc knows about task IDs now --- app/Db/TwinCAT_TaskInfo.db | 260 ++---------------------------- iocBoot/templates/Makefile.base | 4 +- iocBoot/templates/st.cmd.template | 4 +- 3 files changed, 18 insertions(+), 250 deletions(-) diff --git a/app/Db/TwinCAT_TaskInfo.db b/app/Db/TwinCAT_TaskInfo.db index 7a47240..c899820 100644 --- a/app/Db/TwinCAT_TaskInfo.db +++ b/app/Db/TwinCAT_TaskInfo.db @@ -1,4 +1,5 @@ -record(longin,"$(PREFIX):TaskInfo:1:CycleTime"){ + +record(longin,"$(PREFIX):TaskInfo:$(IDX):CycleTime"){ field(PINI, "1") field(TSE, -2) field(DTYP, "asynInt32") @@ -7,7 +8,7 @@ record(longin,"$(PREFIX):TaskInfo:1:CycleTime"){ info(archive, "monitor 1: VAL") } -record(longin,"$(PREFIX):TaskInfo:1:Priority"){ +record(longin,"$(PREFIX):TaskInfo:$(IDX):Priority"){ field(PINI, "1") field(TSE, -2) field(DTYP, "asynInt32") @@ -16,7 +17,7 @@ record(longin,"$(PREFIX):TaskInfo:1:Priority"){ info(archive, "monitor 1: VAL") } -record(waveform,"$(PREFIX):TaskInfo:1:TaskName"){ +record(waveform,"$(PREFIX):TaskInfo:$(IDX):TaskName"){ field(PINI, "1") field(TSE, -2) field(DTYP, "asynInt8ArrayIn") @@ -28,14 +29,14 @@ record(waveform,"$(PREFIX):TaskInfo:1:TaskName"){ } -record(longin,"$(PREFIX):TaskInfo:1:AdsPort"){ +record(longin,"$(PREFIX):TaskInfo:$(IDX):AdsPort"){ field(DTYP, "asynInt32") field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[1].AdsPort?") info(archive, "monitor 1: VAL") field(SCAN,"I/O Intr") } -record(longin,"$(PREFIX):TaskInfo:1:CycleCount"){ +record(longin,"$(PREFIX):TaskInfo:$(IDX):CycleCount"){ field(PINI, "1") field(TSE, -2) field(DTYP, "asynInt32") @@ -44,7 +45,7 @@ record(longin,"$(PREFIX):TaskInfo:1:CycleCount"){ info(archive, "monitor 1: VAL") } -record(longin,"$(PREFIX):TaskInfo:1:DcTaskTime"){ +record(longin,"$(PREFIX):TaskInfo:$(IDX):DcTaskTime"){ field(PINI, "1") field(TSE, -2) field(DTYP, "asynInt32") @@ -53,7 +54,7 @@ record(longin,"$(PREFIX):TaskInfo:1:DcTaskTime"){ info(archive, "monitor 1: VAL") } -record(longin,"$(PREFIX):TaskInfo:1:LastExecTime"){ +record(longin,"$(PREFIX):TaskInfo:$(IDX):LastExecTime"){ field(PINI, "1") field(TSE, -2) field(DTYP, "asynInt32") @@ -62,7 +63,7 @@ record(longin,"$(PREFIX):TaskInfo:1:LastExecTime"){ info(archive, "monitor 1: VAL") } -record(bi,"$(PREFIX):TaskInfo:1:FirstCycle"){ +record(bi,"$(PREFIX):TaskInfo:$(IDX):FirstCycle"){ field(PINI, "1") field(TSE, -2) field(DTYP, "asynInt32") @@ -73,7 +74,7 @@ record(bi,"$(PREFIX):TaskInfo:1:FirstCycle"){ info(archive, "monitor 1: VAL") } -record(bi,"$(PREFIX):TaskInfo:1:CycleTimeExceeded"){ +record(bi,"$(PREFIX):TaskInfo:$(IDX):CycleTimeExceeded"){ field(PINI, "1") field(TSE, -2) field(DTYP, "asynInt32") @@ -84,7 +85,7 @@ record(bi,"$(PREFIX):TaskInfo:1:CycleTimeExceeded"){ info(archive, "monitor 1: VAL") } -record(longin, "$(PREFIX):TaskInfo:1:ExceedCount_RBV"){ +record(longin, "$(PREFIX):TaskInfo:$(IDX):ExceedCount_RBV"){ field(DTYP, "asynInt32") field(INP, "@asyn($(PORT),0,1)ADSPORT=$(TASK1_PORT=350)/TS_MS=1000/.ADR.16#F200,16#100,4,19?") field(PINI, "1") @@ -93,7 +94,7 @@ record(longin, "$(PREFIX):TaskInfo:1:ExceedCount_RBV"){ info(archive, "monitor 1: VAL") } -record(bi,"$(PREFIX):TaskInfo:1:InCallAfterOutputUpdate"){ +record(bi,"$(PREFIX):TaskInfo:$(IDX):InCallAfterOutputUpdate"){ field(PINI, "1") field(TSE, -2) field(DTYP, "asynInt32") @@ -104,7 +105,7 @@ record(bi,"$(PREFIX):TaskInfo:1:InCallAfterOutputUpdate"){ info(archive, "monitor 1: VAL") } -record(bi,"$(PREFIX):TaskInfo:1:RTViolation"){ +record(bi,"$(PREFIX):TaskInfo:$(IDX):RTViolation"){ field(PINI, "1") field(TSE, -2) field(DTYP, "asynInt32") @@ -114,238 +115,3 @@ record(bi,"$(PREFIX):TaskInfo:1:RTViolation"){ field(ONAM,"TRUE") info(archive, "monitor 1: VAL") } - - -record(longin,"$(PREFIX):TaskInfo:2:CycleTime"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[2].CycleTime?") - field(SCAN,"I/O Intr") -info(archive, "monitor 1: VAL") -} - -record(longin,"$(PREFIX):TaskInfo:2:Priority"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[2].Priority?") - field(SCAN,"I/O Intr") - info(archive, "monitor 1: VAL") -} - -record(waveform,"$(PREFIX):TaskInfo:2:TaskName"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt8ArrayIn") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[2].TaskName?") - field(NELM,63) - field(SCAN,"I/O Intr") - field(FTVL,"CHAR") - info(archive, "monitor 1: VAL") -} - - -record(longin,"$(PREFIX):TaskInfo:2:AdsPort"){ - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[2].AdsPort?") - info(archive, "monitor 1: VAL") - field(SCAN,"I/O Intr") -} - -record(longin,"$(PREFIX):TaskInfo:2:CycleCount"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[2].CycleCount?") - field(SCAN,"I/O Intr") -info(archive, "monitor 1: VAL") -} - -record(longin,"$(PREFIX):TaskInfo:2:DcTaskTime"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[2].DcTaskTime?") - field(SCAN,"I/O Intr") -info(archive, "monitor 1: VAL") -} - -record(longin,"$(PREFIX):TaskInfo:2:LastExecTime"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[2].LastExecTime?") - field(SCAN,"I/O Intr") -info(archive, "monitor 1: VAL") -} - -record(bi,"$(PREFIX):TaskInfo:2:FirstCycle"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[2].FirstCycle?") - field(SCAN,"I/O Intr") - field(ZNAM,"FALSE") - field(ONAM,"TRUE") -info(archive, "monitor 1: VAL") -} - -record(bi,"$(PREFIX):TaskInfo:2:CycleTimeExceeded"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[2].CycleTimeExceeded?") - field(SCAN,"I/O Intr") - field(ZNAM,"FALSE") - field(ONAM,"TRUE") -info(archive, "monitor 1: VAL") -} - -record(longin, "$(PREFIX):TaskInfo:2:ExceedCount_RBV"){ - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=$(TASK2_PORT=351)/TS_MS=1000/.ADR.16#F200,16#100,4,19?") - field(PINI, "1") - field(SCAN, "I/O Intr") - field(TSE, "-2") - info(archive, "monitor 1: VAL") -} - -record(bi,"$(PREFIX):TaskInfo:2:InCallAfterOutputUpdate"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[2].InCallAfterOutputUpdate?") - field(SCAN,"I/O Intr") - field(ZNAM,"FALSE") - field(ONAM,"TRUE") -info(archive, "monitor 1: VAL") -} - -record(bi,"$(PREFIX):TaskInfo:2:RTViolation"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[2].RTViolation?") - field(SCAN,"I/O Intr") - field(ZNAM,"FALSE") - field(ONAM,"TRUE") -info(archive, "monitor 1: VAL") -} - -record(longin,"$(PREFIX):TaskInfo:3:CycleTime"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[3].CycleTime?") - field(SCAN,"I/O Intr") -info(archive, "monitor 1: VAL") -} - -record(longin,"$(PREFIX):TaskInfo:3:Priority"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[3].Priority?") - field(SCAN,"I/O Intr") - info(archive, "monitor 1: VAL") -} - -record(waveform,"$(PREFIX):TaskInfo:3:TaskName"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt8ArrayIn") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[3].TaskName?") - field(NELM,63) - field(SCAN,"I/O Intr") - field(FTVL,"CHAR") - info(archive, "monitor 1: VAL") -} - - -record(longin,"$(PREFIX):TaskInfo:3:AdsPort"){ - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[3].AdsPort?") - info(archive, "monitor 1: VAL") - field(SCAN,"I/O Intr") -} - -record(longin,"$(PREFIX):TaskInfo:3:CycleCount"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[3].CycleCount?") - field(SCAN,"I/O Intr") -info(archive, "monitor 1: VAL") -} - -record(longin,"$(PREFIX):TaskInfo:3:DcTaskTime"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[3].DcTaskTime?") - field(SCAN,"I/O Intr") -info(archive, "monitor 1: VAL") -} - -record(longin,"$(PREFIX):TaskInfo:3:LastExecTime"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[3].LastExecTime?") - field(SCAN,"I/O Intr") -info(archive, "monitor 1: VAL") -} - -record(bi,"$(PREFIX):TaskInfo:3:FirstCycle"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[3].FirstCycle?") - field(SCAN,"I/O Intr") - field(ZNAM,"FALSE") - field(ONAM,"TRUE") -info(archive, "monitor 1: VAL") -} - -record(bi,"$(PREFIX):TaskInfo:3:CycleTimeExceeded"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[3].CycleTimeExceeded?") - field(SCAN,"I/O Intr") - field(ZNAM,"FALSE") - field(ONAM,"TRUE") -info(archive, "monitor 1: VAL") -} - -record(longin, "$(PREFIX):TaskInfo:3:ExceedCount_RBV"){ - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=$(TASK3_PORT=352)/TS_MS=1000/.ADR.16#F200,16#100,4,19?") - field(PINI, "1") - field(SCAN, "I/O Intr") - field(TSE, "-2") - info(archive, "monitor 1: VAL") -} - -record(bi,"$(PREFIX):TaskInfo:3:InCallAfterOutputUpdate"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[3].InCallAfterOutputUpdate?") - field(SCAN,"I/O Intr") - field(ZNAM,"FALSE") - field(ONAM,"TRUE") -info(archive, "monitor 1: VAL") -} - -record(bi,"$(PREFIX):TaskInfo:3:RTViolation"){ - field(PINI, "1") - field(TSE, -2) - field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),0,1)ADSPORT=851/POLL_RATE=1/TwinCAT_SystemInfoVarList._TaskInfo[3].RTViolation?") - field(SCAN,"I/O Intr") - field(ZNAM,"FALSE") - field(ONAM,"TRUE") -info(archive, "monitor 1: VAL") -} diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index b761ecf..4871c92 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -89,10 +89,10 @@ st.cmd: _check_versions --macro pv_delimiter=$(PV_DELIMITER) \ --macro plc_hostname_override='$(PLC_HOSTNAME)' \ --macro ignore_linter_errors='$(IGNORE_LINTER_ERRORS)' \ - --template "$(TEMPLATE_PATH)/$(STCMD_TEMPLATE)" \ + --template "$(TEMPLATE_PATH)/$(STCMD_TEMPLATE)":"st.cmd" \ $(PYTMC_OPTS) \ $(PYTMC_STCMD_OPTS) \ - "$(call pyabspath,$(PROJECT_PATH))" > st.cmd + "$(call pyabspath,$(PROJECT_PATH))" db: _check_versions @echo "Executing pytmc db: creating $(PLC).db and $(PLC).archive..." diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index 10d58f4..fb4246c 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -133,7 +133,9 @@ dbLoadRecords("save_restoreStatus.db", "P={{prefix}}{{pv_delimiter}}") dbLoadRecords("caPutLog.db", "IOC=$(IOC)") ## TwinCAT task and application databases ## -dbLoadRecords("TwinCAT_TaskInfo.db", "PORT=$(ASYN_PORT), PREFIX={{prefix}}") +{% for priority, (_, task) in plc.instance.task_pous.items() %} +dbLoadRecords("TwinCAT_TaskInfo.db", "PORT=$(ASYN_PORT),PREFIX={{prefix}},IDX={{task.array_index}}") +{% endfor %} dbLoadRecords("TwinCAT_AppInfo.db", "PORT=$(ASYN_PORT), PREFIX={{prefix}}") cd "$(IOC_TOP)" From 3a145a1428f562637c41798be1c5cc21e436c317 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Mon, 11 Jul 2022 11:05:32 -0700 Subject: [PATCH 11/35] REF: set max_params dynamically based on record count --- iocBoot/templates/st.cmd.template | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index fb4246c..7090f23 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -9,6 +9,7 @@ # Project hash: {{ project.git_info.sha }} # # Libraries: +# {% for library, info in get_library_versions(plc) | dictsort %} {% if "PlaceholderReference" in info and "PlaceholderResolution" in info %} # {{ library }}: {{ info.PlaceholderReference.version }} -> {{ info.PlaceholderResolution.version }} ({{ info.PlaceholderResolution.vendor }}) @@ -18,7 +19,21 @@ {% endfor %} # ################### AUTO-GENERATED DO NOT EDIT ################### +{%- if plc.tmc %} + +{%- set allow_errors = ignore_linter_errors | int %} +{%- set db_filenames, records = generate_records(plc, allow_errors=allow_errors) %} +{%- set num_records = records | length %} +{%- set max_params = num_records + 1000 %} +{%- else %} + +{%- set db_filenames = [] %} +{%- set records = {} %} +{%- set num_records = 0 %} +{%- set max_params = 10000 %} + +{%- endif %} < envPaths epicsEnvSet("ADS_IOC_TOP", "$(TOP)" ) @@ -39,7 +54,7 @@ epicsEnvSet("ASYN_PORT", "ASYN_PLC") epicsEnvSet("IPADDR", "{{plc_hostname_override or plc.target_ip}}") epicsEnvSet("AMSID", "{{plc.ams_id}}") epicsEnvSet("AMS_PORT", "{{plc.port}}") -epicsEnvSet("ADS_MAX_PARAMS", "10000") +epicsEnvSet("ADS_MAX_PARAMS", "{{ max_params }}") epicsEnvSet("ADS_SAMPLE_MS", "50") epicsEnvSet("ADS_MAX_DELAY_MS", "100") epicsEnvSet("ADS_TIMEOUT_MS", "1000") @@ -142,12 +157,9 @@ cd "$(IOC_TOP)" ## PLC Project Database files ## {% if plc.tmc %} -{% set allow_errors = ignore_linter_errors | int %} -{% set db_filenames, records = generate_records(plc, allow_errors=allow_errors) %} {% for db in db_filenames %} dbLoadRecords("{{ db }}", "PORT={{ asyn_port }},{{ db_parameters }}") {% endfor %} -{%- set num_records = records | length %} {%- set queue_size_base = queue_size_base | int %} {%- set queue_size_scale = queue_size_scale | int %} {%- set callback_queue_size = queue_size_base + queue_size_scale * num_records %} From 74f336801f8daf94142d70ddbfe5c7597835b7e1 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Mon, 11 Jul 2022 11:16:08 -0700 Subject: [PATCH 12/35] MNT: build in system() so we can call scripts on startup --- app/src/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/Makefile b/app/src/Makefile index aba22b0..99e7c82 100644 --- a/app/src/Makefile +++ b/app/src/Makefile @@ -20,6 +20,7 @@ adsIoc_DBD += ads.dbd adsIoc_DBD += asyn.dbd adsIoc_DBD += drvAsynIPPort.dbd adsIoc_DBD += dbArchive.dbd +adsIoc_DBD += system.dbd ifneq (,$(findstring /,$(CAPUTLOG))) adsIoc_DBD += caPutLog.dbd From b71e8869bef0e9d6012747f79f2129a89bb9ba71 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Mon, 11 Jul 2022 11:16:38 -0700 Subject: [PATCH 13/35] CLN: remove dbloads --- iocBoot/templates/dbloads.py | 63 ------------------------------------ 1 file changed, 63 deletions(-) delete mode 100644 iocBoot/templates/dbloads.py diff --git a/iocBoot/templates/dbloads.py b/iocBoot/templates/dbloads.py deleted file mode 100644 index 60ea0ae..0000000 --- a/iocBoot/templates/dbloads.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python -''' -Usage: dbloads.py -Input: list of all database db_filenames, delimited by \0 -Output: list of dbLoadRecords(...) calls - -Relevant environment variables: - * DB_PARAMETERS: parameters to pass to dbLoadRecords() - * QUEUE_SIZE_BASE: the minimum callback queue size - * QUEUE_SIZE_SCALE: total_records * scale - -The callback queue size will be calculated as follows: - - (QUEUE_SIZE_SCALE * total_records) + QUEUE_SIZE_BASE -''' - -import os -import sys - - -def count_number_of_records(db_filename): - """Count the number of records in `db_filename`.""" - with open(db_filename, 'rt') as f: - return len( - [line for line in f.readlines() - if line.startswith('record(')] - ) - - -def load_record_entry(db_filename): - """Format dbLoadRecords() based on env variable DB_PARAMETERS.""" - env = dict(os.environ) - db_filename = os.path.split(db_filename)[-1] - env['db_filename'] = db_filename - - return ( - 'dbLoadRecords("{db_filename}", "PORT=ASYN_PLC,{DB_PARAMETERS}")' - ''.format(**env) - ) - - -def main(): - db_filenames = sys.stdin.read().strip('\0').split('\0') - - if db_filenames: - total_records = sum(count_number_of_records(fn) for fn in db_filenames) - else: - total_records = 0 - - # Multiply the number of records by the scale: - queue_size_scale = int(os.environ.get('QUEUE_SIZE_SCALE', '2')) - - # The minimum size of the queue, outside of those for additional records: - queue_size_base = int(os.environ.get('QUEUE_SIZE_BASE', '2000')) - queue_size = queue_size_scale * total_records + queue_size_base - - print('# Total records: {0}'.format(total_records)) - print('callbackSetQueueSize({0})'.format(queue_size)) - print('\n'.join(load_record_entry(fn) for fn in db_filenames)) - - -if __name__ == '__main__': - main() From 4a3e4c00f65e392f8ecc1c575a3e4fa76f432306 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Mon, 11 Jul 2022 12:12:09 -0700 Subject: [PATCH 14/35] ENH: automatic route addition --- iocBoot/templates/Makefile.base | 3 ++ iocBoot/templates/st.cmd.template | 7 ++- scripts/add_route.sh | 78 +++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100755 scripts/add_route.sh diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index 4871c92..d92cf0b 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -36,6 +36,8 @@ PV_DELIMITER ?= ':' PLC_HOSTNAME ?= # Ignore linter errors, if possible. This is disabled by default. IGNORE_LINTER_ERRORS ?= 0 +# IOC host IP regular expression +IOC_HOST_IP_REGEX ?= "^(134|172).*$" ifeq ($(PRODUCTION_IOC), 1) IOC_DATA_PATH ?= /cds/data/iocData @@ -89,6 +91,7 @@ st.cmd: _check_versions --macro pv_delimiter=$(PV_DELIMITER) \ --macro plc_hostname_override='$(PLC_HOSTNAME)' \ --macro ignore_linter_errors='$(IGNORE_LINTER_ERRORS)' \ + --macro ioc_host_ip_regex='$(IOC_HOST_IP_REGEX)' \ --template "$(TEMPLATE_PATH)/$(STCMD_TEMPLATE)":"st.cmd" \ $(PYTMC_OPTS) \ $(PYTMC_STCMD_OPTS) \ diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index 7090f23..1a1eb12 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -1,12 +1,14 @@ #!{{hashbang}} ################### AUTO-GENERATED DO NOT EDIT ################### {% set project, plc = get_plc_by_name(projects, plc) -%} +{%- set plc_host = plc_hostname_override or plc.target_ip %} # # Project: {{ project.filename.name }} # PLC name: {{ plc.name }} ({{ plc.link_name }}) # Generated using: pytmc {{ pytmc_version}} # Project version: {{ project.git_info.describe }} # Project hash: {{ project.git_info.sha }} +# PLC IP/host: {{ plc.target_ip}} ({{ plc_hostname_override }}) # # Libraries: # @@ -38,6 +40,9 @@ epicsEnvSet("ADS_IOC_TOP", "$(TOP)" ) +# Add a route to the PLC +system("${ADS_IOC_TOP}/scripts/add_route.sh {{ plc_host }} {{ ioc_host_ip_regex }}") + epicsEnvSet("ENGINEER", "{{user}}" ) epicsEnvSet("LOCATION", "{{prefix}}" ) epicsEnvSet("IOCSH_PS1", "$(IOC)> " ) @@ -51,7 +56,7 @@ dbLoadDatabase("$(ADS_IOC_TOP)/dbd/adsIoc.dbd") adsIoc_registerRecordDeviceDriver(pdbbase) epicsEnvSet("ASYN_PORT", "ASYN_PLC") -epicsEnvSet("IPADDR", "{{plc_hostname_override or plc.target_ip}}") +epicsEnvSet("IPADDR", "{{plc_host}}") epicsEnvSet("AMSID", "{{plc.ams_id}}") epicsEnvSet("AMS_PORT", "{{plc.port}}") epicsEnvSet("ADS_MAX_PARAMS", "{{ max_params }}") diff --git a/scripts/add_route.sh b/scripts/add_route.sh new file mode 100755 index 0000000..85fad29 --- /dev/null +++ b/scripts/add_route.sh @@ -0,0 +1,78 @@ +#!/bin/bash +# Usage: add_route.sh [plc-hostname] [ip-regex] + +if [ $# -ne 2 ]; then + echo "Usage: $0 [plc hostname] [ip regex]" > /dev/stderr + exit 1 +fi + +CONDA_BIN=${CONDA_BIN=/cds/group/pcds/pyps/conda/py39/envs/pcds-5.4.1/bin/conda} + +if [ ! -f "$CONDA_BIN" ]; then + echo "Conda unavailable. Skipping route addition." > /dev/stderr + exit 1 +fi + +set -e + +add_route() { + local plc_host + local ioc_hostname + local ioc_host_ip + + plc_host=$1 + ioc_hostname=$2 + ioc_host_ip=$3 + ioc_host_net_id="${ioc_host_ip}.1.1" + + if [ -z "$plc_host" ]; then + echo "PLC hostname unspecified" > /dev/stderr + exit 1 + fi + + if [ -z "$ioc_host_ip" ]; then + echo "IOC IP address unspecified" > /dev/stderr + exit 1 + fi + + if [ -z "$ioc_hostname" ]; then + echo "IOC hostname unspecified" > /dev/stderr + exit 1 + fi + + echo "Running ads-async to add a route to ${ioc_hostname} for IOC host ${ioc_hostname} (${ioc_host_ip})..." + set -x + $CONDA_BIN run ads-async route \ + --route-name="${ioc_hostname}" \ + "${plc_host}" \ + "${ioc_host_net_id}" \ + "${ioc_host_ip}" + { set +x; } 2> /dev/null + echo "Done." +} + +find_ioc_ip() { + local ipaddr + local regex + regex=$1 + + if [ -z "$regex" ]; then + echo "IOC IP match regex unspecified" > /dev/stderr + exit 1 + fi + + for ipaddr in $(dig +short "$(hostname)"); do + if [[ "$ipaddr" =~ ${regex} ]]; then + echo "$ipaddr" + return + fi + done +} + + +plc_host=$1 +host_ip_regex=$2 +ioc_hostname=$(hostname -s) +ioc_ip=$(find_ioc_ip "${host_ip_regex}") + +add_route "${plc_host}" "${ioc_hostname}" "${ioc_ip}" From fccfb86570f2d6f85d9e8a43a1c0f80313f8a82d Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Mon, 11 Jul 2022 12:19:21 -0700 Subject: [PATCH 15/35] FIX: envPaths on a new line --- iocBoot/templates/st.cmd.template | 1 + 1 file changed, 1 insertion(+) diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index 1a1eb12..6c7fdce 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -36,6 +36,7 @@ {%- set max_params = 10000 %} {%- endif %} + < envPaths epicsEnvSet("ADS_IOC_TOP", "$(TOP)" ) From acbb0248b13dfd79f82741e0c8d3cf1038b433a7 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Mon, 11 Jul 2022 12:19:31 -0700 Subject: [PATCH 16/35] MNT: update variables + messages for make st.cmd --- iocBoot/templates/Makefile.base | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index d92cf0b..f3021ed 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -13,7 +13,7 @@ SHELL = /bin/bash # Set defaults: PYTMC_OPTS ?= -PYTMC_STCMD_OPTS ?= +PYTMC_TEMPLATE_OPTS ?= PYTMC_DB_OPTS ?= PREFIX ?= HOST_ARCH ?= rhel7-x86_64 @@ -77,7 +77,7 @@ _check_versions: @python -c "import sys, pytmc, distutils.version; print('* Found pytmc v', pytmc.__version__); sys.exit(not (distutils.version.LooseVersion(pytmc.__version__) >= distutils.version.LooseVersion('$(PYTMC_MIN_VERSION)')))" || (echo "A newer pytmc is required: >= $(PYTMC_MIN_VERSION)" 2> /dev/null && exit 1) st.cmd: _check_versions - @echo "Executing pytmc stcmd: creating st.cmd and database files..." + @echo "Executing pytmc template: creating st.cmd and database files..." cd "$(BUILD_PATH)" && \ pytmc template \ --macro prefix="$(PREFIX)" \ @@ -94,7 +94,7 @@ st.cmd: _check_versions --macro ioc_host_ip_regex='$(IOC_HOST_IP_REGEX)' \ --template "$(TEMPLATE_PATH)/$(STCMD_TEMPLATE)":"st.cmd" \ $(PYTMC_OPTS) \ - $(PYTMC_STCMD_OPTS) \ + $(PYTMC_TEMPLATE_OPTS) \ "$(call pyabspath,$(PROJECT_PATH))" db: _check_versions From 1bf04d99caf4661ae9ebdedd6961a4242109bda1 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Mon, 11 Jul 2022 12:23:24 -0700 Subject: [PATCH 17/35] ENH: allow route addition to be disabled --- iocBoot/templates/Makefile.base | 3 +++ iocBoot/templates/st.cmd.template | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index f3021ed..e6efc4b 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -36,6 +36,8 @@ PV_DELIMITER ?= ':' PLC_HOSTNAME ?= # Ignore linter errors, if possible. This is disabled by default. IGNORE_LINTER_ERRORS ?= 0 +# Add a PLC route automatically at startup +ADD_PLC_ROUTE ?= 1 # IOC host IP regular expression IOC_HOST_IP_REGEX ?= "^(134|172).*$" @@ -92,6 +94,7 @@ st.cmd: _check_versions --macro plc_hostname_override='$(PLC_HOSTNAME)' \ --macro ignore_linter_errors='$(IGNORE_LINTER_ERRORS)' \ --macro ioc_host_ip_regex='$(IOC_HOST_IP_REGEX)' \ + --macro add_plc_route='$(ADD_PLC_ROUTE)' \ --template "$(TEMPLATE_PATH)/$(STCMD_TEMPLATE)":"st.cmd" \ $(PYTMC_OPTS) \ $(PYTMC_TEMPLATE_OPTS) \ diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index 6c7fdce..2e69dfe 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -41,9 +41,11 @@ epicsEnvSet("ADS_IOC_TOP", "$(TOP)" ) -# Add a route to the PLC +{% if add_plc_route | int != 0 %} +# Add a route to the PLC automatically: system("${ADS_IOC_TOP}/scripts/add_route.sh {{ plc_host }} {{ ioc_host_ip_regex }}") +{% endif %} epicsEnvSet("ENGINEER", "{{user}}" ) epicsEnvSet("LOCATION", "{{prefix}}" ) epicsEnvSet("IOCSH_PS1", "$(IOC)> " ) From 1c40d3e03b52f941588d9ce4f6c7cf568b40da67 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Mon, 11 Jul 2022 14:37:50 -0700 Subject: [PATCH 18/35] FIX: fix quotes around regex + remove 134. --- iocBoot/templates/Makefile.base | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index e6efc4b..6dd1d7a 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -39,7 +39,7 @@ IGNORE_LINTER_ERRORS ?= 0 # Add a PLC route automatically at startup ADD_PLC_ROUTE ?= 1 # IOC host IP regular expression -IOC_HOST_IP_REGEX ?= "^(134|172).*$" +IOC_HOST_IP_REGEX ?= ^172.*$ ifeq ($(PRODUCTION_IOC), 1) IOC_DATA_PATH ?= /cds/data/iocData From d8b3041899b900410ea19d25662520d206d674a1 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Fri, 22 Jul 2022 13:45:58 -0700 Subject: [PATCH 19/35] ENH: add records for project + dependency information --- app/Db/Makefile | 2 ++ app/Db/TwinCAT_Dependency.db | 17 ++++++++++++ app/Db/TwinCAT_Project.db | 44 +++++++++++++++++++++++++++++++ iocBoot/templates/st.cmd.template | 15 ++++++++++- 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 app/Db/TwinCAT_Dependency.db create mode 100644 app/Db/TwinCAT_Project.db diff --git a/app/Db/Makefile b/app/Db/Makefile index 0152c16..8f36895 100644 --- a/app/Db/Makefile +++ b/app/Db/Makefile @@ -28,6 +28,8 @@ DB += EthercatMCslit_soft.template DB += caPutLog.db DB += TwinCAT_TaskInfo.db DB += TwinCAT_AppInfo.db +DB += TwinCAT_Dependency.db +DB += TwinCAT_Project.db DB_INSTALLS += $(IOCADMIN)/db/iocSoft.db DB_INSTALLS += $(IOCADMIN)/db/devIocInfo.db diff --git a/app/Db/TwinCAT_Dependency.db b/app/Db/TwinCAT_Dependency.db new file mode 100644 index 0000000..5909e33 --- /dev/null +++ b/app/Db/TwinCAT_Dependency.db @@ -0,0 +1,17 @@ +record(lsi, "$(PREFIX):ProjectInfo:$(DEPENDENCY)") { + field(DISP, "TRUE") + field(DTYP, "Soft Channel") + field(PINI, "YES") + field(SCAN, "Passive") + field(VAL, "$(VERSION) -> $(VENDOR)") + info(archive, "monitor 1: VAL") +} + +record(lsi, "$(PREFIX):ProjectInfo:$(DEPENDENCY):Vendor") { + field(DISP, "TRUE") + field(DTYP, "Soft Channel") + field(PINI, "YES") + field(SCAN, "Passive") + field(VAL, "$(VENDOR)") + info(archive, "monitor 1: VAL") +} diff --git a/app/Db/TwinCAT_Project.db b/app/Db/TwinCAT_Project.db new file mode 100644 index 0000000..00675d0 --- /dev/null +++ b/app/Db/TwinCAT_Project.db @@ -0,0 +1,44 @@ +record(lsi, "$(PREFIX):ProjectInfo:PLCHost") { + field(DISP, "TRUE") + field(DTYP, "Soft Channel") + field(PINI, "YES") + field(SCAN, "Passive") + field(VAL, "$(PLC_HOST)") + info(archive, "monitor 1: VAL") +} + +record(lsi, "$(PREFIX):ProjectInfo:Project") { + field(DISP, "TRUE") + field(DTYP, "Soft Channel") + field(PINI, "YES") + field(SCAN, "Passive") + field(VAL, "$(PROJECT)") + info(archive, "monitor 1: VAL") +} + +record(lsi, "$(PREFIX):ProjectInfo:Hash") { + field(DISP, "TRUE") + field(DTYP, "Soft Channel") + field(PINI, "YES") + field(SCAN, "Passive") + field(VAL, "$(HASH)") + info(archive, "monitor 1: VAL") +} + +record(lsi, "$(PREFIX):ProjectInfo:Version") { + field(DISP, "TRUE") + field(DTYP, "Soft Channel") + field(PINI, "YES") + field(SCAN, "Passive") + field(VAL, "$(VERSION)") + info(archive, "monitor 1: VAL") +} + +record(lsi, "$(PREFIX):ProjectInfo:Pytmc") { + field(DISP, "TRUE") + field(DTYP, "Soft Channel") + field(PINI, "YES") + field(SCAN, "Passive") + field(VAL, "$(PYTMC)") + info(archive, "monitor 1: VAL") +} diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index 2e69dfe..79645d3 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -155,12 +155,25 @@ dbLoadRecords("iocSoft.db", "IOC={{prefix}}") dbLoadRecords("save_restoreStatus.db", "P={{prefix}}{{pv_delimiter}}") dbLoadRecords("caPutLog.db", "IOC=$(IOC)") -## TwinCAT task and application databases ## +## TwinCAT task, application, and project information databases ## {% for priority, (_, task) in plc.instance.task_pous.items() %} dbLoadRecords("TwinCAT_TaskInfo.db", "PORT=$(ASYN_PORT),PREFIX={{prefix}},IDX={{task.array_index}}") {% endfor %} dbLoadRecords("TwinCAT_AppInfo.db", "PORT=$(ASYN_PORT), PREFIX={{prefix}}") +dbLoadRecords("TwinCAT_Project.db", "PREFIX={{prefix}},PROJECT={{ project.filename.name }},HASH={{ project.git_info.sha }},VERSION={{ project.git_info.describe }},PYTMC={{ pytmc_version}},PLC_HOST={{ plc_host }}") + +{% for library, info in get_library_versions(plc) | dictsort %} +{%- set libraryname = library | replace(" ", "_") %} +{%- if "PlaceholderReference" in info and "PlaceholderResolution" in info %} +# {{ library }}: {{ info.PlaceholderReference.version }} -> {{ info.PlaceholderResolution.version }} ({{ info.PlaceholderResolution.vendor }}) +dbLoadRecords("TwinCAT_Dependency.db", "PREFIX={{prefix}},DEPENDENCY={{ libraryname }},VERSION={{ info.PlaceholderResolution.version }},VENDOR={{ info.PlaceholderResolution.vendor }}") +{% elif "PlaceholderReference" in info %} +# {{ library }}: {{ info.PlaceholderReference.version }} ({{ info.PlaceholderReference.vendor }}) +dbLoadRecords("TwinCAT_Dependency.db", "PREFIX={{prefix}},DEPENDENCY={{ libraryname }},VERSION={{ info.PlaceholderReference.version }},VENDOR={{ info.PlaceholderReference.vendor }}") +{% endif %} +{%- endfor %} + cd "$(IOC_TOP)" ## PLC Project Database files ## From 5715e169c65801dea74895cac1060deebd43394a Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Fri, 5 Aug 2022 09:31:13 -0700 Subject: [PATCH 20/35] ENH: allow for ams net ID override as well --- iocBoot/templates/Makefile.base | 3 +++ iocBoot/templates/Makefile.ioc | 11 +++++++---- iocBoot/templates/st.cmd.template | 18 ++++++++++++++---- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index 6dd1d7a..1622e13 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -34,6 +34,8 @@ QUEUE_SIZE_SCALE ?= 2 PV_DELIMITER ?= ':' # The PLC hostname which can be used in place of the auto-detected IP address: PLC_HOSTNAME ?= +# The PLC AMS Net ID which can be used in place of the auto-detected one: +PLC_AMS_NET_ID ?= # Ignore linter errors, if possible. This is disabled by default. IGNORE_LINTER_ERRORS ?= 0 # Add a PLC route automatically at startup @@ -92,6 +94,7 @@ st.cmd: _check_versions --macro queue_size_scale=$(QUEUE_SIZE_SCALE) \ --macro pv_delimiter=$(PV_DELIMITER) \ --macro plc_hostname_override='$(PLC_HOSTNAME)' \ + --macro plc_ams_net_id_override='$(PLC_AMS_NET_ID)' \ --macro ignore_linter_errors='$(IGNORE_LINTER_ERRORS)' \ --macro ioc_host_ip_regex='$(IOC_HOST_IP_REGEX)' \ --macro add_plc_route='$(ADD_PLC_ROUTE)' \ diff --git a/iocBoot/templates/Makefile.ioc b/iocBoot/templates/Makefile.ioc index ec21e81..75b8b07 100644 --- a/iocBoot/templates/Makefile.ioc +++ b/iocBoot/templates/Makefile.ioc @@ -11,12 +11,15 @@ PLC := {{ plc_name }} PYTMC_OPTS := PREFIX := PLC:$(PLC) -# If you know the netconfig name of the PLC, enter it here. If specified, this -# will be used in place of the auto-detected IP address from the PLC project: -PLC_HOSTNAME := - # With two $$, as in $$(IOC) below, this will be expanded in the # environment of st.cmd: DB_PARAMETERS := 'PREFIX=$(PREFIX):,IOCNAME=$$(IOC),IOC=$$(IOC)' +# If you know the netconfig name of the PLC, enter it here. If specified, this +# will be used in place of the auto-detected IP address from the PLC project: +PLC_HOSTNAME := +# You may also specify the AMS Net ID of the PLC, but it's usually OK to +# leave this blank as it can be found in the project: +PLC_AMS_NET_ID := + include $(IOC_TOP)/iocBoot/templates/Makefile.base diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index 79645d3..e708249 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -2,13 +2,23 @@ ################### AUTO-GENERATED DO NOT EDIT ################### {% set project, plc = get_plc_by_name(projects, plc) -%} {%- set plc_host = plc_hostname_override or plc.target_ip %} +{%- set plc_ams_net_id = plc_ams_net_id_override or plc.ams_id %} # # Project: {{ project.filename.name }} # PLC name: {{ plc.name }} ({{ plc.link_name }}) # Generated using: pytmc {{ pytmc_version}} # Project version: {{ project.git_info.describe }} # Project hash: {{ project.git_info.sha }} -# PLC IP/host: {{ plc.target_ip}} ({{ plc_hostname_override }}) +{% if plc_hostname_override %} +# PLC IP/host: {{ plc_hostname_override }} (Specified in Makefile; project has: {{ plc.target_ip }}) +{% else %} +# PLC IP/host: {{ plc.target_ip}} +{% endif %} +{% if plc_ams_net_id_override %} +# PLC Net ID: {{ plc_ams_net_id_override }} (Specified in Makefile; project has: {{ plc.ams_id }}) +{% else %} +# PLC Net ID: {{ plc.ams_id}} +{% endif %} # # Libraries: # @@ -59,9 +69,9 @@ dbLoadDatabase("$(ADS_IOC_TOP)/dbd/adsIoc.dbd") adsIoc_registerRecordDeviceDriver(pdbbase) epicsEnvSet("ASYN_PORT", "ASYN_PLC") -epicsEnvSet("IPADDR", "{{plc_host}}") -epicsEnvSet("AMSID", "{{plc.ams_id}}") -epicsEnvSet("AMS_PORT", "{{plc.port}}") +epicsEnvSet("IPADDR", "{{ plc_host }}") +epicsEnvSet("AMSID", "{{ plc_ams_net_id }}") +epicsEnvSet("AMS_PORT", "{{ plc.port }}") epicsEnvSet("ADS_MAX_PARAMS", "{{ max_params }}") epicsEnvSet("ADS_SAMPLE_MS", "50") epicsEnvSet("ADS_MAX_DELAY_MS", "100") From 194c00df77dd1bddababe6395dc92293a0bfde07 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Mon, 8 Aug 2022 15:02:58 -0700 Subject: [PATCH 21/35] REF: use hostname -I instead of dig +short --- scripts/add_route.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/add_route.sh b/scripts/add_route.sh index 85fad29..77e101c 100755 --- a/scripts/add_route.sh +++ b/scripts/add_route.sh @@ -61,7 +61,7 @@ find_ioc_ip() { exit 1 fi - for ipaddr in $(dig +short "$(hostname)"); do + for ipaddr in $(hostname -I); do if [[ "$ipaddr" =~ ${regex} ]]; then echo "$ipaddr" return From 19fe3a5f8ba27bdaa2d5c02fcaa27587883e8dc2 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Wed, 10 Aug 2022 13:35:22 -0700 Subject: [PATCH 22/35] REF: rework how production IOC mode works + update autosave path --- iocBoot/templates/Makefile.base | 29 ++++------------------ iocBoot/templates/st.cmd.template | 40 ++++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index 1622e13..aafa504 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -42,12 +42,8 @@ IGNORE_LINTER_ERRORS ?= 0 ADD_PLC_ROUTE ?= 1 # IOC host IP regular expression IOC_HOST_IP_REGEX ?= ^172.*$ - -ifeq ($(PRODUCTION_IOC), 1) - IOC_DATA_PATH ?= /cds/data/iocData -else - IOC_DATA_PATH ?= $(HOME)/iocData -endif +# This is where IOC data goes: +IOC_DATA_PATH ?= /cds/data/iocData ARCHIVE_PATH ?= $(IOC_DATA_PATH)/$(IOC_NAME)/archive BUILD_PATH ?= $(IOC_INSTANCE_PATH)/.pytmc_build @@ -55,14 +51,13 @@ DB_PARAMETERS ?= 'PREFIX=$(PREFIX):,IOCNAME=$$(IOC),IOC=$$(IOC)' # abspath is failing with spaces - falling back to Python here: pyabspath = $(shell python -c "import os, sys; print(os.path.abspath(os.path.expanduser(sys.argv[1])))" "$(1)" ) -all: build iocdata clean +all: build clean help: @echo "Available commands:" @echo " all: builds the IOC and cleans the temporary files" @echo " build: builds the st.cmd, databases, envPaths, etc." @echo " clean: cleans temporary pytmc files in $(BUILD_PATH)" - @echo " iocdata: create and/or update iocData directories (autosave, etc.)" @echo " lint: lint the pragmas" @echo " lintdb: lint the generated .db file against the IOC dbd" @echo " summary: tool shortcut - display a PLC project summary" @@ -98,6 +93,7 @@ st.cmd: _check_versions --macro ignore_linter_errors='$(IGNORE_LINTER_ERRORS)' \ --macro ioc_host_ip_regex='$(IOC_HOST_IP_REGEX)' \ --macro add_plc_route='$(ADD_PLC_ROUTE)' \ + --macro production_ioc='$(PRODUCTION_IOC)' \ --template "$(TEMPLATE_PATH)/$(STCMD_TEMPLATE)":"st.cmd" \ $(PYTMC_OPTS) \ $(PYTMC_TEMPLATE_OPTS) \ @@ -155,7 +151,6 @@ build: @echo "IOC name: $(IOC_NAME)" @echo "PYTMC_OPTS: $(PYTMC_OPTS)" @echo "PROJECT_PATH: $(PROJECT_PATH)" - @echo "ARCHIVE_PATH: $(ARCHIVE_PATH)" @echo "Absolute project path: " $(call pyabspath,$(PROJECT_PATH)) @echo "-----------------------------------------------------------" @echo "" @@ -182,20 +177,6 @@ clean: @echo "Done" -iocdata: - @echo "Creating IOC data directory" - install --mode 2775 --group ps-ioc --directory $(IOC_DATA_PATH)/$(IOC_NAME)/{iocInfo,archive,logs,autosave} - @echo "Creating autosave files directory" - install --mode 2775 --group ps-ioc --directory $(IOC_INSTANCE_PATH)/autosave - @shopt -s nullglob; \ - for filename in "$(IOC_INSTANCE_PATH)"/*.archive; \ - do \ - if [ -d "$(ARCHIVE_PATH)" ]; then \ - echo "* Installing archive file: $$(basename $$filename)"; \ - install -p -m 0444 "$$filename" "$(ARCHIVE_PATH)"; \ - fi; \ - done - lint: _check_versions @echo "Linting the pytmc pragmas. Use \`make $@ PYTMC_OPTS=...\` to pass args to pytmc." > /dev/stderr pytmc pragmalint "$(call pyabspath,$(PROJECT_PATH))" $(PYTMC_OPTS) @@ -234,4 +215,4 @@ types: _check_versions pytmc types "$(call pyabspath,$(PROJECT_PATH))" $(PYTMC_OPTS) -.PHONY: all _check_versions st.cmd db envPaths copy_build_output build clean iocdata lint lintdb summary code outline debug types +.PHONY: all _check_versions st.cmd db envPaths copy_build_output build clean lint lintdb summary code outline debug types diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index e708249..d00fb95 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -19,6 +19,7 @@ {% else %} # PLC Net ID: {{ plc.ams_id}} {% endif %} +# Production IOC: {{ production_ioc }} # # Libraries: # @@ -206,22 +207,39 @@ dbLoadRecords("{{ db.file }}", "PORT={{ asyn_port }},PREFIX={{prefix}}{{pv_delim {% endfor %} {% endif %} -# Setup autosave -set_savefile_path( "$(IOC_DATA)/$(IOC)/autosave" ) -set_requestfile_path( "$(IOC_TOP)/autosave" ) +# Autosave and archive settings: +save_restoreSet_status_prefix("{{prefix}}{{pv_delimiter}}") +save_restoreSet_IncompleteSetsOk(1) +save_restoreSet_DatedBackupFiles(1) +set_pass0_restoreFile("info_positions.sav") +set_pass1_restoreFile("info_settings.sav") -save_restoreSet_status_prefix( "{{prefix}}{{pv_delimiter}}" ) -save_restoreSet_IncompleteSetsOk( 1 ) -save_restoreSet_DatedBackupFiles( 1 ) -set_pass0_restoreFile( "info_positions.sav" ) -set_pass1_restoreFile( "info_settings.sav" ) +{% if production_ioc %} +# ** Production IOC Settings ** +set_savefile_path("$(IOC_DATA)/$(IOC)/autosave") +set_requestfile_path("$(IOC_DATA)/$(IOC)/autosave") -cd "$(IOC_TOP)/autosave" +# Production IOC autosave files go in iocData: +cd "$(IOC_DATA)/$(IOC)/autosave" + +# Create info_positions.req and info_settings.req makeAutosaveFiles() + +cd "$(IOC_DATA)/$(IOC)/archive" + +# Create $(IOC).archive +makeArchiveFromDbInfo("$(IOC).archive", "archive") +cd "$(IOC_TOP)" +{% else %} +# ** Development IOC Settings ** +# Development IOC autosave and archive files go in the IOC top directory: cd "$(IOC_TOP)" -# Create the archiver file -makeArchiveFromDbInfo("$(IOC_DATA)/$(IOC)/archive/$(IOC).archive", "archive") +# (Development mode) Create info_positions.req and info_settings.req +makeAutosaveFiles() +# (Development mode) Create the archiver file +makeArchiveFromDbInfo("$(IOC).archive", "archive") +{% endif %} # Configure access security: this is required for caPutLog. asSetFilename("$(ACF_FILE)") From ecd8a3f49e7258d36233784651a41e2270baea41 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Wed, 10 Aug 2022 14:38:10 -0700 Subject: [PATCH 23/35] FIX: production IOC flag --- iocBoot/templates/st.cmd.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index d00fb95..b33fc67 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -1,6 +1,7 @@ #!{{hashbang}} ################### AUTO-GENERATED DO NOT EDIT ################### -{% set project, plc = get_plc_by_name(projects, plc) -%} +{% set production_ioc = production_ioc | int %} +{%- set project, plc = get_plc_by_name(projects, plc) -%} {%- set plc_host = plc_hostname_override or plc.target_ip %} {%- set plc_ams_net_id = plc_ams_net_id_override or plc.ams_id %} # @@ -206,7 +207,6 @@ dbLoadRecords("{{ db.file }}", "PORT={{ asyn_port }},PREFIX={{prefix}}{{pv_delim {% endfor %} {% endif %} - # Autosave and archive settings: save_restoreSet_status_prefix("{{prefix}}{{pv_delimiter}}") save_restoreSet_IncompleteSetsOk(1) From 5f37b76e16e5ef24f7f6881e0eb19f496502aaa0 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Wed, 10 Aug 2022 15:21:57 -0700 Subject: [PATCH 24/35] FIX: dbloadrecords should use --- iocBoot/templates/st.cmd.template | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index b33fc67..20c5415 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -20,7 +20,14 @@ {% else %} # PLC Net ID: {{ plc.ams_id}} {% endif %} -# Production IOC: {{ production_ioc }} +{% if production_ioc %} +# ** Production mode IOC ** +# Using /cds/data/iocData for autosave and archiver settings. +{% else %} +# ** DEVELOPMENT MODE IOC ** +# * Using IOC boot directory for autosave. +# * Archiver settings will not be configured. +{% endif %} # # Libraries: # @@ -191,7 +198,7 @@ cd "$(IOC_TOP)" ## PLC Project Database files ## {% if plc.tmc %} {% for db in db_filenames %} -dbLoadRecords("{{ db }}", "PORT={{ asyn_port }},{{ db_parameters }}") +dbLoadRecords("{{ db }}", "PORT=$(ASYN_PORT},{{ db_parameters }}") {% endfor %} {%- set queue_size_base = queue_size_base | int %} {%- set queue_size_scale = queue_size_scale | int %} @@ -203,7 +210,7 @@ callbackSetQueueSize({{ callback_queue_size }}) {% if additional_db_files %} {% for db in additional_db_files %} -dbLoadRecords("{{ db.file }}", "PORT={{ asyn_port }},PREFIX={{prefix}}{{pv_delimiter}},IOCNAME=$(IOC),{{ db.macros }}") +dbLoadRecords("{{ db.file }}", "PORT=$(ASYN_PORT),PREFIX={{prefix}}{{pv_delimiter}},IOCNAME=$(IOC),{{ db.macros }}") {% endfor %} {% endif %} From 8c1ddc1037e42c3321179455ecbb9e15909a39c5 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Wed, 10 Aug 2022 15:22:04 -0700 Subject: [PATCH 25/35] FIX: DISP is 0 or 1 --- app/Db/TwinCAT_Dependency.db | 4 ++-- app/Db/TwinCAT_Project.db | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/Db/TwinCAT_Dependency.db b/app/Db/TwinCAT_Dependency.db index 5909e33..95312bc 100644 --- a/app/Db/TwinCAT_Dependency.db +++ b/app/Db/TwinCAT_Dependency.db @@ -1,5 +1,5 @@ record(lsi, "$(PREFIX):ProjectInfo:$(DEPENDENCY)") { - field(DISP, "TRUE") + field(DISP, "1") field(DTYP, "Soft Channel") field(PINI, "YES") field(SCAN, "Passive") @@ -8,7 +8,7 @@ record(lsi, "$(PREFIX):ProjectInfo:$(DEPENDENCY)") { } record(lsi, "$(PREFIX):ProjectInfo:$(DEPENDENCY):Vendor") { - field(DISP, "TRUE") + field(DISP, "1") field(DTYP, "Soft Channel") field(PINI, "YES") field(SCAN, "Passive") diff --git a/app/Db/TwinCAT_Project.db b/app/Db/TwinCAT_Project.db index 00675d0..bef0d44 100644 --- a/app/Db/TwinCAT_Project.db +++ b/app/Db/TwinCAT_Project.db @@ -1,5 +1,5 @@ record(lsi, "$(PREFIX):ProjectInfo:PLCHost") { - field(DISP, "TRUE") + field(DISP, "1") field(DTYP, "Soft Channel") field(PINI, "YES") field(SCAN, "Passive") @@ -8,7 +8,7 @@ record(lsi, "$(PREFIX):ProjectInfo:PLCHost") { } record(lsi, "$(PREFIX):ProjectInfo:Project") { - field(DISP, "TRUE") + field(DISP, "1") field(DTYP, "Soft Channel") field(PINI, "YES") field(SCAN, "Passive") @@ -17,7 +17,7 @@ record(lsi, "$(PREFIX):ProjectInfo:Project") { } record(lsi, "$(PREFIX):ProjectInfo:Hash") { - field(DISP, "TRUE") + field(DISP, "1") field(DTYP, "Soft Channel") field(PINI, "YES") field(SCAN, "Passive") @@ -26,7 +26,7 @@ record(lsi, "$(PREFIX):ProjectInfo:Hash") { } record(lsi, "$(PREFIX):ProjectInfo:Version") { - field(DISP, "TRUE") + field(DISP, "1") field(DTYP, "Soft Channel") field(PINI, "YES") field(SCAN, "Passive") @@ -35,7 +35,7 @@ record(lsi, "$(PREFIX):ProjectInfo:Version") { } record(lsi, "$(PREFIX):ProjectInfo:Pytmc") { - field(DISP, "TRUE") + field(DISP, "1") field(DTYP, "Soft Channel") field(PINI, "YES") field(SCAN, "Passive") From 6fb886d0686c955b233ec072b984b3a20fb1f0cb Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Wed, 10 Aug 2022 15:41:08 -0700 Subject: [PATCH 26/35] MNT: switch lsi -> stringout for now --- app/Db/TwinCAT_Dependency.db | 4 ++-- app/Db/TwinCAT_Project.db | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/Db/TwinCAT_Dependency.db b/app/Db/TwinCAT_Dependency.db index 95312bc..87d5526 100644 --- a/app/Db/TwinCAT_Dependency.db +++ b/app/Db/TwinCAT_Dependency.db @@ -1,4 +1,4 @@ -record(lsi, "$(PREFIX):ProjectInfo:$(DEPENDENCY)") { +record(stringout, "$(PREFIX):ProjectInfo:$(DEPENDENCY)") { field(DISP, "1") field(DTYP, "Soft Channel") field(PINI, "YES") @@ -7,7 +7,7 @@ record(lsi, "$(PREFIX):ProjectInfo:$(DEPENDENCY)") { info(archive, "monitor 1: VAL") } -record(lsi, "$(PREFIX):ProjectInfo:$(DEPENDENCY):Vendor") { +record(stringout, "$(PREFIX):ProjectInfo:$(DEPENDENCY):Vendor") { field(DISP, "1") field(DTYP, "Soft Channel") field(PINI, "YES") diff --git a/app/Db/TwinCAT_Project.db b/app/Db/TwinCAT_Project.db index bef0d44..a0621ed 100644 --- a/app/Db/TwinCAT_Project.db +++ b/app/Db/TwinCAT_Project.db @@ -1,4 +1,4 @@ -record(lsi, "$(PREFIX):ProjectInfo:PLCHost") { +record(stringout, "$(PREFIX):ProjectInfo:PLCHost") { field(DISP, "1") field(DTYP, "Soft Channel") field(PINI, "YES") @@ -7,7 +7,7 @@ record(lsi, "$(PREFIX):ProjectInfo:PLCHost") { info(archive, "monitor 1: VAL") } -record(lsi, "$(PREFIX):ProjectInfo:Project") { +record(stringout, "$(PREFIX):ProjectInfo:Project") { field(DISP, "1") field(DTYP, "Soft Channel") field(PINI, "YES") @@ -16,7 +16,7 @@ record(lsi, "$(PREFIX):ProjectInfo:Project") { info(archive, "monitor 1: VAL") } -record(lsi, "$(PREFIX):ProjectInfo:Hash") { +record(stringout, "$(PREFIX):ProjectInfo:Hash") { field(DISP, "1") field(DTYP, "Soft Channel") field(PINI, "YES") @@ -25,7 +25,7 @@ record(lsi, "$(PREFIX):ProjectInfo:Hash") { info(archive, "monitor 1: VAL") } -record(lsi, "$(PREFIX):ProjectInfo:Version") { +record(stringout, "$(PREFIX):ProjectInfo:Version") { field(DISP, "1") field(DTYP, "Soft Channel") field(PINI, "YES") @@ -34,7 +34,7 @@ record(lsi, "$(PREFIX):ProjectInfo:Version") { info(archive, "monitor 1: VAL") } -record(lsi, "$(PREFIX):ProjectInfo:Pytmc") { +record(stringout, "$(PREFIX):ProjectInfo:Pytmc") { field(DISP, "1") field(DTYP, "Soft Channel") field(PINI, "YES") From fd6193f89754aa3a1065d1c46cad9ef0f7ad66da Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Wed, 10 Aug 2022 15:41:36 -0700 Subject: [PATCH 27/35] MNT: use short hash for regular stringout --- iocBoot/templates/st.cmd.template | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index 20c5415..aba24e8 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -1,6 +1,8 @@ #!{{hashbang}} ################### AUTO-GENERATED DO NOT EDIT ################### {% set production_ioc = production_ioc | int %} +{%- set git_sha = project.git_info.sha or "" %} +{%- set short_git_sha = git_sha[:7] %} {%- set project, plc = get_plc_by_name(projects, plc) -%} {%- set plc_host = plc_hostname_override or plc.target_ip %} {%- set plc_ams_net_id = plc_ams_net_id_override or plc.ams_id %} @@ -180,7 +182,7 @@ dbLoadRecords("TwinCAT_TaskInfo.db", "PORT=$(ASYN_PORT),PREFIX={{prefix}},IDX={{ {% endfor %} dbLoadRecords("TwinCAT_AppInfo.db", "PORT=$(ASYN_PORT), PREFIX={{prefix}}") -dbLoadRecords("TwinCAT_Project.db", "PREFIX={{prefix}},PROJECT={{ project.filename.name }},HASH={{ project.git_info.sha }},VERSION={{ project.git_info.describe }},PYTMC={{ pytmc_version}},PLC_HOST={{ plc_host }}") +dbLoadRecords("TwinCAT_Project.db", "PREFIX={{prefix}},PROJECT={{ project.filename.name }},HASH={{ short_git_sha }},VERSION={{ project.git_info.describe }},PYTMC={{ pytmc_version}},PLC_HOST={{ plc_host }}") {% for library, info in get_library_versions(plc) | dictsort %} {%- set libraryname = library | replace(" ", "_") %} @@ -198,7 +200,7 @@ cd "$(IOC_TOP)" ## PLC Project Database files ## {% if plc.tmc %} {% for db in db_filenames %} -dbLoadRecords("{{ db }}", "PORT=$(ASYN_PORT},{{ db_parameters }}") +dbLoadRecords("{{ db }}", "PORT=$(ASYN_PORT),{{ db_parameters }}") {% endfor %} {%- set queue_size_base = queue_size_base | int %} {%- set queue_size_scale = queue_size_scale | int %} From a54887df2d8a0ff205e452350568fd8333c6d2ec Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Wed, 10 Aug 2022 15:55:18 -0700 Subject: [PATCH 28/35] FIX: short git hash + run system() *after* dbLoadDatabase --- iocBoot/templates/st.cmd.template | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index aba24e8..e049447 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -1,8 +1,6 @@ #!{{hashbang}} ################### AUTO-GENERATED DO NOT EDIT ################### {% set production_ioc = production_ioc | int %} -{%- set git_sha = project.git_info.sha or "" %} -{%- set short_git_sha = git_sha[:7] %} {%- set project, plc = get_plc_by_name(projects, plc) -%} {%- set plc_host = plc_hostname_override or plc.target_ip %} {%- set plc_ams_net_id = plc_ams_net_id_override or plc.ams_id %} @@ -62,11 +60,6 @@ epicsEnvSet("ADS_IOC_TOP", "$(TOP)" ) -{% if add_plc_route | int != 0 %} -# Add a route to the PLC automatically: -system("${ADS_IOC_TOP}/scripts/add_route.sh {{ plc_host }} {{ ioc_host_ip_regex }}") - -{% endif %} epicsEnvSet("ENGINEER", "{{user}}" ) epicsEnvSet("LOCATION", "{{prefix}}" ) epicsEnvSet("IOCSH_PS1", "$(IOC)> " ) @@ -89,6 +82,11 @@ epicsEnvSet("ADS_MAX_DELAY_MS", "100") epicsEnvSet("ADS_TIMEOUT_MS", "1000") epicsEnvSet("ADS_TIME_SOURCE", "0") +{% if add_plc_route | int != 0 %} +# Add a route to the PLC automatically: +system("${ADS_IOC_TOP}/scripts/add_route.sh {{ plc_host }} {{ ioc_host_ip_regex }}") + +{% endif %} # adsAsynPortDriverConfigure(portName, ipaddr, amsaddr, amsport, # asynParamTableSize, priority, noAutoConnect, defaultSampleTimeMS, # maxDelayTimeMS, adsTimeoutMS, defaultTimeSource) @@ -182,6 +180,8 @@ dbLoadRecords("TwinCAT_TaskInfo.db", "PORT=$(ASYN_PORT),PREFIX={{prefix}},IDX={{ {% endfor %} dbLoadRecords("TwinCAT_AppInfo.db", "PORT=$(ASYN_PORT), PREFIX={{prefix}}") +{% set git_sha = project.git_info.sha or "" %} +{%- set short_git_sha = git_sha[:7] %} dbLoadRecords("TwinCAT_Project.db", "PREFIX={{prefix}},PROJECT={{ project.filename.name }},HASH={{ short_git_sha }},VERSION={{ project.git_info.describe }},PYTMC={{ pytmc_version}},PLC_HOST={{ plc_host }}") {% for library, info in get_library_versions(plc) | dictsort %} From 184e609c5c4c02310fbd22071ad13d145256ffa8 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Thu, 11 Aug 2022 09:02:57 -0700 Subject: [PATCH 29/35] FIX: only set IOC if not set in environment --- iocBoot/templates/Makefile.base | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index aafa504..038010b 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -22,7 +22,7 @@ DBD_PATH ?= $(IOC_TOP)/dbd/adsIoc.dbd PROJECT_PATH ?= $(IOC_INSTANCE_PATH)/../../$(PROJECT_NAME)/$(PROJECT_NAME).tsproj TEMPLATE_PATH ?= $(IOC_TOP)/iocBoot/templates STCMD_TEMPLATE ?= st.cmd.template -IOC_NAME := $(shell basename "$(IOC_INSTANCE_PATH)") +ADS_IOC_NAME := $(shell basename "$(IOC_INSTANCE_PATH)") PRODUCTION_IOC ?= 0 PYTMC_MIN_VERSION ?= 2.13.0 # <-- TODO update before merging # The minimum callback queue size for EPICS IOCs: @@ -44,9 +44,10 @@ ADD_PLC_ROUTE ?= 1 IOC_HOST_IP_REGEX ?= ^172.*$ # This is where IOC data goes: IOC_DATA_PATH ?= /cds/data/iocData - -ARCHIVE_PATH ?= $(IOC_DATA_PATH)/$(IOC_NAME)/archive +# This is where the scripts and database are built: BUILD_PATH ?= $(IOC_INSTANCE_PATH)/.pytmc_build +# This is the default set of macro parameters used for all database files, +# including $PREFIX, $IOCNAME, and $IOC. DB_PARAMETERS ?= 'PREFIX=$(PREFIX):,IOCNAME=$$(IOC),IOC=$$(IOC)' # abspath is failing with spaces - falling back to Python here: pyabspath = $(shell python -c "import os, sys; print(os.path.abspath(os.path.expanduser(sys.argv[1])))" "$(1)" ) @@ -81,7 +82,7 @@ st.cmd: _check_versions pytmc template \ --macro prefix="$(PREFIX)" \ --macro plc="$(PLC)" \ - --macro ioc_name="$(IOC_NAME)" \ + --macro ads_ioc_name="$(ADS_IOC_NAME)" \ --macro user="$(USER)" \ --macro hashbang="$(BINARY_PATH)" \ --macro db_parameters=$(DB_PARAMETERS) \ @@ -109,9 +110,9 @@ db: _check_versions "$(PLC).db" envPaths: - @echo "* Copying envPaths and fixing IOC_TOP..." + @echo "* Copying envPaths and fixing variables..." @cat "$(TEMPLATE_PATH)"/envPaths | \ - sed -e 's/^epicsEnvSet("IOC",.*)/epicsEnvSet("IOC","$(IOC_NAME)")/' \ + sed -e 's/^epicsEnvSet("IOC",.*)/epicsEnvSet("IOC","$${IOC=$(ADS_IOC_NAME)}")/' \ > "$(IOC_INSTANCE_PATH)"/envPaths @echo 'epicsEnvSet("IOC_TOP", "$(IOC_INSTANCE_PATH)")' >> "$(IOC_INSTANCE_PATH)"/envPaths @echo 'epicsEnvSet("IOC_DATA", "$(IOC_DATA_PATH)")' >> "$(IOC_INSTANCE_PATH)"/envPaths @@ -148,7 +149,7 @@ build: @echo "-----------------------------------------------------------" @echo "Build path: $(BUILD_PATH)" @echo "PLC: $(PLC)" - @echo "IOC name: $(IOC_NAME)" + @echo "IOC name: $(ADS_IOC_NAME) (* Does this match IOC Manager? *)" @echo "PYTMC_OPTS: $(PYTMC_OPTS)" @echo "PROJECT_PATH: $(PROJECT_PATH)" @echo "Absolute project path: " $(call pyabspath,$(PROJECT_PATH)) From c521709aaef85d4257aad1f92932640297dbb404 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Thu, 11 Aug 2022 09:37:27 -0700 Subject: [PATCH 30/35] REF: switch back stringout->lsi + use correct syntax --- app/Db/TwinCAT_Dependency.db | 14 ++++++-------- app/Db/TwinCAT_Project.db | 25 ++++++++++--------------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/app/Db/TwinCAT_Dependency.db b/app/Db/TwinCAT_Dependency.db index 87d5526..7708f6d 100644 --- a/app/Db/TwinCAT_Dependency.db +++ b/app/Db/TwinCAT_Dependency.db @@ -1,17 +1,15 @@ -record(stringout, "$(PREFIX):ProjectInfo:$(DEPENDENCY)") { - field(DISP, "1") +record(lsi, "$(PREFIX):ProjectInfo:$(DEPENDENCY)") { + field(DISP, 1) field(DTYP, "Soft Channel") + field(INP, ["$(VERSION) -> $(VENDOR)"]) field(PINI, "YES") - field(SCAN, "Passive") - field(VAL, "$(VERSION) -> $(VENDOR)") info(archive, "monitor 1: VAL") } -record(stringout, "$(PREFIX):ProjectInfo:$(DEPENDENCY):Vendor") { - field(DISP, "1") +record(lsi, "$(PREFIX):ProjectInfo:$(DEPENDENCY):Vendor") { + field(DISP, 1) field(DTYP, "Soft Channel") + field(INP, ["$(VENDOR)"]) field(PINI, "YES") - field(SCAN, "Passive") - field(VAL, "$(VENDOR)") info(archive, "monitor 1: VAL") } diff --git a/app/Db/TwinCAT_Project.db b/app/Db/TwinCAT_Project.db index a0621ed..6d8ebda 100644 --- a/app/Db/TwinCAT_Project.db +++ b/app/Db/TwinCAT_Project.db @@ -1,44 +1,39 @@ -record(stringout, "$(PREFIX):ProjectInfo:PLCHost") { +record(lsi, "$(PREFIX):ProjectInfo:PLCHost") { field(DISP, "1") field(DTYP, "Soft Channel") + field(INP, ["$(PLC_HOST)"]) field(PINI, "YES") - field(SCAN, "Passive") - field(VAL, "$(PLC_HOST)") info(archive, "monitor 1: VAL") } -record(stringout, "$(PREFIX):ProjectInfo:Project") { +record(lsi, "$(PREFIX):ProjectInfo:Project") { field(DISP, "1") field(DTYP, "Soft Channel") + field(INP, ["$(PROJECT)"]) field(PINI, "YES") - field(SCAN, "Passive") - field(VAL, "$(PROJECT)") info(archive, "monitor 1: VAL") } -record(stringout, "$(PREFIX):ProjectInfo:Hash") { +record(lsi, "$(PREFIX):ProjectInfo:Hash") { field(DISP, "1") field(DTYP, "Soft Channel") + field(INP, ["$(HASH)"]) field(PINI, "YES") - field(SCAN, "Passive") - field(VAL, "$(HASH)") info(archive, "monitor 1: VAL") } -record(stringout, "$(PREFIX):ProjectInfo:Version") { +record(lsi, "$(PREFIX):ProjectInfo:Version") { field(DISP, "1") field(DTYP, "Soft Channel") + field(INP, ["$(VERSION)"]) field(PINI, "YES") - field(SCAN, "Passive") - field(VAL, "$(VERSION)") info(archive, "monitor 1: VAL") } -record(stringout, "$(PREFIX):ProjectInfo:Pytmc") { +record(lsi, "$(PREFIX):ProjectInfo:Pytmc") { field(DISP, "1") field(DTYP, "Soft Channel") + field(INP, ["$(PYTMC)"]) field(PINI, "YES") - field(SCAN, "Passive") - field(VAL, "$(PYTMC)") info(archive, "monitor 1: VAL") } From 2eda3fd7625217382aef860173ca67297e0d3222 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Thu, 11 Aug 2022 13:58:29 -0700 Subject: [PATCH 31/35] MNT: increase length of a few select lsi records --- app/Db/TwinCAT_Dependency.db | 2 ++ app/Db/TwinCAT_Project.db | 1 + 2 files changed, 3 insertions(+) diff --git a/app/Db/TwinCAT_Dependency.db b/app/Db/TwinCAT_Dependency.db index 7708f6d..a8578d6 100644 --- a/app/Db/TwinCAT_Dependency.db +++ b/app/Db/TwinCAT_Dependency.db @@ -3,6 +3,7 @@ record(lsi, "$(PREFIX):ProjectInfo:$(DEPENDENCY)") { field(DTYP, "Soft Channel") field(INP, ["$(VERSION) -> $(VENDOR)"]) field(PINI, "YES") + field(SIZV, 100) info(archive, "monitor 1: VAL") } @@ -11,5 +12,6 @@ record(lsi, "$(PREFIX):ProjectInfo:$(DEPENDENCY):Vendor") { field(DTYP, "Soft Channel") field(INP, ["$(VENDOR)"]) field(PINI, "YES") + field(SIZV, 100) info(archive, "monitor 1: VAL") } diff --git a/app/Db/TwinCAT_Project.db b/app/Db/TwinCAT_Project.db index 6d8ebda..93e3518 100644 --- a/app/Db/TwinCAT_Project.db +++ b/app/Db/TwinCAT_Project.db @@ -19,6 +19,7 @@ record(lsi, "$(PREFIX):ProjectInfo:Hash") { field(DTYP, "Soft Channel") field(INP, ["$(HASH)"]) field(PINI, "YES") + field(SIZV, 100) info(archive, "monitor 1: VAL") } From e300e3193388da6aa126ef9f93cee1ac46fa93de Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Mon, 15 Aug 2022 15:23:17 -0700 Subject: [PATCH 32/35] MNT: support _DEPENDENCY_CHECK_ for whatrecord --- configure/RELEASE | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configure/RELEASE b/configure/RELEASE index fd125e2..fdab345 100644 --- a/configure/RELEASE +++ b/configure/RELEASE @@ -42,6 +42,9 @@ CAPUTLOG=$(EPICS_MODULES)/caPutLog/$(CAPUTLOG_MODULE_VERSION) # =============================================================== EPICS_BASE=$(EPICS_SITE_TOP)/base/$(BASE_MODULE_VERSION) +# Set externally by tools that want to introspect Makefiles: +ifneq ($(_DEPENDENCY_CHECK_),1) + # Check for valid EPICS_BASE ifeq ($(wildcard $(EPICS_BASE)/include),) $(error Invalid EPICS_BASE: $(EPICS_BASE)/include) @@ -75,3 +78,5 @@ endif ifeq ($(wildcard $(CAPUTLOG)/lib/$(T_A)),) $(error Invalid CAPUTLOG: $(CAPUTLOG)/lib/$(T_A)) endif + +endif From 7163aab4f78c945268ca8ee78d358f833757a587 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Mon, 29 Aug 2022 13:32:50 -0700 Subject: [PATCH 33/35] MNT: bump required pytmc version --- iocBoot/templates/Makefile.base | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index 038010b..f5988f8 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -24,7 +24,7 @@ TEMPLATE_PATH ?= $(IOC_TOP)/iocBoot/templates STCMD_TEMPLATE ?= st.cmd.template ADS_IOC_NAME := $(shell basename "$(IOC_INSTANCE_PATH)") PRODUCTION_IOC ?= 0 -PYTMC_MIN_VERSION ?= 2.13.0 # <-- TODO update before merging +PYTMC_MIN_VERSION ?= 2.14.0 # The minimum callback queue size for EPICS IOCs: QUEUE_SIZE_BASE ?= 2000 # Additional records generated from the PLC project will increase the callback From 6a1ece9c7f4cb17063fe053dc731ce704c6e4b80 Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Mon, 29 Aug 2022 13:33:03 -0700 Subject: [PATCH 34/35] FIX: only run pre/post IOC scripts in production mode --- iocBoot/templates/st.cmd.template | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index e049447..f783d5d 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -65,9 +65,11 @@ epicsEnvSet("LOCATION", "{{prefix}}" ) epicsEnvSet("IOCSH_PS1", "$(IOC)> " ) epicsEnvSet("ACF_FILE", "$(ADS_IOC_TOP)/iocBoot/templates/unrestricted.acf") +{% if production_ioc %} # Run common startup commands for linux soft IOC's < /reg/d/iocCommon/All/pre_linux.cmd +{% endif %} # Register all support components dbLoadDatabase("$(ADS_IOC_TOP)/dbd/adsIoc.dbd") adsIoc_registerRecordDeviceDriver(pdbbase) @@ -273,6 +275,8 @@ caPutLogInit("$(EPICS_CAPUTLOG_HOST):$(EPICS_CAPUTLOG_PORT)", 0) # Start autosave backups create_monitor_set( "info_positions.req", 10, "" ) create_monitor_set( "info_settings.req", 60, "" ) +{% if production_ioc %} # All IOCs should dump some common info after initial startup. < /reg/d/iocCommon/All/post_linux.cmd +{% endif %} From 5c8d65aab8bde7f296332a946784c80ffa49902a Mon Sep 17 00:00:00 2001 From: Ken Lauer Date: Mon, 29 Aug 2022 13:47:05 -0700 Subject: [PATCH 35/35] ENH: last-minute support for additional user-specified db files --- iocBoot/templates/Makefile.base | 3 +++ iocBoot/templates/st.cmd.template | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/iocBoot/templates/Makefile.base b/iocBoot/templates/Makefile.base index f5988f8..a18ca42 100644 --- a/iocBoot/templates/Makefile.base +++ b/iocBoot/templates/Makefile.base @@ -49,6 +49,8 @@ BUILD_PATH ?= $(IOC_INSTANCE_PATH)/.pytmc_build # This is the default set of macro parameters used for all database files, # including $PREFIX, $IOCNAME, and $IOC. DB_PARAMETERS ?= 'PREFIX=$(PREFIX):,IOCNAME=$$(IOC),IOC=$$(IOC)' +# Additional database files can be specified in this space-delimited list: +ADDITIONAL_DB_FILES ?= # abspath is failing with spaces - falling back to Python here: pyabspath = $(shell python -c "import os, sys; print(os.path.abspath(os.path.expanduser(sys.argv[1])))" "$(1)" ) @@ -95,6 +97,7 @@ st.cmd: _check_versions --macro ioc_host_ip_regex='$(IOC_HOST_IP_REGEX)' \ --macro add_plc_route='$(ADD_PLC_ROUTE)' \ --macro production_ioc='$(PRODUCTION_IOC)' \ + --macro additional_db_files='$(ADDITIONAL_DB_FILES)' \ --template "$(TEMPLATE_PATH)/$(STCMD_TEMPLATE)":"st.cmd" \ $(PYTMC_OPTS) \ $(PYTMC_TEMPLATE_OPTS) \ diff --git a/iocBoot/templates/st.cmd.template b/iocBoot/templates/st.cmd.template index f783d5d..0732511 100644 --- a/iocBoot/templates/st.cmd.template +++ b/iocBoot/templates/st.cmd.template @@ -213,10 +213,11 @@ callbackSetQueueSize({{ callback_queue_size }}) {% endif %} {% if additional_db_files %} -{% for db in additional_db_files %} -dbLoadRecords("{{ db.file }}", "PORT=$(ASYN_PORT),PREFIX={{prefix}}{{pv_delimiter}},IOCNAME=$(IOC),{{ db.macros }}") - +{% for db in additional_db_files.split(" ") %} +# Load user-specified database: {{ db }} +dbLoadRecords("{{ db }}", "PORT=$(ASYN_PORT),{{ db_parameters }}") {% endfor %} + {% endif %} # Autosave and archive settings: save_restoreSet_status_prefix("{{prefix}}{{pv_delimiter}}")