Tools
XML Sort
TwinCAT saves its project files somewhat arbitrarily, the order of elements is changed seemingly at random. Use this XML sorter before committing your changes to fix the XML layout and keep your Git history more clean.
Usage
Call with python -m tctools.xml_sort or tc_xml_sort.
usage: tc_xml_sort [-h] [--version] [--dry]
[--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}] [--check]
[-r] [--filter FILTER [FILTER ...]]
[--skip-nodes SKIP_NODES [SKIP_NODES ...]]
target [target ...]
Positional Arguments
- target
File(s) or folder(s) to target
Named Arguments
- --version, -V
show program’s version number and exit
- --dry
Do not modify files on disk, only report changes to be made
Default:
False- --log-level, -l
Possible choices: DEBUG, INFO, WARNING, ERROR, CRITICAL
Set log level to change verbosity
Default:
'INFO'- --check
Do not modify files on disk, but give a non-zero exit code if there would be changes
Default:
False- -r, --recursive
Also target folder (and their files) inside a target folder
Default:
False- --filter
Target files only with these patterns
Default: [’*.tsproj’, ‘*.xti’, ‘*.plcproj’]
- --skip-nodes, -n
Do not touch the attributes and sub-nodes of nodes with these names
Default:
['Device', 'DataType', 'DeploymentEvents']
Example: tc_xml_sort -r ./MyTwinCATProject
Notes
Nodes with the attribute
xml:space="preserve"are not touched
Differences with Ruud’s XmlSorter
The precursor of this script is the XmlSorter made by Ruud, written in C#: https://github.com/DEMCON/XmlSorter
There are a couple of difference between this sorter and Ruud’s:
The root attribute xmlns:xsi cannot be sorted
This is because lxml does not show it as an attribute.
This sorter will prefer self-closing tags where content is emtpy, instead of leaving them as they were.
This is a consequence of
lxml, it cannot identify self-closing tags upon reading.The self-closing tags also do not have a trailing space before the final
"/>".
Unicode characters are written as
#...;instead of literals.Something
lxmljust seems to do.
None of these appear problematic for TwinCAT. Projects can be opened and built again as expected, and when saved again the file will be as TwinCAT likes it.
Auto Formatter
Use this to make consistent use of whitespace. Visual Studio with PLC doesn’t do a lot of the things that other IDEs do, like removing trailing whitespace and making consistent usage of spaces / tabs. This tool is meant to supplement this.
Specify your preferences with an .editorconfig file, as you would for other projects. An example:
[*.TcPOU]
indent_style = space
indent_size = 4
Usage
Call with python -m tctools.format or tc_format.
usage: __main__.py [-h] [--version] [--dry]
[--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}] [--check]
[-r] [--filter FILTER [FILTER ...]]
target [target ...]
Positional Arguments
- target
File(s) or folder(s) to target
Named Arguments
- --version, -V
show program’s version number and exit
- --dry
Do not modify files on disk, only report changes to be made
Default:
False- --log-level, -l
Possible choices: DEBUG, INFO, WARNING, ERROR, CRITICAL
Set log level to change verbosity
Default:
'INFO'- --check
Do not modify files on disk, but give a non-zero exit code if there would be changes
Default:
False- -r, --recursive
Also target folder (and their files) inside a target folder
Default:
False- --filter
Target files only with these patterns
Default: [’*.tsproj’, ‘*.xti’, ‘*.plcproj’]
Example: tc_format -r ./MyTwinCATProject
Valid options
The following universal .editorconfig fields are considered:
indent_styleIf style is set to space, any tab character will be replaced by
tab_widthnumber of spacesIf style is set to tab, any
tab_width-number of spaces will be replaced by a tab
trim_trailing_whitespaceIf true, whitespace at the end of lines is removed
insert_final_newlineIf true, every code block must end with a newline
And The following unofficial (custom) .editorconfig fields are used:
twincat_align_variablesIf true, variables in declarations are aligned together
twincat_parentheses_conditionalsIf true, parentheses are enforced inside if-statements (
IF (condition = 1) THEN...)If false, parentheses inside if-statements are removed (
IF condition = 1 THEN...)
When a config property is not set, the formatter will typically take no action.
For example, not specifying indent_style (or using unset) will result in no whitespace conversions at all.
Git Info
Use to insert Git version into source file based on a template, to make it available for compilation.
Create a template file (e.g. .TcGVL.template), with {{...}} tags as placeholders for the version info.
Then run the info tool (preferably as part of your build) to have it create a new file next to it.
Usage
Call with python -m tctools.git_info or tc_git_info.
usage: __main__.py [-h] [--version] [--dry]
[--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}]
[--output OUTPUT] [--repo REPO]
[--tolerate-dirty TOLERATE_DIRTY]
template
Positional Arguments
- template
Template file to be used for newly created file
Named Arguments
- --version, -V
show program’s version number and exit
- --dry
Do not modify files on disk, only report changes to be made
Default:
False- --log-level, -l
Possible choices: DEBUG, INFO, WARNING, ERROR, CRITICAL
Set log level to change verbosity
Default:
'INFO'- --output
File path for the new output file (default: template file with the last extension stripped)
- --repo
Path to use for the Git repository (default: use the first repository up from the template file)
- --tolerate-dirty, -t
Paths to files that are allowed to be modified without showing the ‘dirty’ flag
Default:
[]
Example: tc_git_info Version.TcGVL.template
Placeholders
Placeholder |
Description |
Example |
|---|---|---|
GIT_HASH |
Full hash of the last commit |
|
GIT_HASH_SHORT |
8-char hash of the last commit |
|
GIT_DATE |
Datetime of the last commit |
|
GIT_NOW |
The current date and time (not a git command at all) |
|
GIT_TAG |
Most relevant tag (result of git tag) |
|
GIT_VERSION |
Guaranteed 3-digit 1.2.3 like-string, based on GIT_TAG |
|
GIT_BRANCH |
Current branch name |
|
GIT_DESCRIPTION |
Most relevant tag + number of commits since then + last commit (result of git describe –tags –always) |
|
GIT_DESCRIPTION_DIRTY |
Same as GIT_DESCRIPTION, except it also adds the –dirty argument to mark if there were uncommitted changes |
|
GIT_DIRTY |
1 if there are uncommited chances, otherwise 0 |
|
When using the --tolerate-dirty flag, the -dirty' state can be repressed.
The dirty detection itself is always done by Git directly.
You can also call git commands directly using function placeholders, e.g.:
myVar : STRING := '{{git describe --tags --abrev=4}}';
Notes
Requires Git, likely required to be added to
PATH.
Release Maker
Use to produce a release archive of compiled PLC code, optionally together with compiled HMI application.
Usage
Call with python -m tctools.make_release or tc_make_release.
usage: __main__.py [-h] [--version] [--dry]
[--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}]
[--destination DESTINATION] [--include-hmi]
[--add-file ADD_FILE [ADD_FILE ...]] [--platform PLATFORM]
[--check-cpu CHECK_CPU CHECK_CPU]
[--check-devices CHECK_DEVICES [CHECK_DEVICES ...]]
[--check-version-variable CHECK_VERSION_VARIABLE CHECK_VERSION_VARIABLE]
[--check-version-hmi CHECK_VERSION_HMI CHECK_VERSION_HMI]
plc-source
Positional Arguments
- plc-source
Path where to search for compilation directory of PLC project
Named Arguments
- --version, -V
show program’s version number and exit
- --dry
Do not modify files on disk, only report changes to be made
Default:
False- --log-level, -l
Possible choices: DEBUG, INFO, WARNING, ERROR, CRITICAL
Set log level to change verbosity
Default:
'INFO'- --destination
Folder where release output will be saved (default: ./deploy)
Default:
'deploy'- --include-hmi
Also include HMI compilation in release (default: False)
Default:
False- --add-file, -a
Add additional file to release package (<filepath> <relative path inside archive>)
- --platform
Target platform for PLC to copy (default: x64)
Default:
'x64'- --check-cpu
Validate the CPU configuration in the compiled project (<number of cores> <number of isolated cores>)
- --check-devices
Validate devices, only the listed devices by name may be enabled
- --check-version-variable
Validate current version in PLC source code in the given variable (<filename> <variable name>)
- --check-version-hmi
Validate current version in HMI source code in the given object (<filename> <object id>)
Patch PLC
Adding existing source files to a PLC project can be done through the TwinCAT shell, but it is clunky, slow and prone to outright fail. This tool can discover existing files under a given folder and assert their presence in a plc project file (.plcproj).
The patched PLc project will not be sorted! And the XML formatting will be significantly altered, because the entire XML is saved again. All XML elements are maintained, new files are foldes are merely inserted at the end of the relevant XML nodes. However, the entire file still needs to be saved again, which inevitably cause visible (but non-funcitonal) changes.
After opening, modifying and then saving the PLC project the next time, the original TwinCAT project file formatting will be restored.
In case you track your project file under version control, it is recommended to sort it with XML Sort after patching, before committing changes.
Note that it’s best to close the TwinCAT project while the tool runs. If you still have the project opened, you will be prompted to reload the solution after activating the window again. For smaller projects this will likely be fine, after reloading the modified project should show as expected. But in the case that many, many files were added, this reload will get stuck. Close and re-opening the solution after patch_plc should be faster and more reliable.
Usage
Call with pyton -m tctools.patch_plc or tc_patch_plc.
usage: tc_patch_plc [-h] [--version] [--dry]
[--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}]
[--check] [-r] [--filter FILTER [FILTER ...]]
[--ignore IGNORE [IGNORE ...]]
project {merge,reset,remove} source [source ...]
Positional Arguments
- project
Path to the PLC project (typically ‘.plcproj’)
- operation
Possible choices: merge, reset, remove
Type of action to take (see description)
- source
File(s) or folder(s) with PLC source to add to the project
Named Arguments
- --version, -V
show program’s version number and exit
- --dry
Do not modify files on disk, only report changes to be made
Default:
False- --log-level, -l
Possible choices: DEBUG, INFO, WARNING, ERROR, CRITICAL
Set log level to change verbosity
Default:
'INFO'- --check
Do not modify files on disk, but give a non-zero exit code if there would be changes
Default:
False- -r, --recursive
Also target folder (and their files) inside a target folder
Default:
False- --filter
Target files only with these patterns
Default:
['*.TcPOU', '*.TcGVL', '*.TcDUT', '*.TcGTLO', '*.TcIO', '*.TcTLEO', '*.TcTTO']- --ignore
File(s) to ignore on the filesystem (filenames are only matched exactly!)
Default:
[]
Example: tc_patch_plc ./MyPLC.plcproj -r POUs/Generated/