Command-line Usage

Using pytmc

Once pytmc has been installed in a virtual environment the pytmc command can be called from the command line to generate .db files and more.

pytmc db

“pytmc-db” is a command line utility for generating epics records files from TwinCAT3 .tmc files. This program is designed to work in conjunction with ESS’s m-epics-twincat-ads driver.

usage: pytmc db [-h] [--dbd DBD] [--allow-errors] [--no-error-context]
                [--plc PLC] [--debug]
                [--archive-file ARCHIVE_FILE | --no-archive-file]
                INPUT [OUTPUT]

Positional Arguments

INPUT

Path to interpreted .tmc file, or a .tsproj project

OUTPUT

Path to output .db file

Default: <_io.TextIOWrapper name=’<stdout>’ mode=’w’ encoding=’utf-8’>

Named Arguments

--dbd, -d

Specify an expanded .dbd file for validating fields (requires pyPDB)

--allow-errors, -i

Generate the .db file even if linter issues are found

Default: False

--no-error-context

Do not show db file context around errors

Default: False

--plc

The PLC name, if specifying a .tsproj file

--debug

Raise exceptions immediately, such that the IPython debugger may be used

Default: False

--archive-file

Save an archive configuration file. Defaults to OUTPUT.archive if specified

--no-archive-file

Do not write the archive file, regardless of OUTPUT filename settings.

Default: False

pytmc stcmd

“pytmc-stcmd” is a command line utility for generating ESS/ethercatmc-capable EPICS startup st.cmd files directly from TwinCAT3 .tsproj projects.

Relies on the existence (and linking) of FB_MotionStage function blocks.

usage: pytmc stcmd [-h] [--plc PLC_NAME] [-p PREFIX] [--hashbang HASHBANG]
                   [--binary BINARY_NAME] [-n NAME] [--only-motor]
                   [--db-path DB_PATH] [--dbd DBD] [--delim DELIM] [--debug]
                   [--template TEMPLATE_FILENAME]
                   [--template-path TEMPLATE_PATH] [--allow-errors]
                   tsproj_project

Positional Arguments

tsproj_project

Path to .tsproj project

Named Arguments

--plc

PLC project name, if multiple exist

-p, --prefix

PV prefix for the IOC

--hashbang

Indicates to the shell which binary to use for the st.cmd script

Default: “../../bin/rhel7-x86_64/adsIoc”

--binary

IOC application binary name

Default: “adsIoc”

-n, --name

IOC name (defaults to project name)

--only-motor

Parse the project only for motor records, skipping other variables with pytmc pragmas

Default: False

--db-path

Path for db files

Default: “.”

--dbd

Path to the IOC dbd file

--delim

Preferred PV delimiter

Default: “:”

--debug, -d

Post-stcmd, open an interactive Python session

Default: False

--template

st.cmd Jinja2 template

Default: “stcmd_default.cmd”

--template-path

Location where templates are stored

Default: “.”

--allow-errors

Allow non-fatal errors to be ignored

Default: False

pytmc xmltranslate

Tool for making XML-formatted files human-readable

Output uses the following rules: For a line of xml that appears as the following: <tag attr=qual…> text </tag> tail

Note that tail takes precedence over text.

This program will output the following: {attrs:qual…} tag text tail

Tags contained by other tags are indented and printed on the following line.

This tool was created for exploring .tpy files but is well suited to reading any xml formatted file.

usage: pytmc xmltranslate [-h] [-d DEPTH] [-i INDENT_SIZE] input_file

Positional Arguments

input_file

input file

Named Arguments

-d, --depth

Recursive limit for exploring the file

Default: 7

-i, --indent_size

Indent size for output formatting

Default: 4

pytmc debug

“pytmc-debug” is a Qt interface that shows information about how pytmc interprets TwinCAT3 .tmc files.

usage: pytmc debug [-h] [-d DBD] [-a] INPUT

Positional Arguments

INPUT

Path to .tmc file

Named Arguments

-d, --dbd

Specify an expanded .dbd file for validating fields (requires pyPDB)

-a, --allow-no-pragma

Show all items, even those missing pragmas (warning: slow)

Default: False

pytmc pragmalint

