Merge branch 'upstream' R7-3-1

This commit is contained in:
2025-02-28 16:57:29 +01:00
69 changed files with 2548 additions and 1436 deletions
+1 -1
Submodule .ci updated: 12d769835e...20f8e05393
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env python
import os
import sys
import subprocess
from util import *
def get_submodule_releases():
#
releases = []
for root, dirs, files in os.walk('modules'):
for submodule in dirs:
if 'motor' in submodule:
release_path = "modules/{}/configure/RELEASE".format(submodule)
if os.path.exists(release_path):
releases.append(release_path)
return releases[:]
# Comment out SUPPORT from motor's RELEASE file
motor_release = "configure/RELEASE"
update_release_file(motor_release, "SUPPORT", '#')
print("{}Updated {}{}".format(ANSI_BLUE, motor_release, ANSI_RESET))
grep_release_file(motor_release, "#SUPPORT")
# Comment out SUPPORT from the driver module RELEASE files
releases = get_submodule_releases()
for release in releases:
updated = update_release_file(release, "SUPPORT", '#')
if updated:
print("{}Updated {}{}".format(ANSI_BLUE, release, ANSI_RESET))
grep_release_file(release, "#SUPPORT")
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env python
import os
import pprint
pprint.pprint(dict(os.environ), width = 1)
#!print("{}", breakmehere)
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env python
from __future__ import print_function
import logging
import fileinput
import os
# Setup ANSI Colors
ANSI_RED = "\033[31;1m"
ANSI_GREEN = "\033[32;1m"
ANSI_YELLOW = "\033[33;1m"
ANSI_BLUE = "\033[34;1m"
ANSI_MAGENTA = "\033[35;1m"
ANSI_CYAN = "\033[36;1m"
ANSI_RESET = "\033[0m"
ANSI_CLEAR = "\033[0K"
logger = logging.getLogger(__name__)
def create_file(filename):
dirname = os.path.dirname(filename)
print(dirname)
if not os.path.exists(dirname):
os.makedirs(dirname, 0o0755)
if not os.path.exists(filename):
fh = open(filename, 'w')
fh.close()
else:
logger.debug("{} already exists".format(filename))
# Update a definition in a release file that already exists
# Append a defintion to a release file that already exists
# Commented out a definition in a release file (location='#')
def update_release_file(filename, var, location):
updated_line = '{0}={1}'.format(var, location.replace('\\', '/'))
found = False
logger.debug("Opening '%s' for adding '%s'", filename, updated_line)
for line in fileinput.input(filename, inplace=1):
output_line = line.strip()
if '{0}='.format(var) in line:
logger.debug("Found '%s=' line, replacing", var)
found = True
if location != '#':
output_line = updated_line
else:
if output_line[0] != '#':
output_line = "#{}".format(output_line)
logger.debug("Writing line to '%s': '%s'", filename, output_line)
print(output_line)
fileinput.close()
if not found and location != '#':
fh = open(release_local, "a")
logger.debug("Adding new definition: '%s'", updated_line)
print(updated_line, file=fh)
fh.close()
return found
def grep_release_file(filename, var):
fh = open(filename, 'r')
for line in fh:
if '{0}='.format(var) in line:
print(line)
fh.close()
+4 -4
View File
@@ -1,7 +1,7 @@
MODULES="sncseq ipac asyn autosave busy"
SNCSEQ=R2-2-8
SNCSEQ=R2-2-9
IPAC=master
ASYN=R4-38
AUTOSAVE=R5-9
BUSY=R1-7-1
ASYN=R4-42
AUTOSAVE=R5-10-2
BUSY=R1-7-3
+195
View File
@@ -0,0 +1,195 @@
# .github/workflows/ci-scripts-build.yml for use with EPICS Base ci-scripts
# (see: https://github.com/epics-base/ci-scripts)
# This is YAML - indentation levels are crucial
# Set the 'name:' properties to values that work for you (MYMODULE)
name: "GHA full build"
# Only run manually
on:
workflow_dispatch
env:
SETUP_PATH: .ci-local:.ci
# For the sequencer on Linux/Windows/MacOS
APT: re2c
CHOCO: re2c
BREW: re2c
jobs:
build-base:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
# Set environment variables from matrix parameters
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
BASE: ${{ matrix.base }}
WINE: ${{ matrix.wine }}
RTEMS: ${{ matrix.rtems }}
RTEMS_TARGET: ${{ matrix.rtems_target }}
EXTRA: ${{ matrix.extra }}
TEST: ${{ matrix.test }}
SET: ${{ matrix.set }}
strategy:
fail-fast: false
matrix:
# Job names also name artifacts, character limitations apply
include:
- os: ubuntu-20.04
cmp: gcc
configuration: default
wine: "64"
base: "7.0"
set: modules
name: "Ub-20 gcc-9 + MinGW"
- os: ubuntu-20.04
cmp: gcc
configuration: static
wine: "64"
base: "7.0"
set: modules
name: "Ub-20 gcc-9 + MinGW, static"
- os: ubuntu-20.04
cmp: gcc
configuration: static
extra: "CMD_CXXFLAGS=-std=c++11"
base: "7.0"
set: modules
name: "Ub-20 gcc-9 C++11, static"
- os: ubuntu-20.04
cmp: clang
configuration: default
extra: "CMD_CXXFLAGS=-std=c++11"
base: "7.0"
set: modules
name: "Ub-20 clang-10 C++11"
### fails building autosave
#!- os: ubuntu-20.04
#! cmp: gcc
#! configuration: default
#! rtems: "4.10"
#! base: "7.0"
#! set: modules
#! name: "Ub-20 gcc-9 + RT-4.10"
- os: ubuntu-20.04
cmp: gcc
configuration: default
rtems: "4.9"
base: "7.0"
set: modules
name: "Ub-20 gcc-9 + RT-4.9"
### fails building asyn
#!- os: ubuntu-20.04
#! cmp: gcc
#! configuration: default
#! rtems: "5"
#! rtems_target: RTEMS-pc686-qemu
#! base: "7.0"
#! set: modules
#! name: "Ub-20 gcc-9 + RT-5.1 pc686"
### fails building autosave
#!- os: ubuntu-20.04
#! cmp: gcc
#! configuration: default
#! rtems: "5"
#! rtems_target: RTEMS-beatnik
#! test: NO
#! base: "7.0"
#! set: modules
#! name: "Ub-20 gcc-9 + RT-5.1 beatnik"
#!- os: ubuntu-20.04
#! cmp: gcc-8
#! utoolchain: true
#! configuration: default
#! base: "7.0"
#! set: modules
#! name: "Ub-20 gcc-8"
- os: ubuntu-20.04
cmp: clang
configuration: default
base: "7.0"
set: modules
name: "Ub-20 clang-10"
- os: macos-latest
cmp: clang
configuration: default
base: "7.0"
set: modules
name: "MacOS clang-12"
- os: windows-2019
cmp: gcc
configuration: default
base: "7.0"
set: modules
name: "Win2019 MinGW"
- os: windows-2019
cmp: gcc
configuration: static
base: "7.0"
set: modules
name: "Win2019 MinGW, static"
- os: windows-2019
cmp: vs2019
configuration: default
base: "7.0"
set: modules
name: "Win2019 MSC-19"
- os: windows-2019
cmp: vs2019
configuration: static
base: "7.0"
set: modules
name: "Win2019 MSC-19, static"
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Automatic core dumper analysis
uses: mdavidsaver/ci-core-dumper@master
- name: "apt-get install"
run: |
sudo apt-get update
sudo apt-get -y install qemu-system-x86 g++-mingw-w64-x86-64 gdb
if: runner.os == 'Linux'
- name: "apt-get install ${{ matrix.cmp }}"
run: |
sudo apt-get -y install software-properties-common
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get -y install ${{ matrix.cmp }}
if: matrix.utoolchain
- name: Sanity Check
run: python .ci-local/github-actions/sanity-check.py
- name: Prepare and compile dependencies
run: python .ci/cue.py prepare
- name: Patch main module
run: python .ci-local/github-actions/post-prepare.py
- name: Build main module
run: python .ci/cue.py build
- name: Run main module tests
run: python .ci/cue.py test
- name: Upload tapfiles Artifact
uses: actions/upload-artifact@v4
with:
name: tapfiles ${{ matrix.name }}
path: '**/O.*/*.tap'
- name: Collect and show test results
run: python .ci/cue.py test-results
+104
View File
@@ -0,0 +1,104 @@
# .github/workflows/ci-scripts-build.yml for use with EPICS Base ci-scripts
# (see: https://github.com/epics-base/ci-scripts)
# This is YAML - indentation levels are crucial
# Set the 'name:' properties to values that work for you (MYMODULE)
name: "GHA build"
# Trigger on pushes to the master branch and PRs
on:
push:
paths-ignore:
- 'documentation/*'
- '**/*.html'
- '**/*.md'
- '.github/workflows/ci-scripts-build-full.yml'
branches:
- master
pull_request:
env:
SETUP_PATH: .ci-local:.ci
# For the sequencer on Linux/Windows/MacOS
APT: re2c
CHOCO: re2c
BREW: re2c
jobs:
build-base:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
# Set environment variables from matrix parameters
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
BASE: ${{ matrix.base }}
WINE: ${{ matrix.wine }}
RTEMS: ${{ matrix.rtems }}
RTEMS_TARGET: ${{ matrix.rtems_target }}
EXTRA: ${{ matrix.extra }}
TEST: ${{ matrix.test }}
SET: ${{ matrix.set }}
strategy:
fail-fast: false
matrix:
# Job names also name artifacts, character limitations apply
include:
- os: ubuntu-20.04
cmp: gcc
configuration: default
base: "7.0"
set: modules
name: "7.0 Ub-20 gcc-9"
- os: macos-latest
cmp: clang
configuration: default
base: "3.15"
set: modules
name: "3.15 MacOS clang-12"
- os: windows-2019
cmp: vs2019
configuration: static
base: "3.15"
set: modules
name: "3.15 Win VS2019, static"
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Automatic core dumper analysis
uses: mdavidsaver/ci-core-dumper@master
- name: "apt-get install"
run: |
sudo apt-get update
sudo apt-get -y install qemu-system-x86 g++-mingw-w64-x86-64 gdb
if: runner.os == 'Linux'
- name: "apt-get install ${{ matrix.cmp }}"
run: |
sudo apt-get -y install software-properties-common
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get -y install ${{ matrix.cmp }}
if: matrix.utoolchain
- name: Sanity Check
run: python .ci-local/github-actions/sanity-check.py
- name: Prepare and compile dependencies
run: python .ci/cue.py prepare
- name: Patch main module
run: python .ci-local/github-actions/post-prepare.py
- name: Build main module
run: python .ci/cue.py build
- name: Run main module tests
run: python .ci/cue.py test
- name: Upload tapfiles Artifact
uses: actions/upload-artifact@v4
with:
name: tapfiles ${{ matrix.name }}
path: '**/O.*/*.tap'
- name: Collect and show test results
run: python .ci/cue.py test-results
+2 -1
View File
@@ -3,10 +3,11 @@ O.*
*.swp
*BAK.adl
bin/
db/
/db/
dbd/
html/
include/
/iocsh/
lib/
templates/
cdCommands
+2 -1
View File
@@ -1,5 +1,6 @@
# motor
[![Build Status](https://travis-ci.org/epics-modules/motor.png)](https://travis-ci.org/epics-modules/motor)
[![Build Status](https://github.com/epics-modules/motor/actions/workflows/ci-scripts-build.yml/badge.svg)](https://github.com/epics-modules/motor/actions/workflows/ci-scripts-build.yml)
<!--[![Build Status](https://travis-ci.org/epics-modules/motor.png)](https://travis-ci.org/epics-modules/motor)-->
This module contains motor support for the Experimental Physics and Industrial Control System (EPICS).
+88
View File
@@ -1,5 +1,93 @@
# Motor Releases
## __R7-3-1 (2023-06-07)__
R7-3-1 is a release based on the master branch.
### Changes since R7-3
#### Modifications to existing features
* Commit [5eb994d](https://github.com/epics-modules/motor/commit/5eb994dc5e0f8a809382b300ad13f8c83e7da33b) from [Mark Rivers](https://github.com/MarkRivers): Added readController() functions to asynMotorController
#### Driver submodules (and noteworthy changes)
| Module | Release | Changes |
| ---------------- | ------- | ------- |
| **motorAcsMotion** | [R2-2](https://github.com/epics-motor/motorAcsMotion/releases/tag/R2-2) | Improved homing and workaround for vxWorks build error |
## __R7-3 (2023-05-23)__
R7-3 is a release based on the master branch.
### Changes since R7-2-2
#### New features
* Commit [c764bd6](https://github.com/epics-modules/motor/commit/c764bd6426c3939bded75df2909b76d148c2f8c9): Added motorAcsMotion as a submodule
* Pull request [#160](https://github.com/epics-modules/motor/pull/160) from [Torsten Bögershausen](https://github.com/tboegi): Added the Restore Mode (**RSTM**) field
* Pull request [#163](https://github.com/epics-modules/motor/pull/163): Autosave the RSTM field and allow it to be specified when motor databases are loaded
* Pull request [#197](https://github.com/epics-modules/motor/pull/197): Added model-2-specific databases to work around MOTOR_REC_{OFFSET,RESOLUTION,DIRECTION} errors at iocInit
* Pull request [#193](https://github.com/epics-modules/motor/pull/193) from [Jack Harper](https://github.com/rerpha): Added raw limit (**RHLM**, **RLLM**) fields
* Pull request [#202](https://github.com/epics-modules/motor/pull/202) and [#204](https://github.com/epics-modules/motor/pull/204): Added prop(YES) to fields in motorRecord.dbd that should generate DBE_PROPERTY callbacks
* Pull request [#122](https://github.com/epics-modules/motor/pull/122) from [Torsten Bögershausen](https://github.com/tboegi): Addded Acceleration (**ACCS**) and Acceleration Used (**ACCU**) fields
* Pull request [#203](https://github.com/epics-modules/motor/pull/203): Changed the Acceleration Used (ACCU) field from a readback to a control
#### Modifications to existing features
* Pull request [#180](https://github.com/epics-modules/motor/pull/180) from [Torsten Bögershausen](https://github.com/tboegi): Reset UEIP to 'No' if no encoder is present
* Pull request [#193](https://github.com/epics-modules/motor/pull/193) from [Jack Harper](https://github.com/rerpha): Soft limits are synced on MRES changes
#### Bug fixes
* Pull request [#176](https://github.com/epics-modules/motor/pull/176) from [Torsten Bögershausen](https://github.com/tboegi): Added shareLib.h to motordrvCom.h for compatibility with base 7.0.4
* Pull request [#182](https://github.com/epics-modules/motor/pull/182) from [Freddie Akeroyd](https://github.com/FreddieAkeroyd): Bug fix for negative backlash distance when relative moves are used
* Pull request [#167](https://github.com/epics-modules/motor/pull/167) from [Torsten Bögershausen](https://github.com/tboegi): devMotorAsyn: remove initEvent in init_record()
* Commit [c3d6c6e](https://github.com/epics-modules/motor/commit/c3d6c6ee439e4d46fd2d4c2790091f7c76e31120) from [Mark Rivers](https://github.com/MarkRivers): Fixes for DTYP and EGU not displaying correctly in Phoebus
* Pull request [#206](https://github.com/epics-modules/motor/pull/206) from [Torsten Bögershausen](https://github.com/tboegi): Bug fix for RHLM, RLLM when MRES is negative
* Pull request [#186](https://github.com/epics-modules/motor/pull/186) from [justincslac](https://github.com/justincslac): Bug fix for .gitignore that caused the Db dir to be ignored on case-insensitive file systems
* Commit [96509ca](https://github.com/epics-modules/motor/commit/96509caba2ea1995bfeca3a0e8f11e1f273d2e05) from [Keenan Lang](https://github.com/keenanlang): Added basic_asyn_motor_settings.req which allows autosaveBuild to work with basic_asyn_motor.db
#### Documentation
* Commit [382c832](https://github.com/epics-modules/motor/commit/382c8324e5176ce769a09302bf829beca5a9cbea) from [Mark Rivers](https://github.com/MarkRivers): Added "Model 3 EPICS Motor Driver Support" slides
* Pull request [#190](https://github.com/epics-modules/motor/pull/190) from [Xiaoqiang Wang](https://github.com/xiaoqiangwang): Corrected field types in motorRecord.html
#### Continuous Integration
* Configured to build with GitHub Actions using ci-scripts v3.0.1
#### Driver submodules (and noteworthy changes)
All driver modules now use Github Actions for CI builds.
| Module | Release | Changes |
| ---------------- | ------- | ------- |
| **motorAcs** | [R1-1-1](https://github.com/epics-motor/motorAcs/releases/tag/R1-1-1) | |
| **motorAcsMotion** | [R2-1](https://github.com/epics-motor/motorAcsMotion/releases/tag/R2-1) | Added as a motor submodule |
| **motorAcsTech80** | [R1-0-2](https://github.com/epics-motor/motorAcsTech80/releases/tag/R1-0-2) | |
| **motorAerotech** | [R1-1-1](https://github.com/epics-motor/motorAerotech/releases/tag/R1-1-1) | Ensemble driver and doCommand.ab bug fixes |
| **motorAMCI** | [R1-0-2](https://github.com/epics-motor/motorAMCI/releases/tag/R1-0-2) | Replaced printf calls with asynPrint calls in ANG1Driver.cpp |
| **motorAttocube** | [R1-0-2](https://github.com/epics-motor/motorAttocube/releases/tag/R1-0-2) | |
| **motorDeltaTau** | [R1-0-2](https://github.com/epics-motor/motorDeltaTau/releases/tag/R1-0-2) | |
| **motorFaulhaber** | [R1-0-2](https://github.com/epics-motor/motorFaulhaber/releases/tag/R1-0-2) | |
| **motorHytec** | [R1-0-3](https://github.com/epics-motor/motorHytec/releases/tag/R1-0-3) | |
| **motorIms** | [R1-0-2](https://github.com/epics-motor/motorIms/releases/tag/R1-0-2) | |
| **motorKohzu** | [R1-0-2](https://github.com/epics-motor/motorKohzu/releases/tag/R1-0-2) | |
| **motorMclennan** | [R1-1-1](https://github.com/epics-motor/motorMclennan/releases/tag/R1-1-1) | |
| **motorMicos** | [R2-1](https://github.com/epics-motor/motorMicos/releases/tag/R2-1) | Added support for the SMC Taurus |
| **motorMicroMo** | [R1-0-2](https://github.com/epics-motor/motorMicroMo/releases/tag/R1-0-2) | |
| **motorMicronix** | [R1-1](https://github.com/epics-motor/motorMicronix/releases/tag/R1-1) | |
| **motorMotorSim** | [R1-2](https://github.com/epics-motor/motorMotorSim/releases/tag/R1-2) | Added motorSim8x.iocsh. Multiple improvements to example IOC. |
| **motorMXmotor** | [R1-0-2](https://github.com/epics-motor/motorMXmotor/releases/tag/R1-0-2) | |
| **motorNewFocus** | [R1-2-1](https://github.com/epics-motor/motorNewFocus/releases/tag/R1-2-1) | Improved example newfocus8742 configuration. iocsh files now installed. |
| **motorNewport** | [R1-2-1](https://github.com/epics-motor/motorNewport/releases/tag/R1-2-1) | Added support for the FCL200. ESP300 driver now supports UEIP=Yes. iocsh files now installed. |
| **motorNPoint** | [R1-1](https://github.com/epics-motor/motorNPoint/releases/tag/R1-1) | |
| **motorOms** | [R1-2](https://github.com/epics-motor/motorOms/releases/tag/R1-2) | Enabled non-VxWorks IOCs & epicsMutexTryLock bug fix |
| **motorOmsAsyn** | [R1-0-3](https://github.com/epics-motor/motorOmsAsyn/releases/tag/R1-0-3) | Type fixes |
| **motorOriel** | [R1-0-2](https://github.com/epics-motor/motorOriel/releases/tag/R1-0-2) | |
| **motorParker** | [R1-1-1](https://github.com/epics-motor/motorParker/releases/tag/R1-1-1) | |
| **motorPhytron** | [R1-2](https://github.com/epics-motor/motorPhytron/releases/tag/R1-2) | Added encoder options. Bug fixes for deceleration and homing to limts. |
| **motorPI** | [R1-1-1](https://github.com/epics-motor/motorPI/releases/tag/R1-1-1) | Added E-816 example configuration. iocsh files now installed. |
| **motorPIGCS2** | [R1-2](https://github.com/epics-motor/motorPIGCS2/releases/tag/R1-2) | Added support for E-518 & E-873.3QTU controllers. Added closed loop commands for the E-727. Bug fixes. |
| **motorPiJena** | [R1-0-2](https://github.com/epics-motor/motorPiJena/releases/tag/R1-0-2) | |
| **motorScriptMotor** | [R1-2](https://github.com/epics-motor/motorScriptMotor/releases/tag/R1-2) | Added Attocube AMC support |
| **motorSmarAct** | [R2-0](https://github.com/epics-motor/motorSmarAct/releases/tag/R2-0) | Too many new features to list here; see [motorSmarAct release notes](https://github.com/epics-motor/motorSmarAct/releases/tag/R2-0) |
| **motorSmartMotor** | [R1-0-2](https://github.com/epics-motor/motorSmartMotor/releases/tag/R1-0-2) | |
| **motorThorLabs** | [R1-0-2](https://github.com/epics-motor/motorThorLabs/releases/tag/R1-0-2) | Added support for Kinesis KDC101 and KST101 |
## __R7-2-2 (2021-02-02)__
R7-2-2 is a release based on the R7-2-1-bugfix branch.
+27 -5
View File
@@ -50,13 +50,22 @@ the links in the table below: <br />
<td><a href="https://github.com/epics-modules/motor/issues">github issues</a></td>
<td>n/a</td>
</tr>
<tr>
<td>R7-3</td>
<td>R3.15.7 or later</td>
<td><a href="https://github.com/epics-modules/motor/archive/R7-3-1.tar.gz">motorR7-3-1.tar.gz</a></td>
<td><a href="https://epics.anl.gov/bcda/synApps/motor/R7-3/motorRecord.html">motorRecord.html</a></td>
<td><a href="https://github.com/epics-modules/motor/releases/tag/R7-3">release notes</a></td>
<td><a href="https://github.com/epics-modules/motor/issues?utf8=%E2%9C%93&q=milestone%3AR7-3">github issues</a></td>
<td>2023-05-23</td>
</tr>
<tr>
<td>R7-2</td>
<td>R3.15.7 or later</td>
<td><a href="https://github.com/epics-modules/motor/archive/R7-2-1.tar.gz">motorR7-2-1.tar.gz</a></td>
<td><a href="https://epics.anl.gov/bcda/synApps/motor/R7-2-1/motorRecord.html">motorRecord.html</a></td>
<td><a href="https://github.com/epics-modules/motor/releases/tag/R7-2-1">release notes</a></td>
<td><a href="https://github.com/epics-modules/motor/issues?utf8=%E2%9C%93&q=milestone%3AR7-2-1">github issues</a></td>
<td><a href="https://github.com/epics-modules/motor/archive/R7-2-2.tar.gz">motorR7-2-2.tar.gz</a></td>
<td><a href="https://epics.anl.gov/bcda/synApps/motor/R7-2/motorRecord.html">motorRecord.html</a></td>
<td><a href="https://github.com/epics-modules/motor/releases/tag/R7-2">release notes</a></td>
<td><a href="https://github.com/epics-modules/motor/issues?utf8=%E2%9C%93&q=milestone%3AR7-2-2">github issues</a></td>
<td>2020-05-13</td>
</tr>
<tr>
@@ -324,6 +333,19 @@ the links in the table below: <br />
<td><b>Required modules</b></td>
<td><b>Release needed</b></td>
</tr>
<tr>
<td>R7-3</td>
<td><a href="https://epics.anl.gov/modules/soft/asyn/">ASYN</a> &nbsp; <br />
<a href="https://github.com/epics-modules/ipac/wiki">IPAC</a> &nbsp;(for motorHytec &amp; VME-based serial and GPIB examples) <br />
<a href="https://github.com/epics-modules/lua">LUA</a> &nbsp;(for motorScriptMotor) <br />
<a href="https://github.com/epics-modules/modbus">MODBUS</a> &nbsp;(for motorAMCI IOCs)
</td>
<td>R4-41+<br />
R2-16<br />
R3-0<br />
R3-2
</td>
</tr>
<tr>
<td>R7-2</td>
<td><a href="https://epics.anl.gov/modules/soft/asyn/">ASYN</a> &nbsp; <br />
@@ -685,7 +707,7 @@ different releases of EPICS and/or the other required modules are needed).
<hr width="100%" />
<br />
Page Last Modified: 2020-05-14 <br />
Page Last Modified: 2023-06-07 <br />
<i><a href="mailto:kmpeters@anl.gov">Kevin Peterson</a></i> <br />
<br />
</body>
+16 -16
View File
@@ -47,13 +47,13 @@
for new motor drivers.</p>
<p>
The APIs described here are mainly intended to be used with the EPICS motor record.
However the Model 2 and Model 3 drivers are actually independent of the motor record.
However, the Model 2 and Model 3 drivers are actually independent of the motor record.
They implement standard EPICS asyn interfaces, and can in principle be used with
any EPICS records, and do not require the motor record. However, the motor record
currently provides the only "state machine" logic that keeps track of backlash,
enforcing soft limits, etc. Model 2 and 3 drivers to permit access to controller-specific
features that the motor record does not support, and this is typicaly implemented
using standard EPICS records (ao, ai, bo, bi, etc.)</p>
enforcing soft limits, etc. Model 2 and 3 drivers permit access to controller-specific
features that the motor record does not support, and this is typically implemented
using standard EPICS records (ao, ai, bo, bi, etc.).</p>
<h2 id="Model1" style="text-align: left">
Model 1 device and driver support</h2>
<p>
@@ -65,13 +65,13 @@
<li>The communication channel between device support and driver is custom for the
motor record, and is very limited.</li>
<li>The communication between device support and the driver is assumed to be via device-dependent
strings. Thus, it not suited to register-based controllers, or controllers where
the driver calls a vendor-library, rather than just sending strings to the controller.</li>
<li>Cannot use other records to with the driver, only the motor record. Cannot take
strings. Thus, it is not suited to register-based controllers, or controllers where
the driver calls a vendor library rather than just sending strings to the controller.</li>
<li>Cannot use other records with the driver, only the motor record. Cannot take
advantage of controller-specific features not supported by the motor record.</li>
<li>There is no provision for multi-axis coordination.</li>
<li>There is only a single thread per controller <i>type</i>. This means that if a
system has, for example, many controllers of a given type then there is only one
system has, for example, many controllers of a given type, then there is only one
polling thread for all of these controllers. This is because the poller must wait
for each response before sending the next query. This can lead to significantly
poorer performance compared to the Model 2 and Model 3 drivers, which have a separate
@@ -89,7 +89,7 @@
<ul>
<li>Uses standard asyn interfaces to communicate between device support and driver.</li>
<li>There is only a single device-independent device support file (devMotorAsyn.c).</li>
<li>There is a single device-independent driver support file for asyn interfaces (drvMotorAsyn.).</li>
<li>There is a single device-independent driver support file for asyn interfaces (drvMotorAsyn.c).</li>
<li>There is a device-dependent driver file below the asyn one. This driver must implement
a set of functions that the device-independent driver file calls.</li>
<li>Can use other records to talk to driver via asyn interfaces. This allows support
@@ -131,24 +131,24 @@
</ul>
<p>
The Model 3 C++ API is based on the concept of two types of objects: a motor controller
and one or motor motor axes. The controller object supports the functions that apply
and one or more motor axes. The controller object supports the functions that apply
to the entire controller. The controller supports one or more axes. The axis objects
support the functions for a specific axis. These objects are implemented in the
device-dependent driver. There is a base class for each of these objects, asynMotorControlller
device-dependent driver. There is a base class for each of these objects, asynMotorController
and asynMotorAxis.
</p>
<p>
The asynMotorController base class has methods that handle much of the work in writing
a driver, including implementing the asyn interfaces and calling the appropriate
methods in the axis classes. A basic motor driver derived class will often only
need to implement only the constructor for the controller class, and can just use
need to implement the constructor for the controller class, and can just use
the base class implementation of all other methods in the asynMotorController class.</p>
<p>
The asynMotorAxis base class on the other hand mainly provides dummy methods (asynMotorAxis::move(),
asynMotorAxis::stop(), etc.). The main work in writing a Model 3 driver consists
of implementing these methods in the derived class.</p>
<p>
There are Model 3 drivers in the motor module for the simulation motor, Hytec XXXX,
There are Model 3 drivers in the motor module for the simulation motor, Hytec 8601,
Newport XPS, Parker ACR series controllers (e.g. Aires), and the ACS MCB-4B.</p>
<p>
The ACS MCB-4B is the simplest Model 3 driver, consisting of only 336 lines of well-commented
@@ -172,7 +172,7 @@
The number of axes on this controller.</li>
<li><code>numParams</code><br />
The number of controller-specific parameters for this controller.&nbsp; If the driver
only implements the standard motor record parameters then this is set to 0.</li>
only implements the standard motor record parameters, then this is set to 0.</li>
<li><code>interfaceMask</code><br />
A bit mask for extra asyn interfaces supported by this controller. It is not necessary
to specify the interfaces that the base class implements, which includes asynOctet,
@@ -181,11 +181,11 @@
<li><code>interruptMask</code><br />
A bit mask for extra asyn interfaces supported by this controller that will do callbacks
to device support. It is not necessary to specify the interfaces that the base class
implements, which includes asynOctet, asynInt32, asynFloat64, asynFloat64Array,
implements, which include asynOctet, asynInt32, asynFloat64, asynFloat64Array,
and asynGenericPointer. Normally set to 0.</li>
<li><code>asynFlags</code><br />
asyn flags to use when creating the asyn port. This is normally (ASYN_CANBLOCK |
ASYN_MULTIDEVICE). ASYN_CANBLOCK means that the driver is "slow" and asynchonous
ASYN_MULTIDEVICE). ASYN_CANBLOCK means that the driver is "slow" and asynchronous
device support must be used. ASYN_MULTIDEVICE means that the device supports more
than one asyn address, i.e. more than one motor axis.</li>
<li><code>autoConnect</code><br />
+136 -54
View File
@@ -35,9 +35,9 @@
</ul>
<a name="Overview"></a>
<h2>Overview</h2> This documentation describes version R7-2-1 of the EPICS motor
<h2>Overview</h2> This documentation describes version R7-3-1 of the EPICS motor
record, and related EPICS software required to build and use it.&nbsp; Version
R7-2-1 of the motor record is compatible with EPICS base R3.15.7 and above.
R7-3-1 of the motor record is compatible with EPICS base R3.15.7 and above.
<p>
The motor record is intended to support positioning motors of all kinds, but currently
supports motor controllers from the following manufacturers:
@@ -45,7 +45,7 @@ supports motor controllers from the following manufacturers:
<ul>
<li>
ACS Motion Control: <a href="https://github.com/epics-motor/motorAcsTech80">motorAcsTech80</a>
ACS Motion Control: <a href="https://github.com/epics-motor/motorAcsMotion">motorAcsMotion</a> &amp; <a href="https://github.com/epics-motor/motorAcsTech80">motorAcsTech80</a>
</li>
<li>
Advanced Control Systems, Corp: <a href="https://github.com/epics-motor/motorAcs">motorAcs</a>
@@ -62,15 +62,9 @@ supports motor controllers from the following manufacturers:
<li>
attocube systems: <a href="https://github.com/epics-motor/motorAttocube">motorAttocube</a>
</li>
<li>
Delta Tau: <a href="https://github.com/epics-motor/motorDeltaTau">motorDeltaTau</a>
</li>
<li>
Faulhaber: <a href="https://github.com/epics-motor/motorFaulhaber">motorFaulhaber</a>
</li>
<li>
Hytec: <a href="https://github.com/epics-motor/motorHytec">motorHytec</a>
</li>
<li>
Kohzu: <a href="https://github.com/epics-motor/motorKohzu">motorKohzu</a>
</li>
@@ -89,12 +83,21 @@ supports motor controllers from the following manufacturers:
<li>
Newport: <a href="https://github.com/epics-motor/motorNewport">motorNewport</a>
</li>
<li>
Newwood Solutions Ltd (formerly Hytec): <a href="https://github.com/epics-motor/motorHytec">motorHytec</a>
</li>
<li>
Novanta IMS (formerly Schneider Electric (formally IMS)): <a href="https://github.com/epics-motor/motorIms">motorIms</a>
</li>
<li>
Micronix: <a href="https://github.com/epics-motor/motorMicronix">motorMicronix</a>
</li>
<li>
nPoint: <a href="https://github.com/epics-motor/motorNPoint">motorNPoint</a>
</li>
<li>
Omron Delta Tau: <a href="https://github.com/epics-motor/motorDeltaTau">motorDeltaTau</a>
</li>
<li>
Oregon Micro Systems: <a href="https://github.com/epics-motor/motorOms">motorOms</a> &amp; <a href="https://github.com/epics-motor/motorOmsAsyn">motorOmsAsyn</a>
</li>
@@ -110,9 +113,6 @@ supports motor controllers from the following manufacturers:
<li>
piezosystem jena GmbH: <a href="https://github.com/epics-motor/motorPiJena">motorPiJena</a>
</li>
<li>
Schneider Electric (formally IMS): <a href="https://github.com/epics-motor/motorIms">motorIms</a>
</li>
<li>
SmarAct GmbH: <a href="https://github.com/epics-motor/motorSmarAct">motorSmarAct</a>
</li>
@@ -264,6 +264,21 @@ below.
<td>DOUBLE</td>
<td>acceleration time</td>
</tr>
<tr>
<td><a href="#Fields_motion">ACCS</a></td>
<td>R/W</td>
<td>Acceleration (EGU/s^2)</td>
<td>DOUBLE</td>
<td><br>
</td>
</tr>
<tr>
<td><a href="#Fields_motion">ACCU</a></td>
<td>R/W</td>
<td>Acceleration used</td>
<td>RECCHOICE</td>
<td>(0:"Use ACCL", 1:"Use ACCS")</td>
</tr>
<tr>
<td><a href="#Fields_status">ADEL</a></td>
<td>R/W</td>
@@ -455,7 +470,7 @@ below.
<td><a href="#Fields_motion">FRAC</a></td>
<td>R/W</td>
<td>Move Fraction</td>
<td>DOUBLE</td>
<td>FLOAT</td>
<td><br>
</td>
</tr>
@@ -676,7 +691,7 @@ below.
<td><a href="#Fields_private">LRVL</a></td>
<td>R</td>
<td>Last Raw Des Val</td>
<td>DOUBLE</td>
<td>LONG</td>
<td><br>
</td>
</tr>
@@ -889,22 +904,6 @@ below.
<td><br>
</td>
</tr>
<tr>
<td><a href="#Fields_res">RSTM</a></td>
<td>R/W</td>
<td>Restore Mode</td>
<td>RECCHOICE</td>
<td>(0:"Never", 1:"Always", 2:"NearZero", 3:"Conditional")<br>
</td>
</tr>
<tr>
<td><a href="#Fields_motion">SPDB</a></td>
<td>R/W</td>
<td>Set Point Deadband (EGU)</td>
<td>DOUBLE</td>
<td><br>
</td>
</tr>
<tr>
<td><a href="#Fields_link">RDBL</a></td>
<td>R</td>
@@ -925,6 +924,14 @@ below.
<td><a href="#Fields_status">REP</a></td>
<td>R</td>
<td>Raw Encoder Position</td>
<td>LONG</td>
<td><br>
</td>
</tr>
<tr>
<td><a href="#Fields_limit">RHLM</a></td>
<td>R</td>
<td>Raw High Limit</td>
<td>DOUBLE</td>
<td><br>
</td>
@@ -945,6 +952,14 @@ below.
<td><br>
</td>
</tr>
<tr>
<td><a href="#Fields_limit">RLLM</a></td>
<td>R</td>
<td>Raw Low Limit</td>
<td>DOUBLE</td>
<td><br>
</td>
</tr>
<tr>
<td><a href="#Fields_limit">RLLS</a></td>
<td>R</td>
@@ -981,7 +996,7 @@ below.
<td><a href="#Fields_status">RMP</a></td>
<td>R</td>
<td>Raw Motor Position</td>
<td>DOUBLE</td>
<td>LONG</td>
<td><br>
</td>
</tr>
@@ -989,7 +1004,7 @@ below.
<td><a href="#Fields_status">RRBV</a></td>
<td>R</td>
<td>Raw Readback Value</td>
<td>DOUBLE</td>
<td>LONG</td>
<td><br>
</td>
</tr>
@@ -1001,6 +1016,14 @@ below.
<td><br>
</td>
</tr>
<tr>
<td><a href="#Fields_res">RSTM</a></td>
<td>R/W</td>
<td>Restore Mode</td>
<td>RECCHOICE</td>
<td>(0:"Never", 1:"Always", 2:"NearZero", 3:"Conditional")<br>
</td>
</tr>
<tr>
<td><a href="#Fields_motion">RTRY</a></td>
<td>R/W</td>
@@ -1013,7 +1036,7 @@ below.
<td><a href="#Fields_drive">RVAL</a></td>
<td>R/W*</td>
<td>Raw Desired Value</td>
<td>DOUBLE</td>
<td>LONG</td>
<td><br>
</td>
</tr>
@@ -1064,6 +1087,14 @@ below.
<td><br>
</td>
</tr>
<tr>
<td><a href="#Fields_motion">SPDB</a></td>
<td>R/W</td>
<td>Set Point Deadband (EGU)</td>
<td>DOUBLE</td>
<td><br>
</td>
</tr>
<tr>
<td><a href="#Fields_command">SPMG</a></td>
<td>R/W*</td>
@@ -1209,7 +1240,7 @@ below.
<td><a href="#Fields_misc">VERS</a></td>
<td>R</td>
<td>Code Version</td>
<td>DOUBLE</td>
<td>FLOAT</td>
<td>e.g., "1.95"</td>
</tr>
<tr>
@@ -1710,10 +1741,30 @@ below.
motor motion.</td>
</tr>
<tr>
<td colspan="5">The motor record expects the hardware to produce a trapezoidal
<td>ACCS</td>
<td>R/W</td>
<td>Acceleration (EGU/s^2)</td>
<td>DOUBLE</td>
<td>Valid range; 0 &lt;= ACCS</td>
</tr>
<tr>
<td>ACCU</td>
<td>R/W</td>
<td>Acceleration used</td>
<td>RECCHOICE</td>
<td>(0:"Use ACCL", 1:"Use ACCS")&nbsp; This field determines whether the ACCL or ACCS field
is used in the calculation of the acceleration that is sent to device support. The field
that is not used changes with VELO. The default value is "Use ACCL"&nbsp;</td>
</tr>
<tr>
<td colspan="5">
The motor record expects the hardware to produce a trapezoidal
speed profile. That is, the motor speed is expected to increase linearly with
time from the base speed, VBAS, to the full speed, VELO, in ACCL seconds. At the
end of a motion, the speed is expected to decrease similarly to VBAS.&nbsp;</td>
end of a motion, the speed is expected to decrease similarly to VBAS.
<p>Note that the ACCS field can be use to specify the acceleration in EGU/s^2.</p>
<p>Velocity and acceleration are related by the following equation: <br>
VELO - VBAS = ACCL * ACCS &nbsp;</p></td>
</tr>
<tr>
<td>JVEL</td>
@@ -1827,7 +1878,7 @@ below.
<td>FRAC</td>
<td>R/W</td>
<td>Move Fraction</td>
<td>DOUBLE</td>
<td>FLOAT</td>
</tr>
<tr>
<td colspan="5">This field supports closed-loop control of pathological devices
@@ -1872,9 +1923,9 @@ below.
<td>R/W</td>
<td>Set Point Deadband (EGU)</td>
<td>DOUBLE</td>
<td>Before the motor is commanded a move, a check is done if the move is to small.
It is to small when the distance is less the the step size defined in MRES.
When a bigger deadband is wanted than MRES, set the value into SPDB.
<td>Before the motor is commanded to move, a check is done to see if the move is
too small. It is too small when the distance is less than the step size defined in
MRES. When a bigger deadband is wanted than MRES, set the value of SPDB.
</td>
</tr>
<tr valign="top">
@@ -2088,6 +2139,24 @@ below.
the DIR field has the value "Pos", then DLLM will always be consistent with LLM,
otherwise DLLM will always be consistent with HLM.&nbsp;</td>
</tr>
<tr valign="top">
<td>RHLM</td>
<td>R</td>
<td>Raw High Limit</td>
<td>DOUBLE</td>
<td>The maximum allowed value of the RVAL field. If the MRES field is negative,
then RHLM will always be consistent with DLLM, otherwise RHLM will always be
consistent with DHLM.&nbsp;</td>
</tr>
<tr valign="top">
<td>RLLM</td>
<td>R</td>
<td>Raw Low Limit</td>
<td>DOUBLE</td>
<td>The minimum allowed value of the RVAL field. If the MRES field is negative,
then RLLM will always be consistent with DHLM, otherwise RLLM will always be
consistent with DLLM.&nbsp;</td>
</tr>
<tr valign="top">
<td>LVIO</td>
<td>R</td>
@@ -2308,7 +2377,13 @@ below.
motor stops, the VAL field will be set equal to the RBV field, and the DVAL
field will be set equal to the DRBV field.&nbsp; These fields can be set to 1,
but setting either field to 0 results in an error.&nbsp; The record sets HOM[F/R]
to zero when the homing procedure is either completed or aborted.</td>
to zero when the homing procedure is either completed or aborted.
Note that modern controllers, depending on their firmware and configuration,
may do different things. Examples are home into the limit switch, move
into a limit switch, return and search for a home switch or other sequences.
Often HOMF and HOMR then yield the same functionality.
And the controller may choose to do nothing, if a motor is not homable.
</td>
</tr>
<tr valign="top">
<td><br>
@@ -2377,7 +2452,7 @@ below.
<td colspan="5">When one of these fields is set to 1, the record will
immediately reset it to 0, and the motor will move (with backlash takeout if
BDST is nonzero) by a distance TWV (in user coordinates) at the acceleration
specified by ACCL and at speed VELO.</td>
specified by ACCL/ACCS and at speed VELO.</td>
</tr>
<tr valign="top">
<td>TWV</td>
@@ -2426,7 +2501,7 @@ below.
<td>RVAL</td>
<td>R/W*</td>
<td>Raw Desired Value</td>
<td>DOUBLE</td>
<td>LONG</td>
<td>This is the desired position in raw coordinates. When this field is written
to, VAL and DVAL will be changed correspondingly, and the motor will move (with
backlash takeout if BDST is nonzero) to the newly written position.&nbsp;</td>
@@ -2533,7 +2608,7 @@ below.
<td>RRBV</td>
<td>R</td>
<td>Raw Readback Value</td>
<td>DOUBLE</td>
<td>LONG</td>
<td>The current position of the motor, encoder, or readback link, as received
from whatever source has been selected to provide position information. The
units associated with this field depend on the source.&nbsp;</td>
@@ -2542,7 +2617,7 @@ below.
<td>RMP</td>
<td>R</td>
<td>Raw Motor Position</td>
<td>DOUBLE</td>
<td>LONG</td>
<td>The contents of the hardware's step-count register. This field contains the
same information as the dial value, but in steps, rather than in engineering
units.&nbsp;</td>
@@ -2551,7 +2626,7 @@ below.
<td>REP</td>
<td>R</td>
<td>Raw Encoder Position</td>
<td>DOUBLE</td>
<td>LONG</td>
<td>The contents of the hardware's encoder-count register. Ideally, this field
contains the same information as the dial value, but in encoder counts, rather
than in engineering units.&nbsp;</td>
@@ -2806,11 +2881,18 @@ below.
<td>R/W</td>
<td>Enable control</td>
<td>RECCHOICE</td>
<td>(0:"Disable", 1:"Enable")&nbsp; Enable/Disable closed-loop position control.&nbsp;
This field is active only if the GAIN_SUPPORT bit in the MSTA is true.&nbsp;
This field is set by both the user and device support.&nbsp; CNEN is set to <i>Disable</i>
by device support when it detects a motion controller error; e.g. maximum
following error exceeded.</td>
<td>This field is active only if the GAIN_SUPPORT bit in the MSTA is true.
The function of this field is depending on the motion controller.
This field is set by both the user and device support.
<li>
Some (older?) controllers can switch between open- and closed-loop. (0: open loop, 1: closed loop)
</li>
<li>
Some controllers use this field to enable torque control
</li>
<li>
Most modern controllers use this field to enable/disable the motor (amplifier/driver)
</li>
</tr>
<tr valign="top">
<td>PCOF</td>
@@ -2952,7 +3034,7 @@ below.
<td>VERS</td>
<td>R</td>
<td>Code Version</td>
<td>DOUBLE</td>
<td>FLOAT</td>
<td>Version number of the recMotor.c code.</td>
</tr>
<tr valign="top">
@@ -3186,7 +3268,7 @@ below.
<td>LRVL</td>
<td>R</td>
<td>Last Raw Des Val</td>
<td>DOUBLE</td>
<td>LONG</td>
</tr>
<tr valign="top">
<td>LRLV</td>
@@ -3631,6 +3713,6 @@ specific value (e.g., kV) that is not supported by the motor controller. <br>
<hr>
<address>Suggestions and comments to:</address> <br>
<a href="mailto:kmpeters@anl.gov">Kevin Peterson</a> : (kmpeters@anl.gov) <br>
Last modified: 2020-05-14
Last modified: 2023-05-23
</body>
</html>
Binary file not shown.
+4
View File
@@ -85,6 +85,10 @@ ifdef LUA
$(ECHO) Creating $@, LUA = $(LUA)
@echo LUA = $(LUA)>> $@
endif
ifdef AUTOSAVE
$(ECHO) Creating $@, AUTOSAVE = $(AUTOSAVE)
@echo AUTOSAVE = $(AUTOSAVE)>> $@
endif
ifdef MODBUS
$(ECHO) Creating $@, MODBUS = $(MODBUS)
@echo MODBUS = $(MODBUS)>> $@
+1
View File
@@ -10,6 +10,7 @@ record(motor, "$(P)$(M)") {
field(VELO, "$(VELO)")
field(VBAS, "$(VBAS)")
field(ACCL, "$(ACCL)")
field(ACCU, "$(ACCU=0)")
field(BDST, "$(BDST)")
field(BVEL, "$(BVEL)")
field(BACC, "$(BACC)")
+93
View File
@@ -0,0 +1,93 @@
#! Generated by VisualDCT v2.6
#! DBDSTART
#! DBDEND
record(motor, "$(P)$(M)") {
field(DESC, "$(DESC)")
field(DTYP, "$(DTYP)")
field(DIR, "$(DIR)")
field(VELO, "$(VELO)")
field(VBAS, "$(VBAS)")
field(ACCL, "$(ACCL)")
field(ACCU, "$(ACCU=0)")
field(BDST, "$(BDST)")
field(BVEL, "$(BVEL)")
field(BACC, "$(BACC)")
field(OUT, "@asyn($(PORT),$(ADDR))")
field(MRES, "$(MRES)")
field(PREC, "$(PREC)")
field(EGU, "$(EGU)")
field(DHLM, "$(DHLM)")
field(DLLM, "$(DLLM)")
field(INIT, "$(INIT)")
field(RTRY, "$(RTRY=10)")
field(RSTM, "$(RSTM=NearZero)")
field(TWV, "1")
field(SDIS, "$(P)$(M)_able.VAL")
}
record(bo, "$(P)$(M)_able") {
field(DESC, "motor enable")
field(PINI, "YES")
field(OUT, "$(P)$(M).DISP")
field(ZNAM, "Enable")
field(ONAM, "Disable")
}
record(calcout, "$(P)$(M)_vCh") {
field(DESC, "change velocity")
field(CALC, "min(max(a*b,c),d)")
field(INPB, "$(P)$(M).S")
field(INPC, "$(P)$(M).SBAS")
field(INPD, "$(P)$(M).SMAX")
field(OUT, "$(P)$(M).S")
}
record(calcout, "$(P)$(M)_twCh") {
field(DESC, "change TWV")
field(CALC, "min(max(a*b,c),d-e)")
field(INPB, "$(P)$(M).TWV")
field(INPC, "$(P)$(M).MRES")
field(INPD, "$(P)$(M).HLM")
field(INPE, "$(P)$(M).LLM")
field(OUT, "$(P)$(M).TWV")
}
#! Further lines contain data used by VisualDCT
#! View(405,484,0.9)
#! Record("$(P)$(M)",840,675,0,0,"$(P)$(M)")
#! Field("$(P)$(M).DISP",16777215,1,"$(P)$(M).DISP")
#! Field("$(P)$(M).S",16777215,0,"$(P)$(M).S")
#! Field("$(P)$(M).SBAS",16777215,0,"$(P)$(M).SBAS")
#! Field("$(P)$(M).SMAX",16777215,0,"$(P)$(M).SMAX")
#! Field("$(P)$(M).TWV",16777215,0,"$(P)$(M).TWV")
#! Field("$(P)$(M).MRES",16777215,0,"$(P)$(M).MRES")
#! Field("$(P)$(M).HLM",16777215,0,"$(P)$(M).HLM")
#! Field("$(P)$(M).LLM",16777215,0,"$(P)$(M).LLM")
#! Field("$(P)$(M).SDIS",16777215,1,"$(P)$(M).SDIS")
#! Link("$(P)$(M).SDIS","$(P)$(M)_able.VAL")
#! Record("$(P)$(M)_able",1120,874,0,0,"$(P)$(M)_able")
#! Field("$(P)$(M)_able.OUT",16777215,0,"$(P)$(M)_able.OUT")
#! Link("$(P)$(M)_able.OUT","$(P)$(M).DISP")
#! Field("$(P)$(M)_able.VAL",16777215,0,"$(P)$(M)_able.VAL")
#! Record("$(P)$(M)_vCh",440,699,0,0,"$(P)$(M)_vCh")
#! Field("$(P)$(M)_vCh.OUT",16777215,1,"$(P)$(M)_vCh.OUT")
#! Link("$(P)$(M)_vCh.OUT","$(P)$(M).S")
#! Field("$(P)$(M)_vCh.INPB",16777215,1,"$(P)$(M)_vCh.INPB")
#! Link("$(P)$(M)_vCh.INPB","$(P)$(M).S")
#! Field("$(P)$(M)_vCh.INPC",16777215,1,"$(P)$(M)_vCh.INPC")
#! Link("$(P)$(M)_vCh.INPC","$(P)$(M).SBAS")
#! Field("$(P)$(M)_vCh.INPD",16777215,1,"$(P)$(M)_vCh.INPD")
#! Link("$(P)$(M)_vCh.INPD","$(P)$(M).SMAX")
#! Record("$(P)$(M)_twCh",440,925,0,0,"$(P)$(M)_twCh")
#! Field("$(P)$(M)_twCh.OUT",16777215,1,"$(P)$(M)_twCh.OUT")
#! Link("$(P)$(M)_twCh.OUT","$(P)$(M).TWV")
#! Field("$(P)$(M)_twCh.INPB",16777215,1,"$(P)$(M)_twCh.INPB")
#! Link("$(P)$(M)_twCh.INPB","$(P)$(M).TWV")
#! Field("$(P)$(M)_twCh.INPC",16777215,1,"$(P)$(M)_twCh.INPC")
#! Link("$(P)$(M)_twCh.INPC","$(P)$(M).MRES")
#! Field("$(P)$(M)_twCh.INPD",16777215,1,"$(P)$(M)_twCh.INPD")
#! Link("$(P)$(M)_twCh.INPD","$(P)$(M).HLM")
#! Field("$(P)$(M)_twCh.INPE",16777215,1,"$(P)$(M)_twCh.INPE")
#! Link("$(P)$(M)_twCh.INPE","$(P)$(M).LLM")
@@ -0,0 +1,2 @@
# FILE... motor_positions.req
$(P)$(M).DVAL
@@ -0,0 +1,4 @@
# FILE... motor_settings.req
file basic_motor_settings.req P=$(P),M=$(M)
$(P)$(M)_able.VAL
+1
View File
@@ -6,6 +6,7 @@ record(motor,"$(P)$(M)")
field(VELO,"$(VELO)")
field(VBAS,"$(VBAS)")
field(ACCL,"$(ACCL)")
field(ACCU,"$(ACCU=0)")
field(BDST,"$(BDST)")
field(BVEL,"$(BVEL)")
field(BACC,"$(BACC)")
+21
View File
@@ -0,0 +1,21 @@
record(motor,"$(P)$(M)")
{
field(DESC,"$(DESC)")
field(DTYP,"$(DTYP)")
field(DIR,"$(DIR)")
field(VELO,"$(VELO)")
field(VBAS,"$(VBAS)")
field(ACCL,"$(ACCL)")
field(ACCU,"$(ACCU=0)")
field(BDST,"$(BDST)")
field(BVEL,"$(BVEL)")
field(BACC,"$(BACC)")
field(OUT,"@asyn($(PORT),$(ADDR))")
field(MRES,"$(MRES)")
field(PREC,"$(PREC)")
field(EGU,"$(EGU)")
field(DHLM,"$(DHLM)")
field(DLLM,"$(DLLM)")
field(INIT,"$(INIT)")
field(TWV,"1")
}
@@ -0,0 +1,3 @@
# FILE... motor_settings.req
file basic_motor_settings.req P=$(P),M=$(M)
@@ -0,0 +1,3 @@
# FILE... motor_settings.req
file basic_motor_settings.req P=$(P),M=$(M)
+1
View File
@@ -6,6 +6,7 @@ grecord(motor,"$(P)$(M)")
field(VELO,"$(VELO)")
field(VBAS,"$(VBAS)")
field(ACCL,"$(ACCL)")
field(ACCU,"$(ACCU=0)")
field(BDST,"$(BDST)")
field(BVEL,"$(BVEL)")
field(BACC,"$(BACC)")
+1
View File
@@ -11,6 +11,7 @@ $(P)$(M).RRES
$(P)$(M).VBAS
$(P)$(M).VELO
$(P)$(M).ACCL
$(P)$(M).ACCU
$(P)$(M).BDST
$(P)$(M).BVEL
$(P)$(M).BACC
+1
View File
@@ -10,6 +10,7 @@ record(motor, "$(P)$(M)") {
field(VELO, "$(VELO)")
field(VBAS, "$(VBAS)")
field(ACCL, "$(ACCL)")
field(ACCU, "$(ACCU=0)")
field(BDST, "$(BDST)")
field(BVEL, "$(BVEL)")
field(BACC, "$(BACC)")
+1 -1
View File
@@ -1,4 +1,4 @@
ed $(P)$(R)Nelements
$(P)$(R)Nelements
$(P)$(R)MoveMode
$(P)$(R)Npulses
$(P)$(R)StartPulses
+24
View File
@@ -764,6 +764,30 @@ asynStatus asynMotorController::writeController(const char *output, double timeo
return status ;
}
/** Reads a string from the controller.
* Calls readController() with default locations of the input string and default timeout. */
asynStatus asynMotorController::readController()
{
size_t nread;
return readController(inString_, sizeof(inString_), &nread, DEFAULT_CONTROLLER_TIMEOUT);
}
/** Reads a string from the controller
* \param[out] input Pointer to the input string location.
* \param[in] maxChars Size of the input buffer.
* \param[out] nread Number of characters read.
* \param[out] timeout Timeout before returning an error.*/
asynStatus asynMotorController::readController(char *input, size_t maxChars, size_t *nread, double timeout)
{
asynStatus status;
int eomReason;
// const char *functionName="readController";
status = pasynOctetSyncIO->read(pasynUserController_, input, maxChars, timeout, nread, &eomReason);
return status;
}
/** Writes a string to the controller and reads the response.
* Calls writeReadController() with default locations of the input and output strings
* and default timeout. */
+2
View File
@@ -302,6 +302,8 @@ class epicsShareClass asynMotorController : public asynPortDriver {
/* These are convenience functions for controllers that use asynOctet interfaces to the hardware */
asynStatus writeController();
asynStatus writeController(const char *output, double timeout);
asynStatus readController();
asynStatus readController(char *response, size_t maxResponseLen, size_t *responseLen, double timeout);
asynStatus writeReadController();
asynStatus writeReadController(const char *output, char *response, size_t maxResponseLen, size_t *responseLen, double timeout);
asynUser *pasynUserController_;
+36 -25
View File
@@ -55,6 +55,7 @@
#include <asynDriver.h>
#include <asynInt32.h>
#include <asynFloat64SyncIO.h>
#include <asynFloat64.h>
#include <asynDrvUser.h>
#include <asynFloat64Array.h>
@@ -137,6 +138,7 @@ typedef struct
double param;
int needUpdate;
asynUser *pasynUser;
asynUser *pasynUserSync;
asynInt32 *pasynInt32;
void *asynInt32Pvt;
asynFloat64 *pasynFloat64;
@@ -148,7 +150,6 @@ typedef struct
asynGenericPointer *pasynGenericPointer;
void *asynGenericPointerPvt;
void *registrarPvt;
epicsEventId initEvent;
int driverReasons[NUM_MOTOR_COMMANDS];
} motorAsynPvt;
@@ -170,16 +171,30 @@ static void init_controller(struct motorRecord *pmr, asynUser *pasynUser )
motorAsynPvt *pPvt = (motorAsynPvt *)pmr->dpvt;
double position = pPvt->status.position;
double rdbd = (fabs(pmr->rdbd) < fabs(pmr->mres) ? fabs(pmr->mres) : fabs(pmr->rdbd) );
double encRatio[2] = {pmr->mres, pmr->eres};
int use_rel = (pmr->rtry != 0 && pmr->rmod != motorRMOD_I && (pmr->ueip || pmr->urip));
int dval_non_zero_pos_near_zero = (fabs(pmr->dval) > rdbd) &&
(pmr->mres != 0) && (fabs(position * pmr->mres) < rdbd);
epicsFloat64 eratio;
int initPos = 0;
int status;
/*Before setting position, set the correct encoder ratio.*/
start_trans(pmr);
build_trans(SET_ENC_RATIO, encRatio, pmr);
end_trans(pmr);
/* Don't let the encoder ratio be infinite */
if (pmr->eres == 0.0) {
eratio = 1.0;
} else {
eratio = pmr->mres / pmr->eres;
}
/* Write encoder ratio to the driver.*/
pPvt->pasynUserSync->reason = pPvt->driverReasons[motorEncRatio];
status = pasynFloat64SyncIO->write(pPvt->pasynUserSync, eratio, pasynUser->timeout);
if (status) {
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"devMotorAsyn::init_controller, %s failed to set encoder ratio to %f\n", pmr->name, eratio );
} else {
asynPrint(pasynUser, ASYN_TRACE_FLOW,
"devMotorAsyn::init_controller, %s set encoder ratio to %f\n", pmr->name, eratio );
}
switch (pmr->rstm) {
case motorRSTM_NearZero:
@@ -202,15 +217,11 @@ static void init_controller(struct motorRecord *pmr, asynUser *pasynUser )
if (initPos)
{
double setPos = pmr->dval / pmr->mres;
epicsEventId initEvent = epicsEventCreate( epicsEventEmpty );
RTN_STATUS rtnval;
pPvt->initEvent = initEvent;
start_trans(pmr);
rtnval = build_trans(LOAD_POS, &setPos, pmr);
end_trans(pmr);
if (rtnval != OK) {
/* Write setPos to the driver */
pPvt->pasynUserSync->reason = pPvt->driverReasons[motorPosition];
status = pasynFloat64SyncIO->write(pPvt->pasynUserSync, setPos, pasynUser->timeout);
if (status) {
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"devMotorAsyn::init_controller, %s failed to set position to %f\n",
pmr->name, setPos );
@@ -219,13 +230,6 @@ static void init_controller(struct motorRecord *pmr, asynUser *pasynUser )
"devMotorAsyn::init_controller, %s set position to %f\n",
pmr->name, setPos );
}
if ( initEvent )
{
epicsEventMustWait(initEvent);
epicsEventDestroy(initEvent);
pPvt->initEvent = 0;
}
}
else
asynPrint(pasynUser, ASYN_TRACE_FLOW,
@@ -307,6 +311,14 @@ static long init_record(struct motorRecord * pmr )
pPvt->pasynFloat64 = (asynFloat64 *)pasynInterface->pinterface;
pPvt->asynFloat64Pvt = pasynInterface->drvPvt;
/* Initialize Float64 synchronous interface */
status = pasynFloat64SyncIO->connect(port, signal, &pPvt->pasynUserSync, userParam);
if (status != asynSuccess) {
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"devMotorAsyn::init_record, %s connect Float64SyncIO interface failed\n", pmr->name);
goto bad;
}
/* Get the asynDrvUser interface */
pasynInterface = pasynManager->findInterface(pasynUser, asynDrvUserType, 1); if (!pasynInterface) {
asynPrint(pasynUser, ASYN_TRACE_ERROR,
@@ -408,6 +420,9 @@ static long init_record(struct motorRecord * pmr )
* set, a callback will be generated
*/
/* Finished using the Float64 SyncIO interface */
pasynFloat64SyncIO->disconnect(pPvt->pasynUserSync);
/* Finally, indicate to the motor record that these values can be used. */
pasynManager->freeAsynUser(pasynUser);
pPvt->needUpdate = 1;
@@ -721,10 +736,6 @@ static void asynCallback(asynUser *pasynUser)
"devMotorAsyn::asynCallback: %s error in freeAsynUser, %s\n",
pmr->name, pasynUser->errorMessage);
}
if ( pPvt->initEvent && pmsg->command == motorPosition) {
epicsEventSignal( pPvt->initEvent );
}
}
/**
+403 -109
View File
@@ -190,9 +190,10 @@ USAGE... Motor Record Support.
* .76 04-04-18 rls - If URIP is Yes and RDBL is inaccessible (e.g., CA server is down), do not start
* a new target position move (sans Home search or Jog).
* .78 08-21-18 kmp - Reverted .69 stop on RA_PROBLEM true.
* .79 21-11-22 jrh - Added raw limits, sync limits on motor resolution change
*/
#define VERSION 7.2
#define VERSION 7.3
#include <stdlib.h>
#include <string.h>
@@ -234,6 +235,8 @@ static void monitor(motorRecord *);
static void process_motor_info(motorRecord *, bool);
static void load_pos(motorRecord *);
static void check_speed_and_resolution(motorRecord *);
static void set_user_highlimit(motorRecord*, struct motor_dset*);
static void set_user_lowlimit(motorRecord*, struct motor_dset*);
static void set_dial_highlimit(motorRecord *, struct motor_dset *);
static void set_dial_lowlimit(motorRecord *, struct motor_dset *);
static void set_userlimits(motorRecord *);
@@ -383,6 +386,8 @@ typedef union
unsigned int M_JOGR :1;
unsigned int M_HOMF :1;
unsigned int M_HOMR :1;
unsigned int M_RHLM :1;
unsigned int M_RLLM :1;
} Bits;
} nmap_field;
@@ -475,6 +480,73 @@ static void callbackFunc(struct callback *pcb)
}
static double accEGUfromVelo(motorRecord *pmr, double veloEGU)
{
double vmin = pmr->vbas;
double vmax = fabs(veloEGU);
double acc;
/* ACCL or ACCS */
if (pmr->accu == motorACCU_Accs)
acc = pmr->accs;
else if (vmax > vmin)
acc = (vmax - vmin) / pmr->accl;
else
acc = vmax / pmr->accl;
return acc;
}
static void updateACCLfromACCS(motorRecord *pmr)
{
if (pmr->accs > 0.0)
{
double temp_dbl = (pmr->velo > pmr->vbas) ? (pmr->velo - pmr->vbas) / pmr->accs : pmr->velo / pmr->accs;
if (pmr->accl != temp_dbl)
{
pmr->accl = temp_dbl;
db_post_events(pmr, &pmr->accl, DBE_VAL_LOG);
}
}
}
static void updateACCSfromACCL(motorRecord *pmr)
{
double temp_dbl;
temp_dbl = (pmr->velo > pmr->vbas) ? (pmr->velo - pmr->vbas) / pmr->accl : pmr->velo / pmr->accl;
if (pmr->accs != temp_dbl)
{
pmr->accs = temp_dbl;
db_post_events(pmr, &pmr->accs, DBE_VAL_LOG);
}
}
static void updateACCL_ACCSfromVELO(motorRecord *pmr)
{
if (pmr->accu == motorACCU_Accs)
{
if (pmr->accs > 0.0)
{
double temp_dbl = (pmr->velo > pmr->vbas) ? (pmr->velo - pmr->vbas) / pmr->accs : pmr->velo / pmr->accs;
if (pmr->accl != temp_dbl)
{
pmr->accl = temp_dbl;
db_post_events(pmr, &pmr->accl, DBE_VAL_LOG);
}
}
}
else
{
double temp_dbl = (pmr->velo > pmr->vbas) ? (pmr->velo - pmr->vbas) / pmr->accl : pmr->velo / pmr->accl;
if (pmr->accs != temp_dbl)
{
pmr->accs = temp_dbl;
db_post_events(pmr, &pmr->accs, DBE_VAL_LOG);
}
}
}
/******************************************************************************
enforceMinRetryDeadband()
@@ -862,7 +934,7 @@ static long postProcess(motorRecord * pmr)
if (pmr->mip & MIP_JOG_STOP)
{
double acc = (vel - vbase) > 0 ? ((vel - vbase)/ pmr->accl) : (vel / pmr->accl);
double acc = accEGUfromVelo(pmr, pmr->velo) / fabs(pmr->mres);
if (vel <= vbase)
vel = vbase + 1;
@@ -1318,6 +1390,13 @@ static long process(dbCommon *arg)
!(pmr->mip & MIP_STOP) &&
!(pmr->mip & MIP_JOG_STOP))
{
if (pmr->mip == MIP_HOMF || pmr->mip == MIP_HOMR)
{
/* Bug fix: motor enters an infinite HOME loop
in a sequence where VAL HOMF VAL is written */
clear_buttons(pmr);
}
pmr->mip = MIP_DONE;
/* Bug fix, record locks-up when BDST != 0, DLY != 0 and
* new target position before backlash correction move.*/
@@ -2196,7 +2275,7 @@ static RTN_STATUS do_work(motorRecord * pmr, CALLBACK_VALUE proc_ind)
double newpos = pmr->dval / pmr->mres; /* where to go */
double vbase = pmr->vbas / fabs(pmr->mres); /* base speed */
double vel = pmr->velo / fabs(pmr->mres); /* normal speed */
double acc = (vel - vbase) > 0 ? ((vel - vbase) / pmr->accl) : (vel / pmr->accl); /* normal accel. */
double acc = accEGUfromVelo(pmr, pmr->velo) / fabs(pmr->mres);
/*
* 'bpos' is one backlash distance away from 'newpos'.
*/
@@ -2416,7 +2495,7 @@ static RTN_STATUS do_work(motorRecord * pmr, CALLBACK_VALUE proc_ind)
}
/* IF move is in preferred direction, AND, current position is within backlash range. */
else if ((preferred_dir == true) &&
((use_rel == true && relbpos <= 1.0) ||
((use_rel == true && ((pmr->bdst >= 0 && relbpos <= 1.0) || (pmr->bdst < 0 && relbpos >= 1.0))) ||
(use_rel == false && (fabs(newpos - currpos) <= rbdst1))
)
)
@@ -2501,7 +2580,7 @@ static long special(DBADDR *paddr, int after)
int dir = dir_positive ? 1 : -1;
bool changed = false;
int fieldIndex = dbGetFieldIndex(paddr);
double offset, tmp_raw, tmp_limit, fabs_urev;
double fabs_urev;
RTN_STATUS rtnval;
motor_cmnd command;
double temp_dbl;
@@ -2563,6 +2642,7 @@ static long special(DBADDR *paddr, int after)
pmr->sbas = temp_dbl;
db_post_events(pmr, &pmr->sbas, DBE_VAL_LOG);
}
updateACCL_ACCSfromVELO(pmr);
break;
/* new sbas: make vbas agree */
@@ -2578,6 +2658,7 @@ static long special(DBADDR *paddr, int after)
pmr->vbas = temp_dbl;
db_post_events(pmr, &pmr->vbas, DBE_VAL_LOG);
}
updateACCL_ACCSfromVELO(pmr);
break;
/* new vmax: make smax agree */
@@ -2613,6 +2694,7 @@ static long special(DBADDR *paddr, int after)
/* new velo: make s agree */
case motorRecordVELO:
range_check(pmr, &pmr->velo, pmr->vbas, pmr->vmax);
updateACCL_ACCSfromVELO(pmr);
if ((pmr->urev != 0.0) && (pmr->s != (temp_dbl = pmr->velo / fabs_urev)))
{
@@ -2630,6 +2712,7 @@ static long special(DBADDR *paddr, int after)
pmr->velo = temp_dbl;
db_post_events(pmr, &pmr->velo, DBE_VAL_LOG);
}
updateACCL_ACCSfromVELO(pmr);
break;
/* new bvel: make sbak agree */
@@ -2661,6 +2744,17 @@ static long special(DBADDR *paddr, int after)
pmr->accl = 0.1;
db_post_events(pmr, &pmr->accl, DBE_VAL_LOG);
}
updateACCSfromACCL(pmr);
break;
/* new accs */
case motorRecordACCS:
if (pmr->accs <= 0.0)
{
updateACCSfromACCL(pmr);
}
//db_post_events(pmr, &pmr->accs, DBE_VAL_LOG);
updateACCLfromACCS(pmr);
break;
/* new bacc */
@@ -2706,110 +2800,12 @@ static long special(DBADDR *paddr, int after)
/* new user high limit */
case motorRecordHLM:
offset = pmr->off;
if (dir_positive)
{
tmp_limit = pmr->hlm - offset;
MARK(M_DHLM);
}
else
{
tmp_limit = -(pmr->hlm) + offset;
MARK(M_DLLM);
}
/* Which controller limit we set depends not only on dir, but
also on the sign of MRES */
/* Direction +ve AND +ve MRES OR
Direction -ve AND -ve MRES */
if (dir_positive ^ (pmr->mres < 0))
{
command = SET_HIGH_LIMIT;
}
else
/* Direction -ve AND +ve MRES OR
Direction +ve AND -ve MRES */
{
command = SET_LOW_LIMIT;
}
tmp_raw = tmp_limit / pmr->mres;
INIT_MSG();
rtnval = (*pdset->build_trans)(command, &tmp_raw, pmr);
if (rtnval != OK)
{
/* If an error occured, build_trans() has reset
* dial high or low limit to controller's value. */
if (dir_positive)
pmr->hlm = pmr->dhlm + offset;
else
pmr->hlm = -(pmr->dllm) + offset;
}
else
{
SEND_MSG();
if (dir_positive)
pmr->dhlm = tmp_limit;
else
pmr->dllm = tmp_limit;
}
MARK(M_HLM);
set_user_highlimit(pmr, pdset);
break;
/* new user low limit */
case motorRecordLLM:
offset = pmr->off;
if (dir_positive)
{
tmp_limit = pmr->llm - offset;
MARK(M_DLLM);
}
else
{
tmp_limit = -(pmr->llm) + offset;
MARK(M_DHLM);
}
/* Which controller limit we set depends not only on dir, but
also on the sign of MRES */
/* Direction +ve AND +ve MRES OR
Direction -ve AND -ve MRES */
if (dir_positive ^ (pmr->mres < 0))
{
command = SET_LOW_LIMIT;
}
else
/* Direction -ve AND +ve MRES OR
Direction +ve AND -ve MRES */
{
command = SET_HIGH_LIMIT;
}
tmp_raw = tmp_limit / pmr->mres;
INIT_MSG();
rtnval = (*pdset->build_trans)(command, &tmp_raw, pmr);
if (rtnval != OK)
{
/* If an error occured, build_trans() has reset
* dial high or low limit to controller's value. */
if (dir_positive)
pmr->llm = pmr->dllm + offset;
else
pmr->llm = -(pmr->dhlm) + offset;
}
else
{
SEND_MSG();
if (dir_positive)
pmr->dllm = tmp_limit;
else
pmr->dhlm = tmp_limit;
}
MARK(M_LLM);
set_user_lowlimit(pmr, pdset);
break;
/* new dial high limit */
@@ -2883,6 +2879,40 @@ velcheckB:
pmr->vmax = temp_dbl;
db_post_events(pmr, &pmr->vmax, DBE_VAL_LOG);
}
/* We may have new MRES */
if (pmr->mres > 0)
{
if (pmr->dllm != (temp_dbl = pmr->rllm * pmr->mres))
{
pmr->dllm = temp_dbl;
db_post_events(pmr, &pmr->dllm, DBE_VAL_LOG);
}
if (pmr->dhlm != (temp_dbl = pmr->rhlm * pmr->mres))
{
pmr->dhlm = temp_dbl;
db_post_events(pmr, &pmr->dhlm, DBE_VAL_LOG);
}
}
else
{
// MRES < 0 swaps DHLM DLLM
if (pmr->dhlm != (temp_dbl = pmr->rllm * pmr->mres))
{
pmr->dhlm = temp_dbl;
db_post_events(pmr, &pmr->dhlm, DBE_VAL_LOG);
}
if (pmr->dllm != (temp_dbl = pmr->rhlm * pmr->mres))
{
pmr->dllm = temp_dbl;
db_post_events(pmr, &pmr->dllm, DBE_VAL_LOG);
}
set_userlimits(pmr);
db_post_events(pmr, &pmr->hlm, DBE_VAL_LOG);
db_post_events(pmr, &pmr->llm, DBE_VAL_LOG);
}
set_userlimits(pmr);
db_post_events(pmr, &pmr->hlm, DBE_VAL_LOG);
db_post_events(pmr, &pmr->llm, DBE_VAL_LOG);
break;
/* new srev: make mres agree */
@@ -3613,6 +3643,10 @@ static void monitor(motorRecord * pmr)
db_post_events(pmr, &pmr->homf, local_mask);
if ((local_mask = monitor_mask | (MARKED_AUX(M_HOMR) ? DBE_VAL_LOG : 0)))
db_post_events(pmr, &pmr->homr, local_mask);
if ((local_mask = monitor_mask | (MARKED_AUX(M_RHLM) ? DBE_VAL_LOG : 0)))
db_post_events(pmr, &pmr->rhlm, local_mask);
if ((local_mask = monitor_mask | (MARKED_AUX(M_RLLM) ? DBE_VAL_LOG : 0)))
db_post_events(pmr, &pmr->rllm, local_mask);
UNMARK_ALL;
}
@@ -3639,6 +3673,12 @@ static void process_motor_info(motorRecord * pmr, bool initcall)
/* Calculate raw and dial readback values. */
msta.All = pmr->msta;
if ((pmr->ueip == motorUEIP_Yes) && (!(msta.Bits.EA_PRESENT)))
{
pmr->ueip = motorUEIP_No;
db_post_events(pmr, &pmr->ueip, DBE_VAL_LOG);
}
if (pmr->ueip == motorUEIP_Yes)
{
/* An encoder is present and the user wants us to use it. */
@@ -3830,6 +3870,20 @@ static void load_pos(motorRecord * pmr)
* Range check; VBAS < VELO < VMAX.
* S < - VELO / |UREV|.
* ENDIF
*
* IF RLLM is nonzero.
* DLLM < - RLLM * MRES.
* ENDIF
* IF RLLM is not DLLM / MRES.
* RLLM < - DLLM / MRES.
* ENDIF
*
* IF RHLM is nonzero.
* DHLM < - RHLM * MRES.
* ENDIF
* IF RHLM is not DHLM / MRES.
* RHLM < - DHLM / MRES.
* ENDIF
*
* IF SBAK is nonzero.
* Range check; SBAS < SBAK < SMAX.
@@ -3919,6 +3973,57 @@ static void check_speed_and_resolution(motorRecord * pmr)
db_post_events(pmr, &pmr->velo, DBE_VAL_LOG);
db_post_events(pmr, &pmr->s, DBE_VAL_LOG);
if (pmr->mres > 0)
{
/* RLLM <--> DLLM */
if (pmr->rllm != 0.0)
{
pmr->dllm = pmr->rllm * pmr->mres;
MARK(M_DLLM);
}
if (pmr->rllm != pmr->dllm / pmr->mres)
{
pmr->rllm = pmr->dllm / pmr->mres;
MARK_AUX(M_RLLM);
}
/* RHLM <--> DHLM */
if (pmr->rhlm != 0.0)
{
pmr->dhlm = pmr->rhlm * pmr->mres;
MARK(M_DHLM);
}
if (pmr->rhlm != pmr->dhlm / pmr->mres)
{
pmr->rhlm = pmr->dhlm / pmr->mres;
MARK_AUX(M_RHLM);
}
}
else
{
/* RLLM <--> DHLM */
if (pmr->rllm != 0.0)
{
pmr->dhlm = pmr->rllm * fabs(pmr->mres);
MARK(M_DHLM);
}
if (pmr->rllm != pmr->dhlm / fabs(pmr->mres))
{
pmr->rllm = pmr->dhlm / fabs(pmr->mres);
MARK_AUX(M_RLLM);
}
/* RHLM <--> DLLM */
if (pmr->rhlm != 0.0)
{
pmr->dllm = pmr->rhlm * fabs(pmr->mres);
MARK(M_DLLM);
}
if (pmr->rhlm != pmr->dllm / fabs(pmr->mres))
{
pmr->rhlm = pmr->dllm / fabs(pmr->mres);
MARK_AUX(M_RHLM);
}
}
/* SBAK (revolutions/sec) <--> BVEL (EGU/sec) */
if (pmr->sbak != 0.0)
{
@@ -3933,12 +4038,22 @@ static void check_speed_and_resolution(motorRecord * pmr)
db_post_events(pmr, &pmr->sbak, DBE_VAL_LOG);
db_post_events(pmr, &pmr->bvel, DBE_VAL_LOG);
/* Sanity check on acceleration time. */
if (pmr->accl == 0.0)
/* ACCS (EGU/sec^2) <--> ACCL (sec) */
if (pmr->accs > 0.0)
{
pmr->accl = 0.1;
db_post_events(pmr, &pmr->accl, DBE_VAL_LOG);
updateACCLfromACCS(pmr);
}
else
{
/* Sanity check on acceleration time. */
if (pmr->accl == 0.0)
{
pmr->accl = 0.1;
db_post_events(pmr, &pmr->accl, DBE_VAL_LOG);
}
updateACCSfromACCL(pmr);
}
/* Sanity check on backlash acceleration time. */
if (pmr->bacc == 0.0)
{
pmr->bacc = 0.1;
@@ -3960,6 +4075,164 @@ static void check_speed_and_resolution(motorRecord * pmr)
range_check(pmr, &pmr->hvel, pmr->vbas, pmr->vmax);
}
/*
FUNCTION... void set_user_highlimit(motorRecord *)
USAGE... Set user high limit.
NOTES... This function sends a command to the device to set the user high
limit. This is respective to the direction of the motor.
*/
static void set_user_highlimit(motorRecord* pmr, struct motor_dset* pdset)
{
int dir_positive = (pmr->dir == motorDIR_Pos);
double tmp_limit, offset, tmp_raw;
motor_cmnd command;
RTN_STATUS rtnval;
offset = pmr->off;
if (dir_positive)
{
tmp_limit = pmr->hlm - offset;
MARK(M_DHLM);
}
else
{
tmp_limit = -(pmr->hlm) + offset;
MARK(M_DLLM);
}
/* Which controller limit we set depends not only on dir, but
also on the sign of MRES */
/* Direction +ve AND +ve MRES OR
Direction -ve AND -ve MRES */
if (dir_positive ^ (pmr->mres < 0))
{
command = SET_HIGH_LIMIT;
}
else
/* Direction -ve AND +ve MRES OR
Direction +ve AND -ve MRES */
{
command = SET_LOW_LIMIT;
}
tmp_raw = tmp_limit / pmr->mres;
INIT_MSG();
rtnval = (*pdset->build_trans)(command, &tmp_raw, pmr);
if (rtnval != OK)
{
/* If an error occured, build_trans() has reset
* dial high or low limit to controller's value. */
if (dir_positive)
pmr->hlm = pmr->dhlm + offset;
else
pmr->hlm = -(pmr->dllm) + offset;
}
else
{
// set dial and raw limits
SEND_MSG();
if (dir_positive)
{
pmr->dhlm = tmp_limit;
}
else
{
pmr->dllm = tmp_limit;
}
if (command == SET_HIGH_LIMIT)
{
pmr->rhlm = tmp_raw;
MARK_AUX(M_RHLM);
}
else
{
pmr->rllm = tmp_raw;
MARK_AUX(M_RLLM);
}
}
MARK(M_HLM);
}
/*
FUNCTION... void set_user_lowlimit(motorRecord *)
USAGE... Set user low limit.
NOTES... This function sends a command to the device to set the user low
limit. This is respective to the direction of the motor.
*/
static void set_user_lowlimit(motorRecord* pmr, struct motor_dset* pdset)
{
int dir_positive = (pmr->dir == motorDIR_Pos);
double tmp_limit, offset, tmp_raw;
motor_cmnd command;
RTN_STATUS rtnval;
offset = pmr->off;
if (dir_positive)
{
tmp_limit = pmr->llm - offset;
MARK(M_DLLM);
}
else
{
tmp_limit = -(pmr->llm) + offset;
MARK(M_DHLM);
}
/* Which controller limit we set depends not only on dir, but
also on the sign of MRES */
/* Direction +ve AND +ve MRES OR
Direction -ve AND -ve MRES */
if (dir_positive ^ (pmr->mres < 0))
{
command = SET_LOW_LIMIT;
}
else
/* Direction -ve AND +ve MRES OR
Direction +ve AND -ve MRES */
{
command = SET_HIGH_LIMIT;
}
tmp_raw = tmp_limit / pmr->mres;
INIT_MSG();
rtnval = (*pdset->build_trans)(command, &tmp_raw, pmr);
if (rtnval != OK)
{
/* If an error occured, build_trans() has reset
* dial high or low limit to controller's value. */
if (dir_positive)
pmr->llm = pmr->dllm + offset;
else
pmr->llm = -(pmr->dhlm) + offset;
}
else
{
// set dial and raw limits
SEND_MSG();
if (dir_positive) {
pmr->dllm = tmp_limit;
}
else
{
pmr->dhlm = tmp_limit;
}
if (command == SET_HIGH_LIMIT)
{
pmr->rhlm = tmp_raw;
MARK_AUX(M_RHLM);
}
else
{
pmr->rllm = tmp_raw;
MARK_AUX(M_RLLM);
}
}
MARK(M_LLM);
}
/*
FUNCTION... void set_dial_highlimit(motorRecord *)
USAGE... Set dial-coordinate high limit.
@@ -3976,6 +4249,7 @@ static void set_dial_highlimit(motorRecord *pmr, struct motor_dset *pdset)
RTN_STATUS rtnval;
tmp_raw = pmr->dhlm / pmr->mres;
INIT_MSG();
if (pmr->mres < 0) {
command = SET_LOW_LIMIT;
@@ -3997,6 +4271,16 @@ static void set_dial_highlimit(motorRecord *pmr, struct motor_dset *pdset)
pmr->llm = -(pmr->dhlm) + offset;
MARK(M_LLM);
}
if (command == SET_HIGH_LIMIT)
{
pmr->rhlm = tmp_raw;
MARK_AUX(M_RHLM);
}
else
{
pmr->rllm = tmp_raw;
MARK_AUX(M_RLLM);
}
MARK(M_DHLM);
}
@@ -4038,6 +4322,16 @@ static void set_dial_lowlimit(motorRecord *pmr, struct motor_dset *pdset)
pmr->hlm = -(pmr->dllm) + offset;
MARK(M_HLM);
}
if (command == SET_HIGH_LIMIT)
{
pmr->rhlm = tmp_raw;
MARK_AUX(M_RHLM);
}
else
{
pmr->rllm = tmp_raw;
MARK_AUX(M_RLLM);
}
MARK(M_DLLM);
}
+41 -1
View File
@@ -68,13 +68,16 @@ menu(motorRMOD) {
choice(motorRMOD_G,"Geometric")
choice(motorRMOD_I,"In-Position")
}
menu(motorRSTM) {
choice(motorRSTM_Never, "Never")
choice(motorRSTM_Always, "Always")
choice(motorRSTM_NearZero, "NearZero")
choice(motorRSTM_Conditional, "Conditional")
}
menu(motorACCU) {
choice(motorACCU_Accl, "Use ACCL")
choice(motorACCU_Accs, "Use ACCS")
}
include "menuOmsl.dbd"
@@ -148,12 +151,14 @@ recordtype(motor) {
promptgroup(GUI_COMMON)
special(SPC_MOD)
interest(1)
prop(YES) # get_graphic_double, get_control_double
}
field(VMAX,DBF_DOUBLE) {
prompt("Max. Velocity (EGU/s)")
promptgroup(GUI_COMMON)
special(SPC_MOD)
interest(1)
prop(YES) # get_graphic_double, get_control_double
}
field(S,DBF_DOUBLE) {
prompt("Speed (revolutions/sec)")
@@ -180,6 +185,18 @@ recordtype(motor) {
interest(1)
initial("0.2")
}
field(ACCS,DBF_DOUBLE) {
prompt("Move Accel. (EGU/s^2)")
promptgroup(GUI_COMMON)
special(SPC_MOD)
interest(1)
}
field(ACCU,DBF_MENU) {
prompt("Acceleration used")
special(SPC_MOD)
menu(motorACCU)
initial("0")
}
field(BDST,DBF_DOUBLE) {
prompt("BL Distance (EGU)")
asl(ASL0)
@@ -269,6 +286,7 @@ recordtype(motor) {
special(SPC_MOD)
pp(TRUE)
interest(1)
prop(YES) # get_graphic_double, get_control_double
}
field(ERES,DBF_DOUBLE) {
prompt("Encoder Step Size (EGU)")
@@ -302,34 +320,52 @@ recordtype(motor) {
prompt("Display Precision")
promptgroup(GUI_COMMON)
interest(1)
prop(YES) # get_precision
}
field(EGU,DBF_STRING) {
prompt("Engineering Units")
promptgroup(GUI_COMMON)
interest(1)
size(16)
prop(YES) # get_units
}
field(RHLM,DBF_DOUBLE) {
prompt("Raw High Limit")
promptgroup(GUI_COMMON)
special(SPC_NOMOD)
interest(1)
}
field(RLLM,DBF_DOUBLE) {
prompt("Raw Low Limit")
promptgroup(GUI_COMMON)
special(SPC_NOMOD)
interest(1)
}
field(HLM,DBF_DOUBLE) {
prompt("User High Limit")
special(SPC_MOD)
pp(TRUE)
prop(YES) # get_graphic_double, get_control_double
}
field(LLM,DBF_DOUBLE) {
prompt("User Low Limit")
special(SPC_MOD)
pp(TRUE)
prop(YES) # get_graphic_double, get_control_double
}
field(DHLM,DBF_DOUBLE) {
prompt("Dial High Limit")
promptgroup(GUI_COMMON)
special(SPC_MOD)
pp(TRUE)
prop(YES) # get_graphic_double, get_control_double
}
field(DLLM,DBF_DOUBLE) {
prompt("Dial Low Limit")
promptgroup(GUI_COMMON)
special(SPC_MOD)
pp(TRUE)
prop(YES) # get_graphic_double, get_control_double
}
field(HOPR,DBF_DOUBLE) {
prompt("High Operating Range")
@@ -362,24 +398,28 @@ recordtype(motor) {
promptgroup(GUI_COMMON)
pp(TRUE)
interest(2)
prop(YES) # get_alarm_double
}
field(LOLO,DBF_DOUBLE) {
prompt("Lolo Alarm Limit (EGU)")
promptgroup(GUI_COMMON)
pp(TRUE)
interest(2)
prop(YES) # get_alarm_double
}
field(HIGH,DBF_DOUBLE) {
prompt("High Alarm Limit (EGU)")
promptgroup(GUI_COMMON)
pp(TRUE)
interest(2)
prop(YES) # get_alarm_double
}
field(LOW,DBF_DOUBLE) {
prompt("Low Alarm Limit (EGU)")
promptgroup(GUI_COMMON)
pp(TRUE)
interest(2)
prop(YES) # get_alarm_double
}
field(HHSV,DBF_MENU) {
prompt("Hihi Severity")
+17 -14
View File
@@ -1,12 +1,12 @@
file {
name="/home/oxygen/MOONEY/epics/synApps/support/motor/motorApp/op/adl/motorx_all.adl"
version=030107
name="/home/epics/support/motor/motorApp/op/adl/motorx_all.adl"
version=030117
}
display {
object {
x=188
y=29
y=31
width=450
height=875
}
@@ -87,6 +87,17 @@ display {
1a7309,
}
}
rectangle {
object {
x=0
y=0
width=450
height=26
}
"basic attribute" {
clr=1
}
}
rectangle {
object {
x=80
@@ -597,6 +608,7 @@ text {
clr=14
bclr=1
}
format="string"
limits {
}
}
@@ -1237,17 +1249,6 @@ text {
textix="SET"
align="horiz. centered"
}
rectangle {
object {
x=0
y=0
width=450
height=26
}
"basic attribute" {
clr=1
}
}
"text entry" {
object {
x=0
@@ -1260,6 +1261,7 @@ rectangle {
clr=54
bclr=1
}
format="string"
limits {
}
}
@@ -1306,6 +1308,7 @@ text {
bclr=1
}
align="horiz. centered"
format="string"
limits {
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+69 -70
View File
@@ -5,7 +5,7 @@
<property name="geometry">
<rect>
<x>188</x>
<y>29</y>
<y>31</y>
<width>450</width>
<height>875</height>
</rect>
@@ -14,7 +14,6 @@
<string>
QWidget#centralWidget {background: rgba(200, 200, 200, 255);}
QPushButton::menu-indicator {image: url(none.png); width: 0}
caTable {
font: 10pt;
@@ -108,6 +107,39 @@ border-radius: 2px;
</property>
<widget class="QWidget" name="centralWidget">
<widget class="caGraphics" name="caRectangle_0">
<property name="form">
<enum>caGraphics::Rectangle</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>450</width>
<height>26</height>
</rect>
</property>
<property name="foreground">
<color alpha="255">
<red>236</red>
<green>236</green>
<blue>236</blue>
</color>
</property>
<property name="fillstyle">
<enum>Filled</enum>
</property>
<property name="lineColor">
<color alpha="255">
<red>236</red>
<green>236</green>
<blue>236</blue>
</color>
</property>
<property name="linestyle">
<enum>Solid</enum>
</property>
</widget>
<widget class="caGraphics" name="caRectangle_1">
<property name="form">
<enum>caGraphics::Rectangle</enum>
</property>
@@ -149,7 +181,7 @@ border-radius: 2px;
<string>$(P)$(M)_able.VAL</string>
</property>
</widget>
<widget class="caGraphics" name="caRectangle_1">
<widget class="caGraphics" name="caRectangle_2">
<property name="form">
<enum>caGraphics::Rectangle</enum>
</property>
@@ -363,7 +395,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>1,1;448,1;</string>
<string>448,1;</string>
</property>
</widget>
<widget class="caTextEntry" name="caTextEntry_0">
@@ -1358,10 +1390,10 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>1,1;448,1;</string>
<string>448,1;</string>
</property>
</widget>
<widget class="caGraphics" name="caRectangle_2">
<widget class="caGraphics" name="caRectangle_3">
<property name="form">
<enum>caGraphics::Rectangle</enum>
</property>
@@ -1562,10 +1594,10 @@ border-radius: 2px;
<enum>caLineEdit::Static</enum>
</property>
<property name="formatType">
<enum>decimal</enum>
<enum>string</enum>
</property>
</widget>
<widget class="caGraphics" name="caRectangle_3">
<widget class="caGraphics" name="caRectangle_4">
<property name="form">
<enum>caGraphics::Rectangle</enum>
</property>
@@ -1676,7 +1708,7 @@ border-radius: 2px;
</rect>
</property>
</widget>
<widget class="caGraphics" name="caRectangle_4">
<widget class="caGraphics" name="caRectangle_5">
<property name="form">
<enum>caGraphics::Rectangle</enum>
</property>
@@ -1722,7 +1754,7 @@ border-radius: 2px;
<string>$(P)$(M).HOMF</string>
</property>
</widget>
<widget class="caGraphics" name="caRectangle_5">
<widget class="caGraphics" name="caRectangle_6">
<property name="form">
<enum>caGraphics::Rectangle</enum>
</property>
@@ -2767,7 +2799,7 @@ border-radius: 2px;
<height>24</height>
</rect>
</property>
<widget class="caGraphics" name="caRectangle_6">
<widget class="caGraphics" name="caRectangle_7">
<property name="form">
<enum>caGraphics::Rectangle</enum>
</property>
@@ -2813,7 +2845,7 @@ border-radius: 2px;
<string>$(P)$(M).SET</string>
</property>
</widget>
<widget class="caGraphics" name="caRectangle_7">
<widget class="caGraphics" name="caRectangle_8">
<property name="form">
<enum>caGraphics::Rectangle</enum>
</property>
@@ -3206,7 +3238,7 @@ border-radius: 2px;
<enum>caChoice::Static</enum>
</property>
</widget>
<widget class="caGraphics" name="caRectangle_8">
<widget class="caGraphics" name="caRectangle_9">
<property name="form">
<enum>caGraphics::Rectangle</enum>
</property>
@@ -3341,39 +3373,6 @@ border-radius: 2px;
</rect>
</property>
</widget>
<widget class="caGraphics" name="caRectangle_9">
<property name="form">
<enum>caGraphics::Rectangle</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>450</width>
<height>26</height>
</rect>
</property>
<property name="foreground">
<color alpha="255">
<red>236</red>
<green>236</green>
<blue>236</blue>
</color>
</property>
<property name="fillstyle">
<enum>Filled</enum>
</property>
<property name="lineColor">
<color alpha="255">
<red>236</red>
<green>236</green>
<blue>236</blue>
</color>
</property>
<property name="linestyle">
<enum>Solid</enum>
</property>
</widget>
<widget class="caTextEntry" name="caTextEntry_21">
<property name="geometry">
<rect>
@@ -3422,7 +3421,7 @@ border-radius: 2px;
<enum>caLineEdit::Static</enum>
</property>
<property name="formatType">
<enum>decimal</enum>
<enum>string</enum>
</property>
</widget>
<widget class="caPolyLine" name="caPolyLine_2">
@@ -3462,7 +3461,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>1,1;447,1;</string>
<string>447,1;</string>
</property>
</widget>
<widget class="caLabel" name="caLabel_29">
@@ -3549,7 +3548,7 @@ border-radius: 2px;
<double>1.0</double>
</property>
<property name="formatType">
<enum>decimal</enum>
<enum>string</enum>
</property>
<property name="colorMode">
<enum>caLineEdit::Static</enum>
@@ -3796,7 +3795,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>0,0;0,187;</string>
<string>0,187;</string>
</property>
</widget>
<widget class="caPolyLine" name="caPolyLine_4">
@@ -3833,7 +3832,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>0,0;0,187;</string>
<string>0,187;</string>
</property>
</widget>
<widget class="caFrame" name="caFrame_3">
@@ -3947,7 +3946,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>0,0;22,0;</string>
<string>22,0;</string>
</property>
</widget>
</widget>
@@ -4062,7 +4061,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>0,0;22,0;</string>
<string>22,0;</string>
</property>
</widget>
</widget>
@@ -4177,7 +4176,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>0,0;22,0;</string>
<string>22,0;</string>
</property>
</widget>
</widget>
@@ -4400,7 +4399,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>0,0;22,0;</string>
<string>22,0;</string>
</property>
</widget>
</widget>
@@ -4533,7 +4532,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>2,1;1,345;</string>
<string>1,345;</string>
</property>
</widget>
<widget class="caGraphics" name="caRectangle_12">
@@ -6609,7 +6608,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>0,0;22,0;</string>
<string>22,0;</string>
</property>
</widget>
</widget>
@@ -6724,7 +6723,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>0,0;22,0;</string>
<string>22,0;</string>
</property>
</widget>
</widget>
@@ -6839,7 +6838,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>0,0;22,0;</string>
<string>22,0;</string>
</property>
</widget>
</widget>
@@ -7178,7 +7177,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>1,1;448,1;</string>
<string>448,1;</string>
</property>
</widget>
<widget class="caGraphics" name="caRectangle_13">
@@ -7251,7 +7250,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>1,1;448,1;</string>
<string>448,1;</string>
</property>
</widget>
<widget class="caLabel" name="caLabel_77">
@@ -7432,7 +7431,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>0,0;0,55;</string>
<string>0,55;</string>
</property>
</widget>
<widget class="caPolyLine" name="caPolyLine_16">
@@ -7469,7 +7468,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>0,0;0,55;</string>
<string>0,55;</string>
</property>
</widget>
<widget class="caTextEntry" name="caTextEntry_31">
@@ -7695,7 +7694,7 @@ border-radius: 2px;
<enum>Solid</enum>
</property>
<property name="xyPairs">
<string>1,2;259,1;</string>
<string>259,1;</string>
</property>
</widget>
<widget class="caLabel" name="caLabel_81">
@@ -8319,6 +8318,7 @@ border-radius: 2px;
</widget>
<zorder>caRectangle_0</zorder>
<zorder>caRectangle_1</zorder>
<zorder>caRectangle_2</zorder>
<zorder>caLabel_0</zorder>
<zorder>caLabel_1</zorder>
<zorder>caLabel_2</zorder>
@@ -8334,23 +8334,23 @@ border-radius: 2px;
<zorder>caFrame_0</zorder>
<zorder>caLabel_11</zorder>
<zorder>caPolyLine_1</zorder>
<zorder>caRectangle_2</zorder>
<zorder>caRectangle_3</zorder>
<zorder>caLabel_12</zorder>
<zorder>caLabel_13</zorder>
<zorder>caLabel_14</zorder>
<zorder>caRectangle_3</zorder>
<zorder>caRectangle_4</zorder>
<zorder>caLabel_15</zorder>
<zorder>caLabel_16</zorder>
<zorder>caRectangle_4</zorder>
<zorder>caRectangle_5</zorder>
<zorder>caRectangle_6</zorder>
<zorder>caLabel_17</zorder>
<zorder>caLabel_18</zorder>
<zorder>caLabel_19</zorder>
<zorder>caGraphics_0</zorder>
<zorder>caGraphics_1</zorder>
<zorder>caLabel_20</zorder>
<zorder>caRectangle_6</zorder>
<zorder>caRectangle_7</zorder>
<zorder>caRectangle_8</zorder>
<zorder>caFrame_1</zorder>
<zorder>caLabel_21</zorder>
<zorder>caLabel_22</zorder>
@@ -8360,9 +8360,8 @@ border-radius: 2px;
<zorder>caLabel_26</zorder>
<zorder>caFrame_2</zorder>
<zorder>caLabel_27</zorder>
<zorder>caRectangle_8</zorder>
<zorder>caLabel_28</zorder>
<zorder>caRectangle_9</zorder>
<zorder>caLabel_28</zorder>
<zorder>caPolyLine_2</zorder>
<zorder>caLabel_29</zorder>
<zorder>caLabel_30</zorder>