“pytmc pragmalint” is a command line utility for linting PyTMC pragmas in a given TwinCAT project or source code file

usage: pytmc pragmalint [-h] [--markdown] [--verbose] filename

Positional Arguments

filename

Path to .tsproj project or source code file

Named Arguments

--markdown

Make output more markdown-friendly, for easier sharing

Default: False

--verbose, -v

Show all pragmas, including good ones

Default: False

pytmc stcmd

“pytmc-stcmd” is a command line utility for generating ESS/ethercatmc-capable EPICS startup st.cmd files directly from TwinCAT3 .tsproj projects.

Relies on the existence (and linking) of FB_MotionStage function blocks.

usage: pytmc stcmd [-h] [--plc PLC_NAME] [-p PREFIX] [--hashbang HASHBANG]
                   [--binary BINARY_NAME] [-n NAME] [--only-motor]
                   [--db-path DB_PATH] [--dbd DBD] [--delim DELIM] [--debug]
                   [--template TEMPLATE_FILENAME]
                   [--template-path TEMPLATE_PATH] [--allow-errors]
                   tsproj_project

Positional Arguments

tsproj_project

Path to .tsproj project

Named Arguments

--plc

PLC project name, if multiple exist

-p, --prefix

PV prefix for the IOC

--hashbang

Indicates to the shell which binary to use for the st.cmd script

Default: “../../bin/rhel7-x86_64/adsIoc”

--binary

IOC application binary name

Default: “adsIoc”

-n, --name

IOC name (defaults to project name)

--only-motor

Parse the project only for motor records, skipping other variables with pytmc pragmas

Default: False

--db-path

Path for db files

Default: “.”

--dbd

Path to the IOC dbd file

--delim

Preferred PV delimiter

Default: “:”

--debug, -d

Post-stcmd, open an interactive Python session

Default: False

--template

st.cmd Jinja2 template

Default: “stcmd_default.cmd”

--template-path

Location where templates are stored

Default: “.”

--allow-errors

Allow non-fatal errors to be ignored

Default: False

pytmc summary

“pytmc-summary” is a command line utility for inspecting TwinCAT3 .tsproj projects.

usage: pytmc summary [-h] [--all] [--outline] [--boxes] [--code] [--plcs]
                     [--nc] [--symbols] [--types]
                     [--filter-types FILTER_TYPES] [--links] [--markdown]
                     [--debug]
                     filename

Positional Arguments

filename

Path to project or solution (.tsproj, .sln)

Named Arguments

--all, -a

All possible information

Default: False

--outline

Outline XML

Default: False

--boxes, -b

Show boxes

Default: False

--code, -c

Show code

Default: False

--plcs, -p

Show plcs

Default: False

--nc, -n

Show NC axes

Default: False

--symbols, -s

Show symbols

Default: False

--types

Show TMC types and record suffixes, if available

Default: False

--filter-types

Filter the types shown by name

--links, -l

Show links

Default: False

--markdown

Make output more markdown-friendly, for easier sharing

Default: False

--debug, -d

Post-summary, open an interactive Python session

Default: False

pytmc template

“pytmc template” is a command line utility to expand a template based on a TwinCAT3 project (or XML-format file such as .TMC).

The template file is expected to be in Jinja template format.

The following dictionaries are available in the template context:

solutions - {solution_filename: [project_fn: {...}, ...], ...}
projects - {project_filename: {...}, ...}
others - {filename: {...}, ...}

If installed and available, git_info will be available on each project.

The following helpers are available in the environment:

config_to_pragma
data_type_to_record_info
determine_block_type
element_to_class_name
enumerate_types
generate_records
get_boxes
get_data_type_by_reference
get_data_types
get_library_versions
get_links
get_linter_results
get_motors
get_nc
get_plc_by_name
get_pou_call_blocks
get_symbols
get_symbols_by_type
list_types
max
min
separate_by_classname

And the following filters:

epics_prefix
epics_suffix
pragma
title_fill

And the following variables:

pytmc_version
types

usage: pytmc template [-h] [-t TEMPLATES] [--macro MACROS] [--debug]
                      projects [projects ...]

Positional Arguments

projects

Path to project or solution (.tsproj, .sln)

Named Arguments

-t, --template

Template filename with optional output filename. In the form input_filename[:output_filename].Defaults to ‘-’ (standard input -> standard output).

--macro, -m

Define a macro for the template in the form MACRO=VALUE

--debug, -d

Post template generation, open an interactive Python session

Default: False

pytmc types

“pytmc-types” is a Qt interface that shows DataType-related information from a tmc file.

usage: pytmc types [-h] INPUT

Positional Arguments

INPUT

Path to .tmc file

Templates

stcmd_default.cmd

#!{{hashbang}}

< envPaths
epicsEnvSet("IOCNAME", "{{name}}" )
epicsEnvSet("ENGINEER", "{{user}}" )
epicsEnvSet("LOCATION", "{{prefix}}" )
epicsEnvSet("IOCSH_PS1", "$(IOCNAME)> " )

cd "$(TOP)"

# Run common startup commands for linux soft IOC's
< /reg/d/iocCommon/All/pre_linux.cmd

# Register all support components
dbLoadDatabase("dbd/{{binary_name}}.dbd")
{{binary_name}}_registerRecordDeviceDriver(pdbbase)

cd "$(TOP)/db"

epicsEnvSet("ASYN_PORT",     "{{asyn_port}}")
epicsEnvSet("IPADDR",        "{{plc_ip}}")
epicsEnvSet("AMSID",         "{{plc_ams_id}}")
epicsEnvSet("IPPORT",        "{{plc_ads_port}}")

adsAsynPortDriverConfigure("$(ASYN_PORT)","$(IPADDR)","$(AMSID)","$(IPPORT)", 1000, 0, 0, 50, 100, 1000, 0)

{% if motors %}
epicsEnvSet("MOTOR_PORT",    "{{motor_port}}")
epicsEnvSet("PREFIX",        "{{prefix}}{{delim}}")
epicsEnvSet("ECM_NUMAXES",   "{{motors|length}}")
epicsEnvSet("NUMAXES",       "{{motors|length}}")

EthercatMCCreateController("$(MOTOR_PORT)", "$(ASYN_PORT)", "$(NUMAXES)", "200", "1000")

#define ASYN_TRACE_ERROR     0x0001
#define ASYN_TRACEIO_DEVICE  0x0002
#define ASYN_TRACEIO_FILTER  0x0004
#define ASYN_TRACEIO_DRIVER  0x0008
#define ASYN_TRACE_FLOW      0x0010
#define ASYN_TRACE_WARNING   0x0020
#define ASYN_TRACE_INFO      0x0040
asynSetTraceMask("$(ASYN_PORT)", -1, 0x41)

#define ASYN_TRACEIO_NODATA 0x0000
#define ASYN_TRACEIO_ASCII  0x0001
#define ASYN_TRACEIO_ESCAPE 0x0002
#define ASYN_TRACEIO_HEX    0x0004
asynSetTraceIOMask("$(ASYN_PORT)", -1, 2)

#define ASYN_TRACEINFO_TIME 0x0001
#define ASYN_TRACEINFO_PORT 0x0002
#define ASYN_TRACEINFO_SOURCE 0x0004
#define ASYN_TRACEINFO_THREAD 0x0008
asynSetTraceInfoMask("$(ASYN_PORT)", -1, 5)

#define AMPLIFIER_ON_FLAG_CREATE_AXIS  1
#define AMPLIFIER_ON_FLAG_WHEN_HOMING  2
#define AMPLIFIER_ON_FLAG_USING_CNEN   4

{% for motor in motors | sort(attribute='nc_axis.axis_number') %}
epicsEnvSet("AXIS_NO",         "{{motor.nc_axis.axis_number}}")
epicsEnvSet("MOTOR_PREFIX",    "{{motor|epics_prefix}}")
epicsEnvSet("MOTOR_NAME",      "{{motor|epics_suffix}}")
epicsEnvSet("DESC",            "{{motor.name}} / {{motor.nc_axis.name}}")
epicsEnvSet("EGU",             "{{motor.nc_axis.units}}")
epicsEnvSet("PREC",            "{{motor|pragma('precision', 3) }}")
epicsEnvSet("AXISCONFIG",      "{{motor|pragma('axisconfig', '')}}")
epicsEnvSet("ECAXISFIELDINIT", "{{motor|pragma('additional_fields', '') }}")
epicsEnvSet("AMPLIFIER_FLAGS", "{{motor|pragma('amplifier_flags', '') }}")

EthercatMCCreateAxis("$(MOTOR_PORT)", "$(AXIS_NO)", "$(AMPLIFIER_FLAGS)", "$(AXISCONFIG)")
dbLoadRecords("EthercatMC.template", "PREFIX=$(MOTOR_PREFIX), MOTOR_NAME=$(MOTOR_NAME), R=$(MOTOR_NAME)-, MOTOR_PORT=$(MOTOR_PORT), ASYN_PORT=$(ASYN_PORT), AXIS_NO=$(AXIS_NO), DESC=$(DESC), PREC=$(PREC) $(ECAXISFIELDINIT)")
dbLoadRecords("EthercatMCreadback.template", "PREFIX=$(MOTOR_PREFIX), MOTOR_NAME=$(MOTOR_NAME), R=$(MOTOR_NAME)-, MOTOR_PORT=$(MOTOR_PORT), ASYN_PORT=$(ASYN_PORT), AXIS_NO=$(AXIS_NO), DESC=$(DESC), PREC=$(PREC) ")
dbLoadRecords("EthercatMCdebug.template", "PREFIX=$(MOTOR_PREFIX), MOTOR_NAME=$(MOTOR_NAME), MOTOR_PORT=$(MOTOR_PORT), AXIS_NO=$(AXIS_NO), PREC=3")

{% endfor %}
{% endif %}
{% for db in additional_db_files %}
dbLoadRecords("{{ db.file }}", "{{ db.macros }}")

{% endfor %}
cd "$(TOP)"

dbLoadRecords("db/iocAdmin.db", "P={{prefix}},IOC={{prefix}}" )
dbLoadRecords("db/save_restoreStatus.db", "P={{prefix}},IOC={{name}}" )

# Setup autosave
set_savefile_path( "$(IOC_DATA)/$(IOC)/autosave" )
set_requestfile_path( "$(TOP)/autosave" )
save_restoreSet_status_prefix( "{{prefix}}:" )
save_restoreSet_IncompleteSetsOk( 1 )
save_restoreSet_DatedBackupFiles( 1 )
set_pass0_restoreFile( "$(IOC).sav" )
set_pass1_restoreFile( "$(IOC).sav" )

# Initialize the IOC and start processing records
iocInit()

# Start autosave backups
create_monitor_set( "$(IOC).req", 5, "" )

# All IOCs should dump some common info after initial startup.
< /reg/d/iocCommon/All/post_linux.cmd

asyn_standard_file.jinja2

{% for r in records%}
{{r}}

{% endfor %}

asyn_standard_record.jinja2

record({{record.record_type}}, "{{record.pvname}}") {
{% if record.long_description %}
  # {{ record.long_description }}
{% endif %}
{% for alias in record.aliases %}
  alias("{{alias}}")
{% endfor %}
{% block add_fields  %}{% endblock %}
{% for f in record.fields%}
  field({{f}}, "{{record.fields[f]}}")
{% endfor %}
{% if record.autosave['pass1'] %}
  info(autosaveFields, "{{ record.autosave['pass1'] | sort | join(' ') }}")
{% endif %}
{% if record.autosave['pass0'] %}
  info(autosaveFields_pass0, "{{ record.autosave['pass0'] | sort | join(' ') }}")
{% endif %}
{% if record.archive_settings %}
  {% if record.archive_settings['method'] == 'scan' and record.archive_settings['seconds'] == 1 %}
  info(archive, "{{ record.archive_settings['fields'] | join(' ') }}")
  {% else %}
  info(archive, "{{ record.archive_settings['method'] }} {{ record.archive_settings['seconds'] }}: {{ record.archive_settings['fields'] | join(' ') }}")
  {% endif %}
{% endif %}
{% if record.direction == "input" %}
  field(ASG, "NO_WRITE")
{% endif %}
}