diff --git a/.appveyor.yml b/.appveyor.yml
new file mode 100644
index 0000000..7590fb7
--- /dev/null
+++ b/.appveyor.yml
@@ -0,0 +1,170 @@
+# .appveyor.yml for use with EPICS Base ci-scripts
+# (see: https://github.com/epics-base/ci-scripts)
+
+# This is YAML - indentation levels are crucial
+
+#---------------------------------#
+# build cache #
+#---------------------------------#
+# The AppVeyor cache allowance is way too small (1GB per account across all projects, branches and jobs)
+# to be used for the dependency builds.
+
+cache:
+ - C:\Users\appveyor\.tools
+
+#---------------------------------#
+# repository cloning #
+#---------------------------------#
+
+# Called at very beginning, before repo cloning
+init:
+ # Set autocrlf to make batch files work
+ - git config --global core.autocrlf true
+ # print the connection info for RDP connections (see 'debugging' below)
+ #- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
+
+# Set clone depth (do not fetch complete history)
+clone_depth: 5
+
+# Skipping commits affecting only specific files
+skip_commits:
+ files:
+ - 'documentation/*'
+ - 'templates/*'
+ - '**/*.html'
+ - '**/*.md'
+ - '.travis.yml'
+
+#---------------------------------#
+# additional packages #
+#---------------------------------#
+
+install:
+# fetch submodules (like ci-scripts)
+ - cmd: git submodule update --init --recursive
+# for the sequencer
+ - cinst re2c
+
+#---------------------------------#
+# build matrix configuration #
+#---------------------------------#
+
+# Since dependencies cannot be cached and AppVeyor only grants a single builder VM, all jobs
+# are executed sequentially, each one taking 10-15 minutes.
+# Consider this when defining your build matrix. (A full matrix build takes more than 8 hours.)
+
+# Default build worker image
+image: Visual Studio 2015
+
+# Build Configurations: shared/static, optimized/debug
+configuration:
+ - default
+ - static
+ - debug
+ - static-debug
+
+# Environment variables
+
+# Well-known variables to use
+# CMP compiler to use ('gcc' for native MinGW, 'vs...' for Visual Studio)
+# SET source setup file
+# ADD_MODULES extra modules (for a specific job)
+# TEST set to NO to skip running the tests (default: YES)
+# VV set VV=1 to make build scripts verbose (default: unset)
+# EXTRA content will be added to make command line
+# EXTRA1..5 more additional arguments for the make command
+# (one argument per variable)
+
+# Usually from setup files, but may be specified or overridden
+# on a job line
+# MODULES list of dependency modules
+# BASE branch or release tag name of the EPICS Base to use
+# branch or release tag for a specific module
+# ... see README for setup file syntax description
+
+# AppVeyor specific
+# APPVEYOR_BUILD_WORKER_IMAGE run job using specified VM image
+# (not the one from the image: line above)
+
+environment:
+ # common / default variables for all jobs
+ SETUP_PATH: .ci-local:.ci
+
+ matrix:
+ - CMP: vs2019
+ BASE: "7.0"
+ SET: "deps2"
+ APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+ - CMP: gcc
+ BASE: "7.0"
+ SET: "deps2"
+ - CMP: vs2019
+ BASE: "3.15"
+ SET: "deps2"
+ APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+ - CMP: vs2019
+ BASE: "3.14"
+ SET: "deps1"
+ APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+ #- CMP: vs2017
+ # BASE: "7.0"
+ # SET: "deps2"
+ # APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ - CMP: vs2015
+ BASE: "7.0"
+ SET: "deps2"
+ #- CMP: vs2013
+ # BASE: "7.0"
+ # SET: "deps2"
+
+# Platform: processor architecture
+platform:
+ - x86
+ - x64
+
+# Matrix configuration: exclude sets of jobs
+matrix:
+ exclude:
+ # Exclude more jobs to reduce build time
+ # E.g., skip 32-bit for newer compilers
+ - platform: x86
+ CMP: vs2019
+ #- platform: x86
+ # CMP: vs2015
+
+#---------------------------------#
+# building & testing #
+#---------------------------------#
+
+build_script:
+ - cmd: python .ci/cue.py prepare
+ - cmd: python .ci/cue.py build
+
+test_script:
+ - cmd: python .ci/cue.py -T 20M test
+
+on_finish:
+ - ps: Get-ChildItem *.tap -Recurse -Force | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
+ - cmd: python .ci/cue.py -T 5M test-results
+
+#---------------------------------#
+# debugging #
+#---------------------------------#
+
+## if you want to connect by remote desktop to a failed build, uncomment these lines
+## note that you will need to connect within the usual build timeout limit (60 minutes)
+## so you may want to adjust the build matrix above to just build the one of interest
+
+# to print the RDP connection info
+# uncomment the appropriate line in the init: section above
+
+# block a failed build (until the watchdog barks)
+#on_failure:
+# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
+
+#---------------------------------#
+# notifications #
+#---------------------------------#
+
+notifications:
+ - provider: GitHubPullRequest
diff --git a/.ci-local/cfg_libcom-only.sh b/.ci-local/cfg_libcom-only.sh
new file mode 100755
index 0000000..5d89a77
--- /dev/null
+++ b/.ci-local/cfg_libcom-only.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+set -e
+
+if [ "$LIBCOM_ONLY" = "YES" ]
+then
+ cat << EOF >> ./configure/CONFIG_SITE.local
+EPICS_LIBCOM_ONLY = YES
+EOF
+fi
diff --git a/.ci-local/deps-latest.set b/.ci-local/deps-latest.set
new file mode 100644
index 0000000..4a2a263
--- /dev/null
+++ b/.ci-local/deps-latest.set
@@ -0,0 +1,8 @@
+MODULES="sncseq sscan calc ipac"
+
+BASE_RECURSIVE=no
+
+SNCSEQ=master
+SSCAN=master
+CALC=master
+IPAC=master
diff --git a/.ci-local/deps1.set b/.ci-local/deps1.set
new file mode 100644
index 0000000..34dc30a
--- /dev/null
+++ b/.ci-local/deps1.set
@@ -0,0 +1,8 @@
+MODULES="sncseq sscan calc ipac"
+
+BASE_RECURSIVE=no
+
+SNCSEQ=R2-2-8
+SSCAN=R2-11-3
+CALC=R3-7-3
+IPAC=2.15
diff --git a/.ci-local/deps2.set b/.ci-local/deps2.set
new file mode 100644
index 0000000..6f0fcae
--- /dev/null
+++ b/.ci-local/deps2.set
@@ -0,0 +1,8 @@
+MODULES="sncseq sscan calc ipac"
+
+BASE_RECURSIVE=no
+
+SNCSEQ=R2-2-8
+SSCAN=R2-11-5
+CALC=R3-7-4
+IPAC=2.16
diff --git a/.ci-local/no-deps.set b/.ci-local/no-deps.set
new file mode 100644
index 0000000..45d901f
--- /dev/null
+++ b/.ci-local/no-deps.set
@@ -0,0 +1,3 @@
+MODULES=""
+
+BASE_RECURSIVE=no
diff --git a/.github/workflows/ci-scripts.yml b/.github/workflows/ci-scripts.yml
new file mode 100644
index 0000000..fb4356d
--- /dev/null
+++ b/.github/workflows/ci-scripts.yml
@@ -0,0 +1,130 @@
+name: asyn
+
+# Trigger on pushes and PRs to any branch
+on:
+ push:
+ paths-ignore:
+ - '**/*.md'
+ - '**/*.txt'
+ pull_request:
+
+env:
+ SETUP_PATH: .ci-local:.ci
+
+jobs:
+ test:
+ name: ${{ matrix.os }}/${{ matrix.deps }}/${{ matrix.base }}/${{ matrix.cmp }}/${{ matrix.configuration }}/${{ matrix.cross }}
+ runs-on: ${{ matrix.os }}
+ env:
+ CMP: ${{ matrix.cmp }}
+ BCFG: ${{ matrix.configuration }}
+ BASE: ${{ matrix.base }}
+ SET: ${{ matrix.deps }}
+ CI_CROSS_TARGETS: ${{ matrix.cross }}
+ TEST: ${{ matrix.test }}
+ APT: re2c
+ CHOCO: re2c
+ BREW: re2c
+
+ strategy:
+ fail-fast: false
+ matrix:
+ # Job names also name artifacts, character limitations apply
+ include:
+ - os: ubuntu-latest
+ cmp: gcc
+ configuration: default
+ base: "7.0"
+ deps: "deps2"
+
+ - os: ubuntu-latest
+ cmp: gcc
+ configuration: static
+ base: "7.0"
+ deps: "deps2"
+
+ - os: ubuntu-latest
+ cmp: gcc
+ configuration: static
+ base: "7.0"
+ deps: "deps2"
+
+ - os: ubuntu-latest
+ cmp: gcc
+ configuration: default
+ base: "3.15"
+ deps: "no-deps"
+
+ - os: ubuntu-latest
+ cmp: gcc
+ configuration: static
+ base: "3.15"
+ deps: "deps2"
+
+# - os: ubuntu-latest
+# cmp: gcc
+# configuration: static
+# base: "3.14"
+# deps: "deps1"
+
+ - os: windows-2019
+ cmp: vs2019
+ configuration: default
+ base: "7.0"
+ deps: "deps2"
+
+ - os: windows-2019
+ cmp: vs2019
+ configuration: static
+ base: "7.0"
+ deps: "deps2"
+
+ - os: ubuntu-latest
+ cmp: gcc
+ configuration: default
+ base: "7.0"
+ deps: "no-deps"
+ cross: "RTEMS-pc386-qemu@4.9"
+
+ - os: ubuntu-latest
+ cmp: gcc
+ configuration: default
+ base: "7.0"
+ deps: "no-deps"
+ cross: "RTEMS-pc386-qemu@4.10"
+ test: NO
+
+# - os: ubuntu-latest
+# cmp: gcc
+# configuration: default
+# base: "7.0"
+# deps: "no-deps"
+# cross: "RTEMS-pc686-qemu@5"
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ submodules: true
+
+ - name: Prepare and compile EPICS dependencies
+ run: python .ci/cue.py prepare
+
+ - name: TIRPC
+ run: echo TIRPC=YES > configure/CONFIG_SITE.Common.linux-x86_64
+
+ - name: Build main module
+ run: python .ci/cue.py build
+
+ - name: Run main module tests
+ run: python .ci/cue.py -T 20M test
+
+ - name: Upload tapfiles Artifact
+ if: ${{ always() }}
+ uses: actions/upload-artifact@v3
+ with:
+ name: tapfiles ${{ matrix.name }}
+ path: '**/O.*/*.tap'
+ if-no-files-found: ignore
+
+ - name: Collect and show test results
+ if: ${{ always() }}
+ run: python .ci/cue.py -T 5M test-results
diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml
new file mode 100644
index 0000000..e92e021
--- /dev/null
+++ b/.github/workflows/publish-docs.yml
@@ -0,0 +1,65 @@
+name: Publish Sphinx Docs to GitHub Pages
+on:
+ # Build the docs on pushes to main branch, PRs to main branch, and new tags.
+ # Publish only on demand.
+ push:
+ branches:
+ - master
+ tags:
+ - '*' # all tags
+ workflow_dispatch: # allow manual triggering
+ inputs:
+ deploy:
+ description: 'Deploy documentation'
+ type: boolean
+ required: true
+ default: false
+
+
+# see: https://sphinx-notes.github.io/pages/
+# see: https://github.com/marketplace/actions/sphinx-to-github-pages
+
+jobs:
+
+ build-docs:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Deploy Information
+ if: ${{ github.event.inputs.deploy }}
+ run: |
+ echo "The will be published from this workflow run."
+
+ - name: Checkout
+ uses: actions/checkout@master
+ with:
+ fetch-depth: 0 # otherwise, you will fail to push refs to dest repo
+
+ - name: Setup Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.10"
+
+ - name: Build Docs
+ run: |
+ pip install m2r2 "pygments >=2.7.0" "sphinx_rtd_theme >=1.2.0" sphinx-multibuild
+ sphinx-build -ET docs/source docs/_build/html/
+
+ - name: Install Doxygen
+ run: sudo apt-get install doxygen graphviz -y
+ shell: bash
+
+ - name: Generate Doxygen Documentation
+ # Doxygen output is put in _build/html/doxygenHTML by the Doxyfile
+ # So it will be published by Publish Jobs below
+ run: |
+ cd docs
+ doxygen
+ cd -
+
+ - name: Publish Docs
+ uses: peaceiris/actions-gh-pages@v3.8.0
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_dir: docs/_build/html
+ keep_files: true
diff --git a/.gitignore b/.gitignore
index cfefcd8..fc8c56a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,14 +1,21 @@
+/cfg/
+/bin/
+/lib/
+/db/
+/dbd/
+/html/
+_build/
+/docs/doxygenHTML/
+/docs/source/_extra
+/docs/_docs/
+/include/
+/templates/
+/configure/*.local
*~
-O.*
+O.*/
*.swp
*_BAK.adl
-bin/
-db/
-dbd/
-html/
-include/
-lib/
-templates/
+/QtC-*
cdCommands
envPaths
dllPath.bat
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..cfa3a70
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule ".ci"]
+ path = .ci
+ url = https://github.com/epics-base/ci-scripts
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 8fb903c..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-language: cpp
-compiler: gcc
-
-env:
- - EPICS_BASE=/usr/lib/epics EPICS_HOST_ARCH=linux-x86_64
-
-before_install:
- # Enabling the NSLS-II EPICS debian package repositories
- - curl https://epics.nsls2.bnl.gov/debian/repo-key.pub | sudo apt-key add -
- - echo "deb https://epics.nsls2.bnl.gov/debian/ wheezy main contrib" | sudo tee -a /etc/apt/sources.list
- - echo "deb-src https://epics.nsls2.bnl.gov/debian/ wheezy main contrib" | sudo tee -a /etc/apt/sources.list
-
- # Installing EPICS base
- - sudo apt-get update -qq
- - sudo apt-get install epics-dev epics-synapps-dev
-
- # Setup configure/RELEASE for the environment
- - echo "EPICS_BASE=/usr/lib/epics" > configure/RELEASE
- - echo "SNCSEQ=/usr/lib/epics" >> configure/RELEASE
-
-install:
- # Build the module
- - make
-
-script:
- - ls bin/linux-x86_64
- - ls lib/linux-x86_64
- - ls include
- - ./asyn/asynPortDriver/unittest/O.linux-x86_64/asynPortDriverTest
diff --git a/Makefile b/Makefile
index 1ee8bf4..4b19f20 100644
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,7 @@ TOP = .
include $(TOP)/configure/CONFIG
DIRS += configure
DIRS += makeSupport
+DIRS += opi
DIRS += asyn
asyn_DEPEND_DIRS = configure
@@ -55,6 +56,10 @@ ifneq ($(EPICS_LIBCOM_ONLY),YES)
testUsbtmcApp_DEPEND_DIRS = asyn
iocBoot_DEPEND_DIRS += testUsbtmcApp
DIRS += iocBoot
+ ifeq ($(DRV_FTDI),YES)
+ DIRS += testFtdiApp
+ testFtdiApp_DEPEND_DIRS = asyn
+ endif
endif
DIRS += testAsynPortClientApp
diff --git a/README.md b/README.md
index cd871a4..63e3194 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
-[](https://travis-ci.org/epics-modules/asyn)
+[](https://github.com/epics-modules/asyn/actions/workflows/ci-scripts.yml)
+[](https://ci.appveyor.com/project/MarkRivers/asyn)
asyn
====
@@ -7,7 +8,8 @@ code to low level drivers. asynDriver allows non-blocking device support that wo
with both blocking and non-blocking drivers.
A primary target for asynDriver is EPICS IOC device support but, other than using
-libCom, most of it is independent of EPICS.
+libCom, most of it is independent of EPICS.
-Additional information:
-* [Home page](http://www.aps.anl.gov/epics/modules/soft/asyn/)
+Documentation and release notes can be found here:
+* [Documentation](https://epics-modules.github.io/asyn)
+* [Release notes](RELEASE.md)
diff --git a/RELEASE.md b/RELEASE.md
new file mode 100755
index 0000000..cb42fa1
--- /dev/null
+++ b/RELEASE.md
@@ -0,0 +1,2100 @@
+# asynDriver: Release Notes
+
+## Release 4-44-2 (March 28, 2023)
+- devEpics
+ - Fix additional problems with waveform, aai, and aao records due to missing initialization of private member variables
+ in devAsynXXXArray.cpp.
+
+## Release 4-44-1 (March 15, 2023)
+- devEpics
+ - Fix problem with waveform out and aao records due to missing initialization of a private member variable
+ in devAsynXXXArray.cpp.
+- testErrorsApp
+ - Add code to test the asynXXXArray->write() functions.
+
+## Release 4-44 (March 13, 2023)
+- devEpics
+ - Rewrite the device support for arrays.
+ Previously it used a large C macro to be able to support int8, int16, int32, float32, and float64
+ data types without a lot of repetitive code. This was changed to use a C++ template file.
+ - Previously only the waveform record was supported for arrays. Added support for aai and aoo records.
+ - Add new devEpicsPvt functions (from Michael Davidsaver):
+ - Avoids leaking DBENTRY during initialization.
+ - Use dbInitEntry() from record rather than dbFindRecord() when available.
+ - Reduces duplicate code.
+- Documentation:
+ - Converted all HTML files in documentation/ to Sphinx RST files in docs/source.
+ - It uses the Read The Docs theme (sphinx-rtd-theme) which provides a panel
+ on the left side of the screen for easy navigation.
+ - Added Github actions to publish the Sphinx generated documentation to Github Pages.
+ - The new home page for the asyn documentation is https://epics-modules.github.io/asyn.
+ - Converted documentation/RELEASE_NOTES.html to RELEASE.md.
+- testErrorsApp
+ - Add aai and aao records to databases in order to test new device support for these.
+- Fix testing on Github Actions by forcing TIRPC=YES, required for modern Linux releases.
+
+## Release 4-43 (September 12, 2022)
+- devEpics
+ - Change logic for output records with asyn:READBACK so they set udf=0 in the outputcallbackcallback()
+ function, and not in the processXX function. This is needed to correctly clear the
+ UDF status and severity.
+ - This problem is happening because for EPICS output records the only way to clear
+ a UDF alarm is to put a value into the record, either from an external put from
+ a CA or DB link (in which case code in the dbAccess.c dbPut() routine clears UDF
+ and the record would get processed) or by reading a value through the DOL link during
+ record processing triggered by some other means.
+ - In both cases UDF will have been cleared before the call to checkAlarms() in the
+ boRecord::process() routine, which is where the UDF field is checked.
+ - Unfortunately for asyn all output records call the checkAlarms() routine before
+ the device support's write_bo() routine, so clearing UDF in processBo() is too late
+ for this process cycle, the UDF_ALARM has already been registered.
+ - This also means that if the bo record is configured with non-zero alarms in ZSV
+ or OSV the initial read wouldn't trigger the appropriate STATE_ALARM either, since
+ they get set in that routine as well.
+- drvAsynUSBTMC
+ - Add support for output terminator.
+ - Increase buffer size to 1 MB.
+ - Add Remote Enable (REN), Local Lockout (LLO), and Go To Local (GTL) support.
+- asynPortDriver
+ - Fixed initialization problem for UInt32 parameters. Initially setting a parameter
+ to 0 left the corresponding PV undefined because the callback wasn't called. Thanks
+ to Erico Nogueira for this fix.
+ - Removed "using std::logic_error" from parameter header files. This is bad practice.
+ This change could potentially break downstream module that would now have to use
+ std::logic_error, rather than just logic_error. This is unlikely since the param
+ classes are essential private to asynPortDriver. Thanks to Luka Krmpotic for this
+ fix.
+- drvAsynIPServerPort
+ - Allow specifying an interface to bind the IP server port. The second argument
+ to drvAsynIPServerPortConfigure allows specifying a hostname or IP address for multi-homed
+ machines. If you want to specify any interface, use "localhost:port", an empty host
+ ":port" or the address "0.0.0.0:port". The address has to be an existing interface
+ on the host. If the name cannot be resolved, the call will fail. If you need the
+ loopback interface, use "127.0.0.1:port". Thanks to Lutz Rossa for this.
+- asynShellCommands
+ - Provide usage information for asynSetTraceMask and asynSetTraceIOMask. This is
+ helpful for remembering how to specify the bit masks numerically or symbolically.
+ Thanks to Michael Davidsaver for this.
+- asynManager
+ - Added asynDisconnected and asynDisabled in strStatus(). Thanks to Kristian Loki
+ for this.
+- configure/RELEASE
+ - All external modules are commented out. Users will need to uncomment the ones
+ to be used.
+- drvVxi11
+ - Fix potential VXI connection resource leak. Thanks to Freddie Akeroyd for this.
+- .ci
+ - Change from Travis to Github Actions. Thanks to Michael Davidsaver for this.
+ - Add support from sscan, calc, and ipac. Thanks to Freddie Akeroyd for this.
+- devGPIB and streamSCPI template files
+ - Changed DB_INSTALLS+= to DB+= to work with recent versions of EPICS.
+
+## Release 4-42 (May 10, 2021)
+- drvProligixGPIB
+ - New driver for the Proligix GPIB-Ethernet controller. Thanks to Eric Norum for
+ this. This $200 device makes GPIB devices available over Ethernet. It uses a proprietary
+ protocol, not VXI-11.
+- asynPortDriver
+ - Added checks for invalid list (<0 or ≥maxAddr).
+ - Added new error code asynParamInvalidList that is returned if the list passed
+ is not valid.
+- devCommonGPIB.c
+ - Added 0 termination after strncpy().
+- asynInterposeEos
+ - Improve efficiency when eosOutLen is 0.
+- asynRecord
+ - Minor changes to avoid compiler warnings.
+
+## Release 4-41 (September 19, 2020)
+- Many files
+ - Changed the code and the Makefile to avoid using shareLib.h from EPICS base. Added
+ a new header file asynAPI.h that is used to control whether functions, classes,
+ and variables are definined internally to the asyn library or externally. This is
+ the mechanism now used in EPICS base 7. It makes it much easier to avoid mistakes
+ in the order of include files that cause external functions to be accidentally exported
+ in the asyn DLL or shareable library. This should work on all versions of base,
+ and have no impact on user code.
+- devAsynInt32.c, devAsynUInt32Digital.c
+ - Replaced strncpy()) with memcpy() to avoid compiler warnings on newer versions
+ of gcc (e.g. 8.3.1).
+
+## Release 4-40-1 (August 24, 2020)
+- drvAsynIPPort
+ - Fixed the logic for using SO_REUSEPORT or SO_RESUSEADDR. In R4-40 RTEMS and Windows
+ used SO_REUSEADDR and all others used SO_REUSEPORT. This does not work because Linux
+ kernels before 3.9 also do not support SO_REUSEPORT. Now if SO_REUSEPORT is not
+ defined then SO_REUSEADDR is used instead.
+
+## Release 4-40 (July 17, 2020)
+- ci-scripts
+ - Updated to v3.0.1 of ci-scripts.
+ - Added native Windows builds (VS2017) on Travis.
+ - Added AppVeyor builds for testing on many Windows configuations.
+- asynPortDriver
+ - Fixed error in writeInt64 method.
+ - Added asynParamSet class.
+ - Added new constuctor that uses asynParamSet.
+ - Added new utility template function findDerivedAsynPortDriver() that returns a
+ pointer to an asynPortDriver derived class object from its name.
+- Build system
+ - Fixed logic for when CALC and SSCAN modules are needed.
+- asynManager
+ - Take connect timestamp *after* connection attempt. autoConnectDevice() has
+ a built-in protection that forces at least 2 seconds between connection attempts.
+ However, previously the timestamp was read *before* starting the connection,
+ so if the connection attempt takes about 2 seconds (or more) to timeout then that
+ 2 second do-not-connect window was already expired (or about to expire) by the time
+ connectAttempt() returns. Now we read the timestamp *after* connectAttempt()
+ returns.
+ - Made 2 changes to queueLockPort.
+ - If the queue request times out then return asynTimeout rather than asynError.
+ - If the call to pasynManager->queueRequest fails then return the actual failure
+ status rather than asynError.
+ These changes improve the alarm handling when a device becomes unavailable. Previously
+ it would toggle between TIMEOUT alarm when an actual read request timed out and
+ READ alarm when a queue request timed out. This caused too many alarms. Previously
+ if the port was Disconnected then it was returning asynError which sets READ alarm.
+ In this case it should be returning asynDisconnected which sets COM alarm.
+- asynTrace
+ - Changed the output with ASYN_TRACEINFO_SOURCE. Previously the file name included
+ the complete path to the file, which could be very long. The path is now removed.
+- asynPortClient
+ - Fix bug in asynUInt32DigitalClient::registerInterruptUser().
+- asynRecord
+ - Fixed problem updating the CNCT field. Previously if an attempt to connect with
+ CNCT failed CNCT stayed in the Connected state, rather than going back to Disconnected
+ immediately.
+- drvAsynIPPort
+ - Added new tcp&, udp& and udp*& protocols that specify that the SO_RESUSEPORT flag
+ should be used. This article explains
+ the use of the SO_REUSEPORT option for both TCP and UDP. The particular use case
+ that motivated the addition of the SO_REUSEPORT to this driver is discussed in this Github issue.
+ On Windows and RTEMS SO_REUSEADDR is used instead of SO_RESUSEPORT, but it should
+ have the same effect.
+- unittest/Makefile
+ - Fixed to link with EPICS_BASE_IOC_LIBS unless EPICS_LIBCOM_ONLY=YES.
+- devEpics
+ - Fixed bug in devAsynOctet when using output records with info tag asynREADBACK=1
+ and asynFIFO not specified. It was supposed to be creating a ring buffer with one
+ element, but was not, so the readback did not work.
+- Many files
+ - Removed tabs and trailing white space.
+ - Minor changes to avoid compiler warnings.
+
+## Release 4-39 (February 24, 2020)
+- Travis CI
+- Added ci-scripts module to provide much more complete testing. Thanks to Ralph
+ Lange for this.
+ - Against EPICS 7.0 / 3.15.7 / 3.14.12.8 / 3.14.12.2
+ - Using g++ and clang
+ - Static and dynamic builds
+ - Cross-compilation to Windows using MinGW
+ - Cross-compilation to RTEMS 4.9 and 4.10 (including running the tests under qemu)
+ - On MacOS
+ - EPICS_LIBCOM_ONLY builds
+- FTDI driver
+ - Added minimal SPI support for AD9915. Thanks to Juri Tagger for this.
+- asynPortDriver
+ - Fixes to callbackThread for problems when calling the asynPortDriver destructor.
+- devEpics
+ - Added asynOctet support for lso, lsi, printf, and sCalcout records. Thanks to
+ Freddie Akeroyd for this.
+- asynInterposeEos
+ - asynInterposeEos checks each byte for EOS. If it cannot find it and nRead ≥
+ maxchars, then previously it set the eom to ASYN_EOM_CNT using a bitwise OR. In
+ this way, multiple flags can be propagated to the requester of the read. Since ASYN_EOM_CNT
+ is not an end flag, but other two (ASYN_EOM_EOS and ASYN_EOM_END) are, it does not
+ make sense to propagate a combination of end and non-end flag. Thus if the nRead ≥ maxchars is true,
+ now set eom = ASYN_EOM_CNT, i.e. without bitwise OR. This
+ fixes a problem with StreamDevice on some VXI-11 devices. Thanks to Jernej Varlec
+ for this.
+- OPI files
+ - Added .bob files for CS-Studio (Phoebus). These are autoconverted from medm .adl
+ files
+
+## Release 4-38 (January 3, 2020)
+- devEpics
+ - Added asynInt64 support for longout, longin, ao, and ai records. This allows these
+ records to be used to communicate with drivers on the asynInt64 interface. This
+ can be useful when running versions of base prior to 3.16.1 where the int64out and
+ int64in records are not available. The ao and ai records can exactly represent up
+ to 52-bit integers, while the longin and longout are limited to 32-bit integers.
+- FTDI driver
+ - Fixed missing argument to the iocsh drvAsynFTDIPortConfigure() command.
+- drvVxi11
+ - Fixed spurious connection error message.
+
+## Release 4-37 (October 18, 2019)
+- Added new 64-bit integer support
+- asynDriver adds new asynInt64, asynInt64SyncIO, and asynInt64Array interfaces.
+- asynDriver.h now does the typedef of epicsInt64 and epicsUInt64 when __STDC_VERSION__
+ < 199901L on EPICS 3.14. This allows the Int64 interfaces to be built as long
+ as the compiler supports the `long long` and `unsigned long long`
+ data types.
+- devEpics.dbd is now constructed at build time rather than being a static file.
+ This enables Int64 device support to only be included on EPICS 3.16.1 and later.
+- asynPortDriver adds support for 64-bit integers:
+ - New parameter types asynParamInt64 and asynParamInt64Array.
+ - New methods setInteger64Param(), getInteger64Param(), readInt64(), writeInt64(),
+ getBounds64(), readInt64Array(), writeInt64Array(), doCallbacksInt64Array().
+ - New masks for constructor asynInt64Mask, asynInt64ArrayMask.
+- testErrors test application
+ - Changes to driver, database and medm screens to test the Int64 interfaces. This
+ uses the 64-bit device support which must be commented of out st.cmd if running
+ on EPICS versions prior to 3.16.1.
+- New FTDI driver
+ - This driver allows much greater control over USB ports for serial communication
+ than the standard Linux /dev/ttyUSBx driver. Thanks to Bruno Martins for this.
+- devEpics
+ - Fixes to only print an error message when the status of a write or read operation
+ changes, not each time there is an error. Thanks to Ben Franksen for this.
+- asynRecord
+ - Fixes to allow changing the HOSTINFO for the asynIPPort driver when the port is
+ not connected. Thanks to Krisztián Löki for this.
+- Many files
+ - Changes to avoid compiler warnings.
+
+## Release 4-36 (August 8, 2019)
+- asynManager
+ - Improved debugging output when scheduling queue request timeout.
+- drvAsynIPPort
+ - Improved diagnostic messages.
+- asynPortDriver
+ - Added new parseAsynUser() method. Changed all readXXX and writeXXX methods to
+ use this, rather than getAddress().
+ - Use asynPortDriver::getAddress() in callback functions, rather than pasynManager::getAddress().
+ This allows the getAddress() to be overridden in derived classes.
+ - Fix to prevent a potentially locked mutex from being destroyed, as well as use-after-free
+ bugs on other members of asynPortDriver. Thanks to Martin Konrad for this.
+- asynInterposeDelay, asynInteposeEcho
+ - Fixes to compile on Visual Studio 2010.
+
+## Release 4-35 (March 18, 2019)
+ - devAsynInt32, devAsynFloat64, devAsynUInt32Digital, devAsynOctet
+ - Fixed a deadlock problem when asyn:READBACK was used on output records.
+ - In devAsynOctet there was still an isssue if asyn:READBACK=1 was used without
+ asyn:FIFO, i.e. when ring buffers were not enabled. The code now forces a minimum
+ ring buffer size of 1 if asyn:READBACK=1 to avoid the deadlock. asyn:FIFO can still
+ be used to select a larger ring buffer size.
+ - drvAsynIPPort
+ - Fixed a problem with the disconnectOnReadTimeout option. Previously it would disconnect
+ even if pasynUser->timeout was 0. This is not logical, and meant this option could
+ not be used with StreamDevice, because StreamDevices flushes the input by reading
+ with a timeout of 0 to support I/O Intr scanned records.
+ - Updated the documentation to say that in order to receive UDP broadcast messages
+ the `localPort` parameter in the hostInfo string in `drvAsynIPPortConfigure`
+ must be specified. Example: `drvAsynIPPortConfigure("BD","255.255.255.255:1234:3956
+ UDP",0,0,0)` will listen for broadcast messages on port 3956. If the port
+ is only to be used to receive broadcast messages then the UDP protocol should be
+ specified. If the port is also to be used to send UDP broadcasts then the UDP* protocol
+ must be specified. Example: `drvAsynIPPortConfigure("BD","255.255.255.255:1234:3956
+ UDP*",0,0,0)`. In this case it will send the broadcast messages on UDP port
+ 1234 and listen for broadcast messages on UDP port 3956.
+ - asynShellCommands
+ - Enhancement to allow using strings for the mask arguments of asynSetTraceMask,
+ asynSetTraceIOMask, and asynSetTraceInfoMask shell functions. The mask can be specified
+ as an integer (previous behavior) or as symbolic names connected with + or |. Spaces
+ are allowed but require quotes. The symbolic names are like the macro names in asyn.h,
+ but not case sensitive and the prefixes ASYN_, TRACE_, TRACEIO_, and TRACEINFO_
+ are optional. Thanks to Dirk Zimoch for this. Examples:
+ ```
+ asynSetTraceMask port,0,ASYN_TRACE_ERROR
+ asynSetTraceIOMask port,0,ascii+escape
+ asynSetTraceInfoMask port,0,1+port+TRACEINFO_SOURCE|ASYN_TRACEINFO_THREAD
+ ```
+- asynPortClient.h, asynPortClient.cpp
+ - Renamed asynPortClient base class to asynParamClient. This is the class from which
+ asynInt32Client, asynFloat64Client, etc. are derived.
+ - The new asynPortClient class connects to a specific asynPortDriver object. It
+ creates an asynParamClient derived class object for each of the parameters in that
+ driver. It uses the std::map class to map between the parameter name key and the
+ asynParamClient object for that parameter. It also defines overloaded write() and
+ read() methods that take a paramName argument and the value to be written or pointer
+ to read into. The data type of the value or pointer must match the parameter type
+ or a run-time exception will be thrown. This new class is more convenient to use
+ because it is no longer necessary to create the asynInt32Client, asynFloat64Client,
+ etc. objects for each parameter to be accessed.
+- asynPortDriver
+ - Added asynPortDriver::getNumParams() method to get the number of parameters currently
+ defined.
+- asynInterposeDelay
+ - New interpose driver that waits for a user-specified time after sending each character
+ before sending the next one. Some poorly designed devices require this. Thanks to
+ Dirk Zimoch.
+- asynInterposeEcho
+ - New interpose driver that waits for a device to echo each character before sending
+ the next one. Some poorly designed devices require this. Thanks to Dirk Zimoch.
+
+## Release 4-34 (September 13, 2018)
+- devAsynFloat64.c, devAsynInt32.c
+ - Added support for SCAN=I/O Intr with asynFloat64Average and asynInt32Average device
+ support. Previously only periodic scanning or manual processing was supported. The
+ I/O Intr support computes the average and processes the record once NumAverage callback
+ readings have been received. The SVAL field in the ai record is used to set NumAverage.
+ This is rather a kluge, but there is not another good way to communicate this value
+ to the device support, while allowing it to be changed at run-time.
+- drvAsynIPPort.c
+ - Improved error reporting. Thanks to Dirk Zimoch for this.
+- asynInterposeEos.c
+ - Improved asynTrace output to print bytes read and eom, and print warning if low-level
+ driver returns error.
+- asynInterposeCom.c
+ - Added support for the asynOption ixon (XON/XOFF) for ports communicating via the
+ RFC 2217 Telnet protocol. In this case, as noted in the standard, ixon implies both
+ outbound and inbound flow control.
+- asynPortDriver
+ - Fixed uninitialized value in paramVal.
+- asynShellCommands.h
+ - Add asynOctetDisconnect and asynWaitConnect.
+- drvVxi11.c
+ - Fixed logic for FLAG_NO_SRQ. Error was introduced in R4-31.
+- CONFIG_SITE
+ - Optionally include $(SUPPORT)/configure/CONFIG_SITE.
+ - Older Linux and Cygwin distributions have packages (e.g. glibc-headers) that put
+ the rpc include files in /usr/include/rpc. Newer Linux and Cygwin distributions
+ use the tirpc package instead. For such systems define TIRPC=YES.
+- .travis.yml
+ - Fixed to fetch Debian files from nsls2 with https not http.
+
+## Release 4-33 (January 27, 2018)
+- devAsynFloat64.c
+ - Added support for ASLO/AOFF scaling and SMOO value smoothing to the float64 device
+ support for ai and ao records. SMOO only applies to ai records. devAsynFloat64 directly
+ writes to the record's VAL/OVAL fields, so the conversion routines in the record
+ that use RVAL/VAL don't work.
+- devAsynInt32.c, devAsynUInt32Digital.c, devAsynFloat64.c, devAsynOctet.c
+ - Fixed a problem with output records that have the asyn:READBACK info tag, i.e.
+ output records that update on callbacks from the driver. Previously it did not correctly
+ distinguish between record processing due to a driver callback (in which case it
+ should not call the driver) and normal record processing (in which case the driver
+ should be called). A new test application, testOutputCallbackApp, was added to test
+ this. It allows testing all combinations of the following 6 settings for all 4 of
+ these device support files:
+ - Synchronous driver, i.e. ASYN_CANBLOCK not set.
+ - Asynchronous driver, i.e. ASYN_CANBLOCK is set.
+ - Driver callback is done in the write() operation.
+ - Driver callback is done in a separate thread. The callbacks are triggered with
+ the TriggerCallbacks record.
+ - Single callback is done in each operation.
+ - Multiple callbacks are done in each operation. The NumCallbacks record selects
+ the number of callbacks.
+
+ The callback values are the following. For the longout records (asynInt32 and asynUInt32Digital)
+ and the ao record (asynFloat64) the callback value is N+1 where N the current record
+ value. Thus if one writes 10 to the longout record and NumCallbacks is 5 it will
+ immediately do callbacks with the values 11, 12, 13, 14, 15. For the bo record the
+ value toggles between 0 and 1 for each callback. For the stringout record the value
+ is a string with the format "Value=N". N increments by 1 on each callback as for
+ the longout records. For each output record there is a corresponding input record
+ with SCAN=I/O Intr. If the test is working correctly the output records should always
+ have the same values as the input records.
+- devAsynOctet.c
+ - Fixed bug where the record alarm status was not set correctly if a write or read
+ failed with a synchronous driver.
+- asynManager.c
+ - Improved error messages from autoconnect attempts. Messages are now printed only
+ when the autoconnect status changes, rather than each time there is a failure. Thanks
+ to Ben Franksen for this.
+- drvAsynIPServerPort.c
+ - Changed the logic so it creates maxClients drvAsynIPPort drivers at initialization
+ rather than on-demand when clients connect. This makes it possible to use these
+ ports before iocInit, which is much more useful. They can be used in input and output
+ links in EPICS records, for example. This change should be backwards compatible,
+ since it was transparent when the ports were created.
+ - The first drvAsynIPPort created is now named PORT_NAME:0 rather than PORT_NAME:1,
+ where PORT_NAME is the name of the drvAsynIPServer port created by this driver.
+ This might break backwards compatibility, but clients were normally getting the
+ name from a callback, so probably not.
+ - Set the socket option SO_REUSEADDR when creating the listening socket. Previously
+ if a client was connected and the IOC exited it could not be restarted again immediately.
+ One needed to wait for the operating system to time out the connection. This change
+ allows the IOC to be run again with the same listening port immediately, without
+ waiting for the operating system timeout.
+ - Added an exit handler to close the listen socket and delete the private structure.
+ - Improved the report() function so it shows all the drvAsynIPPort drivers that
+ were created.
+- testIPServerApp
+ - Added a new datbase testIPServer1.db for testing the enhancements to drvAsynIPServerPort.
+ It contains a stringin record and a stringout record that use the drvAsynIPPort
+ created by drvAsynIPServerPort.
+ - Added a new startup script, iocBoot/ioctestIPServer/st.cmd.testIPServer1 which
+ creates a drvAsynIPServerPort called P5001 on localhost:5001. It loads the testIPServer1.db
+ database connected to the drvAsynIPPort created by P5001, called P5001:0. One can
+ telnet to port 5001 on the IOC computer. All text typed in the telnet session will
+ go into the stringin record. Text written to the stringout record will appear in
+ the telnet session.
+- drvVXI11.c
+ - Improved error messages from connection attempts. Messages are now printed only
+ when the connection status changes, rather than each time there is a connection
+ failure. Thanks to Ben Franksen for this.
+- testErrorsApp
+ - Previously the user-defined alarm status and severity were only set on callbacks,
+ i.e. input records with SCAN=I/O Intr and output records with info tag asyn:READBACK=1.
+ Now all calls to the read() and write() methods in each interface also return the
+ user-defined alarm status and severity in pasynUser.
+- asynPortClient
+ - Fixed typo in constructor for asynUInt32DigitalClient, it was calling asynInt32SyncIO->connect
+ rather than asynUInt32DigitalClient->connect.
+- OPI screens
+ - Added new opi/Makefile. This automatically converts all opi/medm/*.adl files into
+ corresponding files in edm/autoconvert, caqtdm/autoconvert, and boy/autoconvert.
+ It uses new RULES_OPI and CONFIG_SITE.linux-x86_64 files in synApps/support/configure
+ directory. The upper-level edm, caqtdm, and boy directories should be used only
+ for manually tweaked files.
+ - The medm adl files were improved to make the autoconverted files work better.
+ The size of text graphics and text update widgets were set to the actual text size,
+ and text update widgets were set to the correct datatype, e.g. string type for enum
+ PVs.
+- Documentation
+ - asynDriver.html has been improved. All level 3 headings are now links in the Contents
+ at the start of the file. This makes it much easier to find a particular topic and
+ jump to it quickly. Many of the test applications are now documented, including
+ medm screen shots to show how they work.
+
+## Release 4-32 (September 15, 2017)
+- asynManager.c
+ - Fixes to queueLockPort() which is used by the asynXXXSyncIO interfaces.
+ - Previously queueLockPort() did not specify a timeout value or timeout callback
+ function in the call to pasynManager->queueRequest().
+ - This meant that if a port disconnected while a lock request was queued it would
+ hang until the port reconnected. For example, calls to the asynXXXSyncIO functions
+ would not return until the port reconnected.
+ - Added a timeout callback for the queueRequest in queueLockPort(). This callback
+ function prints a warning message with ASYN_TRACE_WARNING. It sets the psynUser->auxStatus
+ field to asynTimeout so that queueLockPort() detects an error and returns an error
+ status without locking the port. Callers must be sure to check the return status
+ of queueLockPort and not call any port driver functions if it does. This was already
+ done in all of the asynXXXSyncIO functions.
+ - The timeout for the queueLockPort queue request is determined as follows
+ - Each port now has a queueLockPortTimeout value. This is set to a default of 2.0
+ seconds when the port is created.
+ - This can be changed with a new iocsh command
+ ```
+ asynSetQueueLockPortTimeout(portName, timeout)
+ ```
+ - If the pasynUser->timeout that is passed for a particular I/O operation is larger
+ than the port timeout value this larger value is used instead.
+ - In traceVprintIOSource if the traceIOMask is 0 or traceTruncateSize ≤ 0 output
+ a newline, otherwise output is garbled
+- asynPortDriver
+ - Replaced "int" with "epicsInt32" in many places for consistency and to avoid compiler
+ warnings on some architectures. Thanks to Scott Baily for this.
+ - Added new asynPortDriver::getParamType() methods. Thanks to Mark Davis for this.
+ - Added a new asynPortDriver constructor that removes the paramTableSize argument.
+ Marked the previous constructor as EPICS_DEPRECATED. Added a new initialize() method
+ that both constructors call to do the actual work. Changed all of the asynPortDriver
+ example programs and unit test programs to use the new constructor. Thanks to Martin
+ Konrad for this.
+- Test application *Main.cpp files
+ - The main programs in all of the test applications have been updated to the version
+ in the template files in EPICS base 3.15.5. This includes a call to epicsExit()
+ after the iocsh() returns. This is needed for epicsAtExit to work correctly on some
+ platforms, including Windows.
+- Files in configure/ directories
+ - The Makefile, CONFIG, CONFIG_SITE, and RULES* files in configure/, makeSupport/top/configure/,
+ and documentation/HowToDoSerial/AB300/configure/ have been updated to the versions
+ in the template files in EPICS base 3.15.5. The new versions are better suited to
+ site-specific customization.
+
+## Release 4-31 (February 18, 2017)
+- VXI-11
+ - Added option to omit SRQ channel.
+- Build system
+ - Minor change to build with mingw.
+- Unit tests
+ - Added unit tests in asynPortDriver/unittest.
+- asynPortDriver
+ - Changed the parameter list to be an std::vector. This means that it is no longer
+ necessary to pass the number of parameters in the constructor because the list grows
+ with each call to createParam().
+ - Changed the internal storage of string parameters from char * to std::string.
+ Added new setStringParam() and getStringParam() methods that take an std::string&
+ argument rather than char *. These do not require specifying a maximum string length,
+ unlike the char * methods.
+ - Changed the constructor so that it throws an std::runtime_error exception in the
+ case of any error, rather than simply calling "return" and creating a non-functional
+ asynPortDriver object, which it did previously. It still prints an error message
+ as it has done previously.
+- drvAsynIPPort
+ - Fixed bugs in Unix sockets.
+
+## Release 4-30 (August 23, 2016)
+- asynDriver
+ - Added new fields to the asynUser structure. These are `int alarmStatus`
+ and `int alarmSeverity`. They are intended to pass alarm information
+ back to device support, indepenent of the status return from the write() or read()
+ methods or the auxStatus field used for callbacks.
+- devEpics
+ - Previously when the status return or auxStatus were not asynSuccess then device
+ support did not update the value, and set the record STAT and SEVR based upon rules
+ in the generic device support. If the new alarmStatus and alarmSeverity fields are
+ 0 (default) then the current behavior is retained. If these fields are non-zero,
+ then the record STAT and SEVR will be set to these values, independent of the status
+ return or the auxStatus values. This allows a driver to set the record value, while
+ still setting the STAT and SEVR to values other than NO_ALARM. The behavior of the
+ function asynStatusToEpicsAlarm() was changed, and this function is now always called
+ at the end of the process() function, even if the status or auxStatus is asynSuccess.
+- asynPortDriver
+ - Added new methods setParamAlarmStatus(), setParamAlarmSeverity, getParamAlarmStatus(),
+ getParamAlarmSeverity to write and read the new pasynUser->alarmStatus and pasynUser->alarmSeverity
+ fields.
+ - Changed the constructor so that it sets the ASYN_MULTIDEVICE flag if maxAddr>1
+ even if the caller neglected to set it.
+ - Fixed destructor eliminate memory leaks. Thanks to Henrique Almeida.
+- devAsynOctet
+ - Added support for initial readback from driver for stringout and waveform output
+ records to support bumpless reboots. This support is only enabled if the info tag
+ asyn:INITIAL_READBACK is present for these records in the database. The testErrorsApp
+ application was updated to test this feature.
+ - Check that FTVL is CHAR or UCHAR and return an error in init_record if it is not.
+ - Changed the waveform record device support asynOctetWrite to only support string
+ output. The numchars argument in pasynOctet->write() is obtained by calling strnlen().
+ This makes it consistent with the behavior of the stringout record.
+ - Added a new waveform record device support asynOctetWriteBinary. This passes numchars=NORD
+ and does not call strnlen(), so it should be used for binary data.
+- drvAsynSerialPort
+ - Added support for RS-485 on Linux. This is only supported on ports with hardware
+ RS-485 capability, and only on more recent Linux kernels. Thanks to Florian Feldbauer.
+ The following new options were added for the asynOption interface in this driver.
+ - rs485_enable Y/N
+ - rs485_rts_on_send Y/N
+ - rs485_rts_after_send Y/N
+ - rs485_delay_rts_before_send msec_delay
+ - rs485_delay_rts_after_send msec_delay
+- testErrorsApp
+ - Added new records AlarmStatus and AlarmSeverity that allow this driver to test
+ the new alarm handling behavior.
+
+## Release 4-29 (February 17, 2016)
+- drvAsynIPPort
+ - Revert the change made in R4-27 to drvAsynIPPortConfigure that changed the noProcessEos
+ flag to userFlags. The final argument to drvAsynIPPortConfigure is now noProcessEos
+ again.
+ - Implemented the asynOption interface which allows configuring options using key/value
+ pairs. This interface is used in the drvAsynSerialPort driver for configuring baud
+ rate, stop bits, etc. It is also used on drvAsynIPPort for configuring these same
+ items if the port was configured with the COM qualifier, used for Ethernet/Serial
+ terminal servers that use the TELNET RFC 2217 protocol. For that drvAsynIPPort uses
+ the asynInterposeCOM to interpose the asynOctet and asynOption interfaces.
+ - drvAsynIPPort now also directly supports the asynOption interface for 2 key/value
+ pairs.
+ - key="disconnectOnReadTimeout", value="Y" or "N". This option replaces the USERFLAG_CLOSE_ON_READ_TIMEOUT
+ that was introduced in R4-27. The advantage of using the asynOption interface is
+ that this behavior can now be changed at run-time, rather than being set once when
+ the driver is created.
+ - key="hostInfo", value="host:port[:localport] [protocol]", i.e. the Internet host
+ name, port number, optional local port number and optional protocol. This uses the
+ same syntax as the drvAsynIPPortConfigure command. This allows changing at run time
+ the Internet host and port to which this asyn port is connected. The only restriction
+ is that the setting of the COM (TELNET RFC 2217) protocol cannot be changed from
+ that specified with drvAsynIPPortConfigure. This is because if COM is specified
+ in the drvAsynIPPortConfigure command then asynOctet and asynOption interpose interfaces
+ are used, and asynManager does not support removing interpose interfaces.
+ - Improved debugging output with ASYN_TRACEIO_DRIVER. Previously there was no asynTrace
+ output if recv() or recvfrom() returned ≤0. It is often useful to know if these
+ functions returned 0, so the asynTrace output is now only suppressed if these functions
+ return <0.
+ There was previously no ASYN_TRACEIO_DRIVER output from the flushIt() function,
+ which repeatedly calls recv() until the return value is ≤0. ASYN_TRACEIO_DRIVER
+ will now print a message with the total number of bytes flushed in this function,
+ if the number is greater than 0.
+- asynRecord
+ - Added 2 new record fields to read and control the new drvAsynIPPort options:
+ - DRTO (Disconnect on Read Timeout)
+ - HOSTINFO (hostInfo string)
+ - Added new OPI screen (asynIPPortSetup.[adl,.opi,.edl,.ui]). This screen allows
+ display and control of the new DRTO and HOSTINFO fields. It also allows display
+ and control of the serial port parameters for drvAsynIPPorts created with the COM
+ (RFC 2217) protocol. There was previously no GUI to control these options for IP
+ ports. This screen is accessed via the More menu in asynRecord.adl.
+- asynPortDriver
+ - Add paramName to error messages for easier debugging.
+ - Throw exception if NULL pointer is passed to setStringParam().
+- asynDriver
+ - asynTrace now does flush after each write on files, previously it only did this
+ on stdin and stderr. This prevents trace information in files being lost if the
+ application crashes.
+ - Fixed syntax of call to cantProceed().
+ - Added definition of ASYN_EXCEPTION_STRINGS which provides strings corresponding
+ to each asynException enum value.
+- testBroadcastApp
+ - Added new test application testBroadcastBurst. This application periodically sends
+ a burst of broadcast packets. The number of packets per burst and the interval between
+ bursts can be specified on the command line. It is useful for testing devices to
+ see how tolerant they are of broadcast bursts.
+- testConnectApp
+ - Added missing extern "C" required to build dynamically on Windows.
+- Many source files
+ - Replaced tab characters with spaces. Tabs in source files are bad practice.
+
+## Release 4-28 (December 12, 2015)
+- drvAsynIPPort
+ - Fixed problem with UDP broadcast sockets. Previously sending broadcast messages
+ worked correctly, but any responses from clients to those messages were rejected
+ by the IOC system. This is because connect() and send() were being called. This
+ is not correct, in this case connect() should not be called and sendto() should
+ be called rather than send(). Also changed the code to call recvfrom() rather than
+ recv()for UDP sockets. This returns the source address information, which is now
+ printed with the source message length and contents if ASYN_TRACEIO_DRIVER is set.
+- Test applications
+ - New test application, testOutputReadbackApp. Tests that the initial values of output
+ records are set correctly.
+ - New test application directory, testBroadcastApp. It has 2 applications for sending
+ broadcasts and reading responses. One uses asyn, and the other native OS calls.
+ The native OS call version only builds on Linux. This is used for testing the UDP
+ broadcast problem fixed in this release.
+
+## Release 4-27 (October 7, 2015)
+- Repository location
+ - The source code repository was moved from
+ https://svn.aps.anl.gov/epics/asyn to
+ https://github.com/epics-modules/asyn. This will make it much easier for
+ others to collaborate in the development of asyn.
+- drvAsynSerialPort
+ - Fix to save the previous values of the baud rate and termios structures before
+ attempting to change them. If the change fails then the previous values are restored.
+ Previously if a call to setOption() failed, then subsequent calls to getOption()
+ would return the value that failed. Now subsequent calls to getOption() will return
+ the previous valid option, which is presumably the one that the underlying OS driver
+ is still using. Thanks to Ron Sluiter for the initial fix to this problem.
+- drvAsynSerialPortWin32
+ - Fix to automatically prefix COM port names with "\\.\" unless the port name already
+ begins with "\\.\". This is valid syntax for all COM ports and is required for all
+ ports except COM1-COM9. Note that when passing the port string from the iocsh if
+ the port name is in quotes then backslash characters should not be escaped, e.g.
+ "\\.\COM10". If the port name is not in quotes then the backslash characters must
+ be escaped, e.g. \\\\.\\COM10. Thanks to Freddie Akeroyd for the initial version
+ of this fix.
+- drvAsynIPPort
+ - Added the option to automatically close the port when there is a read timeout.
+ This was done by changing the syntax of the drvAsynIPConfigure command from
+ ```
+ drvAsynIPPortConfigure("portName","hostInfo",priority,noAutoConnect,noProcessEos)
+ ```
+ to
+ ```
+ drvAsynIPPortConfigure("portName","hostInfo",priority,noAutoConnect,userFlags)
+ ```
+ userFlags: bit-wise ORed:
+ - Bit 0 is USERFLAG_NO_PROCESS_EOS. If 0 then asynInterposeEosConfig is called specifying
+ both processEosIn and processEosOut.
+ - Bit 1 is USERFLAG_CLOSE_ON_READ_TIMEOUT. If 1 then the (TCP) socket will be closed
+ when read() returns a timeout.
+ - Bit 2--31 are reserved, set to zero.
+ This change is backwards compatible since bit 0 is the same as the previous noProcessEos.
+ Thanks to Torsten Bogershausen for this change.
+- devEpics
+ - Changed error reporting if pasynManager->queueRequest returned an error. Previously
+ error messages were printed on every call, which would cause a large number of messages
+ if the port was disconnected and records were periodically processing. Now an error
+ message is only printed when the status return from pasynManager->queueRequest changes,
+ so there will be single message for each record when a port disconnects and a single
+ message when it reconnects.
+ - Changed error handling when any of the following errors are encountered:
+ - pasynManager->queueRequest returns an error
+ - The I/O call to the driver (e.g. pasynInt32->read()) returns an error.
+ - The interrupt callback function is passed an error code in pasynUser->auxStatus
+
+ Previously such errors did correctly set the record alarm status and severity. However,
+ they did not return an error code to the function that called the device support
+ write() or read() function. They also updated the record VAL or RVAL field when
+ there was an error, which they should not. Now these functions return an error code
+ and do not update VAL or RVAL when there is an error.
+- asynPortDriver
+ - Changed the status return from pasynManager->queueRequest from asynError to asynDisconnected
+ if a port with ASYN_CANBLOCK=0 is disconnected.
+- asynShellCommands
+ - Added new command asynSetMinTimerPeriod, and corresponding C function. This command
+ is currently only implemented on the WIN32 architectures, and simply prints an error
+ message on all other architectures. It allows reducing the minimum time for epicsThreadSleep()
+ from the default of 10 ms to the minimum supported Windows system value. On most
+ systems this is 1 ms. Note that epicsThreadSleepQuantum() does not seem to report
+ the correct value whether or not this function is called. On my system it always
+ reports 0.0156 seconds. Note also that this function really has nothing to do with
+ asyn, and the equivalent functionality should probably be moved into EPICS base
+ at some time.
+- Deadlock issue
+ - There is a potential deadlock issue when using input records with SCAN=I/O Intr.
+ This is discussed in the KnownProblems document.
+ Thanks to Ambroz Bizjak for finding this problem.
+
+## Release 4-26 (February 15, 2015)
+- devEpics
+ - Added capability for output records to update their values with a callback from
+ the driver. This is enabled by adding the following info tag to the output record:
+ `info(asyn:READBACK, "1")`
+ The output record value will update any time the driver does a callback with a new
+ value. The output record alarm status and severity will also update to reflect the
+ value passed by the driver in pasynUser->auxStatus. The driver callbacks use the
+ same ring buffer mechanism that input records do. The default ring buffer size is
+ 10 for all records except stringin, stringout, and waveform records, for which the
+ default is 0.
+ - Updated the test application testErrorsApp to demonstrate and test output record
+ updates.
+ - Added ring buffer support to devAsynOctet. The default ring buffer size is 0 for
+ all records in devAsynOctet, i.e. stringin, stringout, waveform in and out. Non-zero
+ values can be specified with the asyn:FIFO info tag.
+ - Changed the info tag that is used to control the size of the ring buffer for driver
+ callbacks. The tag has been changed from FIFO to asyn:FIFO, i.e. adding the asyn:
+ namespace to prevent future conflicts with any other facility. NOTE:This
+ change is not backwards compatible, any databases using the FIFO info tag will need
+ to be changed to asyn:FIFO. It is not expected that this will affect many users,
+ since the default ring buffer size is used in nearly all cases.
+- asynPortDriver
+ - Bug fix: If setParamStatus() was called for an array or generic pointer parameter
+ then callParamCallbacks() could return prematurely and not do the callbacks for
+ all modified parameters.
+
+## Release 4-25 (December 10, 2014)
+- devAsynOctet
+ Fixed 2 bugs:
+ - The interrupt callback function for stringin records (e.g. with SCAN=I/O Intr)
+ did not null-terminate the string if the driver returned MAX_STRING_SIZE or more
+ characters. Thanks to Freddie Akeroyd for fixing this.
+ - The interrupt callback function for stringin and waveform records were not properly
+ locking the record when modifying the record fields.
+- devAsynXXXArray
+ - Added optional support for ring buffers with waveform records. Ring buffers were
+ added to asyn device support for scalar (non-array) records in R4-10. To enable
+ ring buffer support on a waveform record the record info tag FIFO can be set to
+ a value greater than 0. For example this line in a db file for a waveform record
+ sets a ring buffer size of 20 elements.
+ ```
+ info("FIFO", "20")
+ ```
+ Ring buffers are only used when records have SCAN=I/O Intr. They allow the record
+ to process all of the arrays from a rapid burst of callbacks from the driver. However,
+ because Channel Access does not provide any buffering for arrays, even if the record
+ processes for each new array callback, Channel Access will not necessarily send
+ events for each value, because it just sends the current record value when the CA
+ callbacks are done.
+ - A new test application, testArrayRingBufferApp was added to test this array ring
+ buffer support. A new iocBoot/ioctestRingBuffer directory was also added.
+- Interfaces
+ - Added new asynOptionSyncIO interface. This interface is needed so that the asynOption
+ interface can be called synchronously when it is OK to block.
+- Building asyn with only using libCom from EPICS base
+ - It has always been asserted that except for devEpics asyn only really depends on
+ libCom from EPICS base. People who are interested in using asyn drivers from other
+ control systems, want to minimize the dependencies of libraries from EPICS base.
+ The following lines have been added to asyn/configure/CONFIG_SITE:
+ ```
+ -------------------------------------------------------------------------------
+ # If you want to build asyn so the only dependency on EPICS base is libCom then set the following flag
+ #EPICS_LIBCOM_ONLY=YES
+ -------------------------------------------------------------------------------
+ ```
+ If EPICS_LIBCOM_ONLY is YES then the build is done so that only libCom is needed.
+ This does the following:
+ - Omits building all of the device support for EPICS records
+ - Omits building the test applications that create IOC applications
+ - Sets asyn_LIBS to Com rather than $(EPICS_BASE_IOCS_LIBS) when creating the library
+ - Changes the logic in asynPortDriver which uses interruptAccept. If EPICS_LIBCOM_ONLY
+ is set then dbDefs.h is not included and interruptAccept is defined as a static
+ variable set to 1.
+ - A new C++ class was added, asyn/asynPortClient/asynPortClient.cpp. This class makes
+ it easy to write a C++ application that starts existing asyn port drivers and communicates
+ with them over standard asyn interfaces without running an IOC.
+ - A new test application directory was added testAsynPortClient. This tests running
+ C++ applications that communicate with asyn port drivers without running an IOC.
+ This currently contains a single test application, testAsynIPPortClient.cpp. This
+ program creates an asynIPPort driver, and uses the command line arguments to set
+ the hostInfo string, a single command string to send to the server, and optionally
+ the input and output EOS. It then prints out the response from the server. There
+ are 3 example shell scipts that show how to use testAsynIPPortClient to communicate
+ with a Web server, XPS motor controller, and a telnet host respectively.
+- drvAsynUSBTMC
+ - Bruno Martins found and fixed a problem with data transfers that spanned multiple
+ USB packets.
+
+## Release 4-24 (October 14, 2014)
+- drvAsynIPPort.c
+ - Added capability to specify the local port that the server should use for the connection.
+ Normally the local host choses a random local port that it binds to and passes to
+ the server. There are a few servers that only accept a specific local port or range
+ of local ports, for which this capability is required. The new syntax is:
+ ```
+ :[:localPort] [protocol]
+ ```
+ For example
+ ```
+ 164.54.160.100:5000:10101 UDP
+ ```
+ where 10101 is the optional local port number.
+- devEpics
+ - Fixed all initialization routines so that if there is an error they do the following:
+ - Call recGblSetSevr(precord,LINK_ALARM,INVALID_ALARM)
+ - Set precord->pact=1
+ - return(INIT_ERROR), where INIT_ERROR=-1
+ - Thanks to Nick Rees for these fixes.
+- Many source files
+ Fixed problem with location of #define epicsExportSharedSymbols and/or #include
+ . In previous versions these were placed immediately before
+ the #include statements defining symbols for that *source file* . However,
+ this was incorrect, they must be placed before all of the #include statements defining
+ symbols *for that DLL* . This mistake causes the same symbol being defined
+ with both dllExport and dllImport when building the DLL. The Visual Studio compiler
+ does not even warn about this error, but it produces a fatal error with the GCC
+ compiler under Cygwin.
+
+## Release 4-23 (June 16, 2014)
+- asynManager.c
+ Fixed a bug in pasynManager->memMalloc. It could return a pointer that was not
+ a multiple of 8 bytes. This led to subtle problems on some architectures (e.g. ARM)
+ if a double was stored in the memory returned by memMalloc. Fixed the code so the
+ pointer is always a multiple of 16 bytes (for future safety).
+- drvAsynUSBTMC
+ - Added driver for USB TMC (Test and Measurement Class) devices.
+ - Works on any system that provides libusb-1.0.
+ - Requires no kernel modifications.
+ - Tested with StreamDevice on Darwin, Linux and Windows.
+ - Enabled by setting DRV_USBTMC=YES in configure/CONFIG_SITE.
+- drvAsynSerialPort
+ Fixed bug: the port was not always being disconnected when the OS returned serious
+ errors. This was preventing USB serial devices from disconnecting and reconnecting
+ properly.
+- drvAsynSerialPortWin32 (Windows serial port driver)
+ - Fixed 2 bugs in pasynOctet->read() when pasynUserTimeout=0:
+ - It was not returning immediately, it was waiting 16 ms.
+ - If there were no characters to be read it was not returning asynTimeout, it was
+ returning asynSuccess. This prevented StreamDevice from working correctly.
+- drvVxi11
+ - Fixed several 32/64 bit issues.
+- drvAsynIPServerPort
+ - Added support for UDP servers, in addition to TCP servers. Thanks to Helge Brands
+ and Dirk Zimoch from PSI for this.
+- drvLinuxGpib
+ - Fix to Makefile to link with system libgpib library.
+- devEpics (asynInt32)
+ - Sign-extend positive or unsigned values as well as negative values when DTYP=asynInt32
+ and asynMask value is non-zero.
+- devEpics (asynUInt32Digital)
+ - Apply mask to longin and longout records.
+- asynPortDriver
+ - Undid the change in R4-22 that changed the asynStdInterfaces from protected to private.
+ That change was not compatible with areaDetector R1-9-1.
+ - Removed paramList.h and paramList.cpp, put the code into asynPortDriver.cpp. These
+ two classes had many interdependencies, so needed to include each other's header
+ files. This was difficult when building dynamically on Windows, where imported and
+ exported symbols need to be distinguished.
+ - Added links to asynPortDriver.html to detailed tutorial on how to write a driver
+ using asynPortDriver.
+- asynOctetSyncIO
+ - Fixed a bug that could cause the values of *nbytesOut, *nbytesIn, and *eomReason
+ to be garbage if an I/O error occurred.
+- Many files
+ - Handled exporting symbols consistently, which is important when building dynamically
+ for Windows with Visual Studio. Eliminated all references to epicsSharedSymbols,
+ now just #include just before the #include for the header
+ file that defines symbols for this file, and after all other #include statements.
+ Thanks to Peter Heesterman for the initial version of this fix.
+- configure directory
+ - Updated the files in the configure directory to the versions from EPICS base 3.14.12.3.
+ Paths to EPICS base and other modules are still defined in configure/RELEASE. However,
+ other configuration values, such as LINUX_GPIB and DRV_USBTMC are now defined in
+ configure/CONFIG_SITE, not in RELEASE.
+
+## Release 4-22 (October 30, 2013
+- asynDriver
+ - Added support functions for setting timestamps in asyn port drivers. These can be
+ used to set the timestamp when the port driver received data. The driver can then
+ set the asynUser->timeStamp field to this value for all input records on read
+ and callback operations. Records that have TSE=-2 will have this timestamp. There
+ is support for registering a user-supplied function to provide the timestamp, which
+ will override the default source that just calls epicsTimeGetCurrent().
+ - Added the following new functions to pasynManager for timestamp support.
+ ```
+ asynStatus (*registerTimeStampSource)(asynUser *pasynUser, void *userPvt, timeStampCallback callback);
+ asynStatus (*unregisterTimeStampSource)(asynUser *pasynUser);
+ asynStatus (*updateTimeStamp)(asynUser *pasynUser);
+ asynStatus (*getTimeStamp)(asynUser *pasynUser, epicsTimeStamp *pTimeStamp);
+ asynStatus (*setTimeStamp)(asynUser *pasynUser, const epicsTimeStamp *pTimeStamp);
+ ```
+ - Added the following shell commands for timestamp support.
+ ```
+ asynRegisterTimeStampSource(const char *portName, const char *functionName);
+ asynUnregisterTimeStampSource(const char *portName);
+ ```
+ - Added a new bit to asynTraceMask, ASYN_TRACE_WARNING. This is intended to be used
+ for messages that are less serious than ASYN_TRACE_ERROR, but more serious than
+ ASYN_TRACE_FLOW.
+ - Added new asynTraceInfoMask. This mask controls the information printed at the beginning
+ of each message by asynPrint and asynPrintIO. Thanks to Ulrik Pedersen for help
+ with this. The mask is defined with the following bits:
+ ```
+ #define ASYN_TRACEINFO_TIME 0x0001
+ #define ASYN_TRACEINFO_PORT 0x0002
+ #define ASYN_TRACEINFO_SOURCE 0x0004
+ #define ASYN_TRACEINFO_THREAD 0x0008
+ ```
+ - ASYN_TRACEINFO_TIME prints what has been printed in previous versions of asyn,
+ the date and time of the message.
+ - ASYN_TRACEINFO_PORT prints [port,addr,reason], where port is the port name, addr
+ is the asyn address, and reason is pasynUser->reason. These are the 3 pieces
+ of "addressing" information in asyn.
+ - ASYN_TRACEINFO_SOURCE prints the file name and line number, i.e. [__FILE__,__LINE__]
+ where the asynPrint statement occurs.
+ - ASYN_TRACEINFO_THREAD prints the thread name, thread ID and thread priority, i.e.
+ [epicsThreadGetNameSelf(), epicsThreadGetIdSelf(), epicsThreadGetPrioritySelf()].
+ - Added a new shell command to control this mask.
+ ```
+ asynSetTraceInfoMask port,addr,mask
+ ```
+ - Added asynTrace information to the output of asynReport if details ≥1.
+- asynOctetSyncIO
+ - Use simple lock/unlock operations rather than queueLockPort/queueUnlockPort for
+ end-of-string manipulations (setInputEos, getInputEos, setOutputEos, getOutputEos).
+ This ensures that these operations can take place even with the device disconnected.
+- devEpics
+ - Finished the support for setting the record TIME field for input records, both for
+ read operations and for callback operations (i.e. records with SCAN=I/O Intr). This
+ work was begun in R4-20, but it was not complete. Fixes were made in devAsynOctet,
+ devAsynInt32, devAsynFloat64, and devAsynUInt32Digital.
+ - Changed the ring buffer overflow messages that are printed in devAsynInt32, devAsynFloat64,
+ and devAsynUInt32Digital. These now use the new ASYN_TRACE_WARNING mask. Prior to
+ asyn R4-20 these used ASYN_TRACE_ERROR, and in asyn R4-20 and R4-21 they used ASYN_TRACEIO_DEVICE.
+- drvAsynIPPort
+ - Fixed a bug in calling poll(). Previously the status return from poll() was not
+ being checked; it was assumed that when poll() returned the port either had new
+ data or had timed out. This is not correct, because poll() can return prematurely
+ with errno=EINTR if a Posix signal occurs before data is received or the timeout
+ expires. This can happen, for example, when the Posix high-resolution timer routines
+ (timer_create, etc.) are used in the IOC. The Prosilica vendor library uses the
+ Posix timer routines, and there were problems using asyn IP ports in IOCs that were
+ also running Prosilica cameras. The problem was fixed by calling poll() again if
+ it returns EINTR and the desired timeout time has not expired since poll() was first
+ called.
+ - Added support for AF_UNIX sockets on systems that provide them.
+- drvAsynSerialPort
+ - Support for all baud rates supported by the operating system.
+ - Fix for XON/XOFF support from Dirk Zimoch.
+- Changes to work with EPICS base 3.15
+ - Removed include of asyn.dbd, from drvAsynSerialPort.dbd, drvAsynIPPort.dbd, drvVxi11.dbd,
+ and drvGsIP488.dbd.
+ - Fixed Makefile rule for vxi11intr.h for parallel builds.
+- drvLinuxGpib
+ - Fixes for eomReason and EOS handling from Dirk Zimoch.
+- asynOctetSyncIO interface
+ - Removed the openSocket() function from this interface. This method really did not
+ belong in this interface, since it just wrapped the call to drvAsynIPPortConfigure().
+- asynRecord
+ - Added 4 additional baud rates to the BAUD field (460800, 576000, 921600, 1152000).
+ However, the BAUD field can still only support 16 fixed baud rates because it is
+ type DBF_ENUM.
+ - Added a new LBAUD (long baud rate) field of type DBF_LONG. This allows selection
+ of any baud rate, not just those in the BAUD menu. Changing the BAUD field changes
+ the LBAUD field. Changing the LBAUD field changes the BAUD field to the appropriate
+ selection if it is a supported value, or to "Unknown" if not.
+ - Added support for ASYN_TRACE_WARNING and asynTraceInfoMask, including the opi screens.
+- asynPortDriver
+ - Added new virtual methods to support Eos operations on the asynOctet interface.
+ These are setInputEosOctet(), getInputEosOctet(), setOutputEosOctet(), getOutputEosOctet().
+ Changed the report() method to print the current values of the inputEos and outputEos.
+ - Added new virtual methods for timestamp support. These are updateTimeStamp(), setTimeStamp(),
+ getTimeStamp().
+ - Added new function getAsynStdInterfaces() to access the asynStdInterfaces structure,
+ which is now private.
+ - Changed the functions that do callbacks when callParamCallbacks() is called to call
+ pasynManager->getTimeStamp() and set the pasynUser->timestamp field to this
+ value in the callbacks.
+ - Changed the base class readXXX() functions (e.g. readInt32(), readFloat64(), etc.)
+ to call pasynManager->getTimeStamp() and set the pasynUser->timestamp field
+ to this value. The readXXX() functions in derived classes should also do this, so
+ that records with TSE=-2 will get the timestamp from the driver.
+- testErrorApp, iocTestErrors
+ - Added an example of a user-supplied timestamp source.
+- testAsynPortDriver
+ - Added calls to lock() and unlock() in simTask. This was previously a serious omission
+ in this example driver. Thanks to Kay Kasemir for spotting this.
+
+## Release 4-21 (February 18, 2013)
+- asynDriver
+ - Restored the original versions of pasynManager->lockPort and unlockPort that
+ were used in asyn prior to R4-14. These versions just call epicsMutexLock and epicsMutexUnlock.
+ In R4-14 these versions were replaced with versions that queued requests to lock
+ the port. The R4-14 versions fixed a problem with the interfaces/asynXXXSyncIO functions,
+ but it has become clear that the original versions are useful in some circumstances.
+ The change was done as follows:
+ - The lockPort and unlockPort functions in R4-20 were renamed to pasynManager->queueLockPort
+ and queueUnlockPort.
+ - The interfaces/asynXXXSyncIO functions were all changed to call the queueLockPort
+ and queueUnlockPort, so they function identically to how they have since R4-14.
+ - The versions of lockPort and unlockPort that existed prior to R4-14 were restored
+ to pasynManager.
+ - Changed the report() function so that if details<0 then asynManager does not
+ print information for each device (address). It calls pasynCommon->report(-details)
+ in this case so driver report functions will not be affected.
+ - Changed the asynTrace print, printIO, vprint, vprintIO functions so they use EPICS_PRINTF_STYLE.
+ This causes the GCC (version 3.0 and higher) and clang compilers to check the agreement
+ of format strings with function arguments when using asynPrint() and asynPrintIO(),
+ just as they do with printf(). This is very helpful in finding errors, and uncovered
+ a number in asyn itself, which have been fixed.
+- devGpib
+ - Changed event code readback to support both the original 'short' VAL field (EPICS
+ 3.14 and earlier) and the new 'string' VAL field (EPICS 3.15 and later).
+ - Added support for DSET_AIRAW and DSET_AORAW definitions.
+ - Replace strcpy with strncpy in devCommonGpib.c to reduce possibility of errors.
+ Use NELEMENTS macro in devSkeletonGpib.c rather than hardcoding. Thanks to Andrew
+ Johnson for these.
+- devEpics
+ - Improved the initMbboDirect function in devAsynUInt32Digital.c. If an initial value
+ is read successfully from the driver it now sets the .Bn fields in the record. It
+ also sets VAL rather than RVAL and returns 2 rather than 0. Thanks to Andrew Johnson
+ for this.
+ - Fixed a bug in devAsynUInt32Digital.c, which was missing a call to epicsMutexLock
+ in interruptCallbackInput. Thanks to Angus Gratton for this fix.
+ - Fixed a bug in devAsynXXXArray.h to handle case of multiple interrupt callbacks
+ between record processing. Previously this would result in a call to the asynXXXArray->read()
+ in the driver, which is not correct. The asynXXXArray device support does not have
+ a ring buffer, so multiple interrupt callbacks between processing results in data
+ being "lost", i.e. the record processes more than once with the same data. This
+ is not really an error, but we now issue an ASYN_TRACEIO_DEVICE warning. This is
+ analogous to ring buffer overflow for non-array data types.
+ - Changed the "ring buffer overflow" messages from "ASYN_TRACE_ERROR" to "ASYN_TRACEIO_DEVICE",
+ for devAsynFloat64. This was done for other device support in R4-20, but float64
+ was overlooked.
+- Interfaces
+ - Added writeRead and writeReadOnce functions to the asynGenericPointer interface.
+ Thanks to Florian Feldbauer for this addition.
+ - Fixed a bug in asynCommonSyncIO that could cause a crash if the connect() function
+ returned an error.
+- asynPortDriver
+ - Added support for the asynOption interface. Added code to demonstrate and test this
+ to the testErrors test application.
+ - Added new method asynPortDriver::flushOctet(), which implements asynOctet::flush().
+ The base class implementation reproduces the behavior of asynOctetBase.c::flushIt,
+ i.e. it calls pasynOctet->read() repeatedly with a timeout of 0.05 seconds until
+ it gets no data back. But now drivers can implement their own version of flush()
+ if a different behavior is desired, which was not previously possible.
+ - Changed the code so that the length of string parameters returned in readOctet and
+ octetCallback is now strlen(string)+1, rather than strlen(string). The length thus
+ now includes the terminating nil. This fixes problems with clients that request
+ long strings or subscribe to monitors with a length of 0, but don't check for a
+ nil terminator.
+ - Changed the meaning of the "details" argument in the asynPortDriver::report() function.
+ The new meaning is:
+ - 0 = no details
+ - ≥1: print details for parameter list (address) 0
+ - ≥2: print details for all parameters lists (addresses)
+ - ≥3: print interrupt callback information
+ - Changed the connect() and disconnect() methods to return an error if the device
+ address specified by the pasynUser is invalid (i.e. <-1 or >MAX_ADDR-1).
+ - Fixed problem that was causing dynamic builds (e.g. SHARED_LIBRARIES=YES) to fail
+ on Windows.
+- asynPortDriver/exceptions
+ - Changes to allow compiling with the old vxWorks Tornado 2.0.2.1 compiler. Thanks
+ to Dirk Zimoch for this fix.
+- Other
+ - Many minor changes to avoid compiler warnings on Linux, vxWorks, and WIN32. Thanks
+ to Dirk Zimoch for many of these.
+
+## Release 4-20 (August 30, 2012)
+- asynManager
+ - Fixed a bug that caused a deadlock if pasynManager->lockPort was called multiple
+ times without calling pasynManager->unlockPort in between. Thanks to Sebastian
+ Marsching from "aquenos GmbH" for this fix.
+- devEpics
+ - Added support for setting the record timestamp from the driver, using a new field,
+ pasynUser->timeStamp. The driver can set this field in read and callback operations.
+ - Fixed a long-standing bug in devAsynXXXArray support for input waveform records
+ with SCAN=I/O Intr. The data were being copied to the record without using dbScanLock.
+ This meant that the data could change while the record was processing.
+ - Changed the "ring buffer overflow" messages from "ASYN_TRACE_ERROR" to "ASYN_TRACEIO_DEVICE",
+ so they do not appear by default. These messages are not really errors, but warnings
+ that record processing it not keeping up with the rate of driver callbacks for records
+ with SCAN=I/O Intr.
+- asynPortDriver
+ - Fixed a bug when adding a parameter that already existed. Thanks to Hinko Kocevar
+ for fixing this.
+- Documentation
+ - Added new document "HowToDoSerial_StreamDevice.html".
+- Test programs
+ - Added new test program, testConnectApp. It uses asynPortDriver, and has a polling
+ thread that sends a user-defined string to a device and reads the response. It can
+ be used to test the behavior when the device is disconnected and then reconnects,
+ etc.
+- Build system
+ - Added a rule in asyn/Makefile to fix a problem that could cause parallel make to
+ fail.
+
+## Release 4-19 (May 21, 2012)
+- Interfaces
+ - Added a new interface, asynEnum. This interface is designed to allow drivers to
+ set the strings, values, and severities for record enum fields. This can be done
+ both at iocInit(), in init_record() with the pasynEnumSyncIO->read() function,
+ and after iocInit via callbacks to device support.
+- devEpics
+ - Added support for the new asynEnum interface for bo, bi, mbbo, and mbbi records
+ in the asynInt32 and asynUInt32Digital device support. These records now attempt
+ to read the initial values of the strings, values (mbbo and mbbi only) and severities
+ for the enum fields. They also support callbacks on the asynEnum interface, so that
+ enum values can be set dynamically at run-time.
+ - Improved the support for setting the alarm status of records. Previously for records
+ that were not I/O Intr scanned STAT was always to READ_ALARM or WRITE_ALARM, and
+ SEVR was set to INVALID_ALARM. A new function, pasynEpicsUtils->asynStatusToEpicsAlarm()
+ was added that converts asynStatus values to EPICS alarm values. This allows records
+ to have STAT=TIMEOUT_ALARM, DISABLE_ALARM, etc. More values of STAT can be supported
+ in the future by adding more values to the asynStatus enum.
+ - Previously it was not possible for input records with SCAN=I/O Intr to have their
+ alarm status set at all. This support has been added. Device support now uses the
+ pasynUser->auxStatus field in the pasynUser passed to the callback function.
+ If auxStatus != asynSuccess then the record alarm STAT and SEVR are set to values
+ based on the asynStatus. asyn port drivers can now signal error status to clients
+ in callback functions by setting pasynUser->auxStatus to asynSuccess, asynTimeout,
+ asynError, etc. This change should be backwards compatible with all drivers because
+ the pasynUser that is used for the callbacks is private to the callback function,
+ and the auxStatus field is initialized to 0, which is asynSuccess.
+ - Added new waveform record device support, asynInt32TimeSeries and asynFloat64TimeSeries.
+ These use callbacks from the driver on those respective interfaces to collect a
+ time series of values in a waveform record. Added new medm file asynTimeSeries.adl
+ for this, and added an example waveform record to testEpics/Db/devInt32.db.
+- asynRecord
+ - Fixed bugs that caused crashes if SCAN=I/O Intr was set at iocInit.
+- asynDriver and asynShellCommands
+ - Added support for I/O redirection to the "dbior" and "asynPrint" commands.
+- asynPortDriver
+ - Added support for the new asynEnum interface described above.
+ - Added support in asynPortDriver for passing status information to clients in callbacks.
+ Each parameter in the parameter library now has an associated asynStatus variable.
+ New functions setParamStatus() and getParamStatus() are provided to access this
+ variable. For example, if setParamStatus(paramIndex, asynError) is called then callParamCallbacks()
+ will cause any input records with SCAN=I/O Intr to go into alarm state.
+ - Moved asynPortDriver from the miscellaneous directory to its own directory. Improved
+ the internals, but did not change the API. Thanks to John Hammonds for this.
+- Other
+ - Added a new test application, testErrorsApp. This application uses a driver based
+ on asynPortDriver to test error handling for all interfaces and all records support
+ by the asyn standard device support (asyn/devEpics). It can be used to test error
+ handling of records with both periodic scanning and I/O Intr scanning. It also tests
+ the new asynEnum interface for setting enum strings, values, and severities at iocInit.
+ - Removed the newline terminator from all messages in pasynUser->errorMessage.
+ This formatting does not belong in the error message. Thanks to Lewis Muir for this.
+ - drvAsynIPServerPort. Added call to epicsSocketEnableAddressReuseDuringTimeWaitState
+ which fixes problems when the IOC is restarted and the port is still in TIME_WAIT
+ state. Thanks to Lewis Muir for this.
+
+## Release 4-18 (November 2, 2011)
+- Miscellaneous
+ - Changes to avoid compiler warnings on 64-bit Darwin.
+ - Changes to avoid compiler warnings and errors on older Solaris compiler.
+ - Changed non-standard __VAR_ARGS__ to __VA_ARGS__ in asynPrint macro.
+ - Added titles to EDM screens.
+ - Added CSS BOY screens.
+ - Fixed build problem. It was rebuilding the VXI11 code with rpcgen each time make
+ was run, even if nothing had changed.
+- asynPortDriver
+ - Cleaned up logic for callbacks on asynUInt32Digital interface. It was not doing
+ callbacks if the value had not changed but an interrupt had occured for bits in
+ the mask. This would happen when interrupts were only enabled on the falling or
+ rising edges but not both. Added an additional form of setUIntDigitalParam that
+ takes an interruptMask argument. In the previous releases drivers were calling setUInt32Interrupt
+ for callbacks which is not correct. That function should only be called by device
+ support to tell the driver which interrupts to recognize. These problems made the
+ quadEM not work correctly with the ipUnidig.
+- drvAsynSerialPort
+ - Bug fix on WIN32. It was waiting forever when timeout=0 when it should return whatever
+ characters are available without waiting at all.
+
+## Release 4-17 (August 3, 2011)
+- asynRecord
+ - Fixed asynRecord.dbd to include promptgroup for fields that need it. Removed the
+ SOCK field and asynSocketSetup.adl; the record no longer supports creating sockets,
+ which can easily be done with the iocsh drvAsynIPPortConfigure command.
+ - Added IXON, IXOFF, and IXANY fields for new XON/XOFF support on serial ports. These
+ fields were added to the asynSerialPortSetup.adl medm screen.
+- devAsynXXXArray
+ - For waveform output records the device support was always writing NELM elements,
+ rather than NORD elements.
+- asynInterposeCom.c
+ - Added missing include file, which caused asyn not to build on EPICS base versions
+ before 3.14.10.
+- vxi11core_xdr.c
+ - Removed unneeded declarations of 'register int32_t *buf' from many functions. Removed
+ register keyword from remaining instances, because address was being taken, which
+ is illegal in C, and was causing errors on vxWorks Pentium cross-compiler.
+- asynPortDriver
+ - Added a global function, findAsynPortDriver(const char *portName), that returns
+ a pointer to an asynPortDriver object given the asyn port name.
+ - Added 3 new asynPortDriver methods: setUInt32DigitalInterrupt, clearUInt32Interrupt,
+ getUInt32Interrupt. These were needed to complete the asynUInt32Digital support.
+- asynShellCommands
+ - The asynOctetSetInputEos, asynOctetSetOutputEos, asynOctetShowInputEos and asynOctetShowOutputEos
+ commands now take effect even if the port is not connected. This makes startup scripts
+ more robust in the face of devices that are not accessible at IOC startup. Removed
+ the unused "drvInfo" parameter from each of these functions.
+- drvAsynIPPort
+ - Host name lookup is now deferred until port connection time. This makes startup
+ scripts robust in the face of a device that is offline at IOC startup and has been
+ offline for so long that it's DNS entry has been deleted.
+ - Prevent reconnects during IOC shutdown. The IP Port exithandler runs before record
+ scanning stops. In that interval, if a record is scanned then it will trigger a
+ reconnect, and new connection can be shutdown without sending data, or without waiting
+ for a reply. Some embedded TCP/IP stacks have problems dealing with this. Thanks
+ to Michael Davidsaver for this fix.
+- drvAsynSerialPort
+ - Added support for local serial ports on Windows, i.e.win32-x86 and windows-x64 architectures.
+ Previously Windows local serial ports were only supported on the cygwin-x86 architecture.
+ - Added support for serial line software handshake flags (ixon/ixoff/xany) on most
+ architectures (e.g. Linux, Cygwin, Darwin, WIN32; see: man stty) and vxWorks (ixon
+ only). Thanks to Dirk Zimoch for this.
+- Miscelleaneous
+ - Changed asyn/Makefile to fix build dependencies for rpcgen of vxi11. Thanks to Michael
+ Davidsaver for this fix.
+
+## Release 4-16 (January 17, 2011)
+- drvAsynIPPort
+ - Support has been added for terminal servers which support the TELNET RFC 2217`protocol.
+ To communicate with such devices specify "COM" as the protocol in the drvAsynIPPortConfigure
+ command. This allows port parameters (speed, parity, etc.) to be set using an asynRecord
+ or asynSetOption commands just as for local serial ports.
+- drvVxi11
+ - Fix from Benjamin Franksen to fix problem with reconnection.
+ - The 'timeout' argument to vxi11Configure has been changed from double to string.
+ This allows vxi11Configure to be called directly from the vxWorks shell.
+
+## Release 4-15 (December 8, 2010)
+- vxi11
+ - The third argument to the vxi11Configure command is now a bit-map. The least significant
+ bit (value 0x1) remains the 'recover with IFC' control. The next-to-least significant
+ bit (value 0x2) when set will cause all devices to be locked when a connection is
+ made. This allows for cooperative exclusive access to devices.
+- asynManager
+ - Fixed memory leak in lockPort() when an error occured, was not calling freeAsynUser().
+ Thanks to Andrew Starritt for finding this.
+- devEpics
+ - Bug fix for devAsynInt32 and devAsynFloat64: it was not freeing the mutex in processAiAverage
+ if numAverage==0, i.e. there had been no callbacks from the driver since the record
+ last processed. This would hang the next thread that tried to take the mutex, typically
+ the driver callback thread.
+ - Bug fix for devAsynXXXArray: it was calling drvUserCreate in the port driver even
+ if there was no userParam in the link, which could crash the driver.
+- Many files
+ - Changes to allow building dynamically on WIN32 (i.e. making DLLs).
+- Makefiles
+ - Changes to allow building on Cygwin 1.7.x or 1.5.x; replaced rpc with $(CYGWIN_RPC_LIB),
+ which allows it to link with rpc on 1.5.x and tirpc on 1.7.x. You need to add one
+ of the following 2 lines to `base/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86`
+ ```
+ For Cygwin 1.7.x:
+ CYGWIN_RPC_LIB = tirpc
+
+ For Cygwin 1.5.x
+ CYGWIN_RPC_LIB = rpc
+ ```
+
+## Release 4-14 (July 29, 2010)
+- asynDriver
+ - Fixed bugs in connection management. Releases 4-11 through 4-13 had the following
+ problems:
+ - If a port was multi-device and auto-connect, and was only accessed using SyncIO
+ calls, then asynManager would never connect to the devices. If regular queued requests
+ were used, which happens if an asyn record is connected to that port and device,
+ then it would connect once the first queue request was done.
+ - For all auto-connect ports there was a race condition, such that the port might
+ or might not be connected when the first queued request or SyncIO call was done
+ on that port. This arose because when the port registered its asynCommon interface,
+ asynManager queued a connection request on that port. But if that connection request
+ callback, which executes in the portThread, had not yet occurred when a queue request
+ or SyncIO call was made, then those operations would be rejected because the port
+ was not yet connected.
+ - These problems were fixed by doing the following:
+ - When the port registers its asynCommon interface and asynManager queues the connection
+ request, it now waits for a short time for the connection callback to complete.
+ The default time is 0.5 seconds, but this time can be changed with a call to the
+ new function pasynManager->setAutoConnectTimeout(double timeout). This function
+ can be accessed from the iocsh shell with the new asynSetAutoConnectTimeout(double
+ timeout) command. This short timeout is designed to allow devices time to connect
+ if they are available, but not to excessively slow down booting of the IOC by waiting,
+ for example, for the system timeout on TCP connections. Note that this change means
+ that it is now very likely that the pasynCommon->connect() call will occur as
+ soon as the asynCommon interface is registered. As noted in the R4-12 release notes,
+ this means that the driver must have already done all initialization required for
+ the asynCommon->connect() callback before it registers the asynCommon interface!
+ - There is an additional new function, pasynManager->waitConnect(asynUser *pasynUser,
+ double timeout), which will wait for the for the port to connect, up to the specified
+ timeout. This function can be called from the iocsh with the new command asynWaitConnect(const
+ char *portName, double timeout). This function makes it possible to wait longer
+ for a port to connect then the current value of the global autoconnect timeout described
+ above.
+ - Fixed problems with the SyncIO calls, which were caused by the implementation of
+ pasynManager->lockPort():
+ - The SyncIO calls (e.g. asynOctetSyncIO) are implemented by calling pasynManager->lockPort(),
+ executing the I/O in the current thread, and then calling pasynManager->unlockPort().
+ These SyncIO functions are designed to be called from threads that are allowed to
+ block, such as SNL programs, or other drivers. The problem with the previous implementation
+ was that pasynManager->lockPort() immediately took the port mutex when it was
+ available, rather than queueing a request to take the mutex. This could lead to
+ one thread effectively getting exclusive access to the port, even if other threads
+ had queued requests or tried to do SyncIO calls themselves. For example, if a device
+ could send unsolicited input, then one might create a thread that simply called
+ pasynOctetSyncIO->read() with a short timeout in a tight loop. The problem with
+ this was that as soon as that thread released the port mutex when the read timed
+ out, it would take the mutex again, blocking other threads that were trying to access
+ the port. Previously the only solution to this problem was to add a short
+ epicsThreadSleep() in the read loop.
+ - This problem has been fixed by reimplementing pasynManager->lockPort(), which
+ now queues a request to access the port and then blocks until the queue request
+ callback runs in the portThread. When the queue request runs, the thread that called
+ pasynManager->lockPort() executes, and the portThread blocks, until pasynManager->unlockPort()
+ is called.
+ - Note that this change to lockPort() does change its functionality in one respect:
+ previously it was OK to call lockPort() on a port that was not connected. This is
+ no longer possible, because the queueRequest call in lockPort will now return an
+ error if the port is not connected.
+ - The change to lockPort did not require any changes to the asynXXXSyncIO functions
+ except asynCommonSyncIO. The asynCommonSyncIO->connectDevice and asynCommonSyncIO->connectDevice
+ calls cannot use lockPort() any more, because as noted above it does not work with
+ disconnected ports. Rather, these functions now directly queue a connection request
+ with a private callback function to connect or disconnect the port.
+- vxi11
+ - Fixed a bug in driver initialization. The driver had not completed all required
+ initialization before it called pasynGpib->registerPort. Because pasynGpib->registerPort
+ registers the asynCommon interface, that now normally triggers an immediate callback
+ to vxiConnect, and the driver was not yet properly initialized to handle that callback.
+ - Added an additional example driver, asynPortTest, that uses asynPortDriver. It implements
+ the asynInt32, asynFloat64, and asynOctet interfaces to communicate with the echo
+ server using asynOctetSyncIO calls. This tests nested SyncIO calls. Added a new
+ startup script, database and medm screen for testing this new driver.
+- devGpib
+ - Added a call to asynOctet->flush() just before the call to asynOctet->write()
+ operation when doing write/read operations. This eliminates any stale input that
+ may have already been sent by the device and would otherwise be incorrectly returned
+ by the read operation.
+- interposeEOS
+ - Now behaves properly even when eomReason is NULL.
+- testIPServerApp
+ - Changed ipEchoServer2.c to eliminate the epicsThreadSleep(0.01) in the listener
+ thread. This sleep is no longer necessary because of the change to lockPort described
+ above, so the example program was changed to test and demonstrate this.
+
+## Release 4-13-1 (May 20, 2010)
+- asynPortDriver
+ - Fixed bug in getXXXParam. It was not returning error status when a parameter was
+ undefined. This caused device support to use undefined values for output records,
+ because the initial read from the driver during device support initialization did
+ not return an error it should have.
+
+## Release 4-13 (April 1, 2010)
+- asyn/Makefile
+ - Change some dependencies to fix parallel (-j) make problem.
+- drvAsynIPPort
+ - A return of 0 from a read of a TCP stream is treated as an END condition rather
+ than as an error. This makes it easier to handle devices that close the connection
+ at the end of a reply.
+ - Support has been added for devices such as web servers that require a connect at
+ the beginning of each transaction. To enable this behaviour, specify "http" as the
+ protocol in the drvAsynIPPortConfigure command and ensure that each transaction
+ ends with a read that detects the broken connection from the device. Note that the
+ device will always appear connected. The connect/disconnect around each transaction
+ is handled within the drvAsynIPPort driver.
+- drvAsynIPServerPort
+ - Corrected the documentation to state that only the TCP/IP protocol is supported,
+ not UDP.
+- asynGpib
+ - Fix problem with NULL-pointer dereferences.
+- drvVxi11
+ - Bug fix from Benjamin Franksen for devices that don't support IRQ.
+- devEPICS
+ - The ring buffer code in devAsynFloat64.c, devAsynInt32.c and devAsynUInt32Digital.c
+ has been improved. Previously when ring buffer overflow occurred during a callback
+ the new value was simply discarded. This meant that when the record processed at
+ the end of a rapid burst of callbacks it would not contain the most recent value.
+ Now when overflow occurs the oldest value is removed from from the ring buffer and
+ the new value is added, so that the record will contain the most recent callback
+ value after a burst.
+ - asynUInt32Digital: asynMask values implying shifts greater than 16 bits are now
+ supported.
+- asynRecord
+ - Fixed bug which caused an error when writing or reading in binary format if the
+ driver did not implement the get(Input/Output)Eos functions. This bug was introduced
+ when readRaw and writeRaw were removed from asynOctet in release 4-10.
+- Additional makeSupport.pl template
+ - makeSupport.pl -t streamSCPI creates skeleton stream protocol and database
+ files for a SCPI (IEEE-488.2) device.
+- asynPortDriver
+ - Fixed bug in readInt32Array, not taking lock where needed.
+ - Added drvInfo strings to parameter lists, and new methods to support this: createParam(),
+ findParam(), getParamName(). The report functions now print out the drvInfo strings,
+ which is very useful. The base class drvUserCreate() method can now be used without
+ reimplementing in derived classes, because the parameter names are now available
+ to the base class. Removed asynParamString_T and drvUserCreateParam(), which are
+ no longer needed. The testAsynPortDriver test application has been updated to use
+ these new features.
+
+## Release 4-12 (August 19, 2009)
+- asynManager
+ - A problem was introduced in R4-11 by not starting the autoconnect process until
+ iocInit(), and operations that do not use the XXXSyncIO functions thus fail before
+ iocInit(). This means, for example, that calls to asynSetOption() to set serial
+ port parameters fail if done in a startup script before iocInit(). R4-12 fixes this
+ problem by decoupling autoconnect operations from iocInit(). NOTE: The first call
+ to the pasynCommon->connect() function now happens almost immediately after pasynManager->registerInterface()
+ is called for the asynCommon interface. This timing is different from all previous
+ asyn releases, and it means that port drivers must initialize everything required
+ by asynCommon->connect() before they register the asynCommon interface. This
+ may require minor re-ordering of the initialization sequence in some drivers.
+- drvAsynSerialPort
+ - Requests to set end-of-string values or serial port parameters are accepted even
+ when the port is not connected. The request takes effect when the port is connected.
+ This makes IOC startup more robust in the face of network or USB to serial adapters
+ that may be unavailable on startup.
+- asynInt32Average, asynFloat64Average
+ - If record is processed before new data have arrived (numAverage==0) set record to
+ UDF/INVALID, set UDF to TRUE and leave value unchanged.
+
+## Release 4-11 (June 16, 2009)
+- asynManager
+ - asynReport at detail level 0 now reports only disconnected subaddresses.
+ - The autoconnect code has undergone considerable modification. When a port is registered
+ with autoConnect true, or whenever a port disconnect exception is raised on an autoConnect
+ port, an attempt at connection occurs immediately followed by retry attempts at
+ 20 second intervals. Attempts to queue requests to a disconnected port (even an
+ autoConnect port) will be rejected. These changes have been made to reduce the occurences
+ of 'connection flurries' and to ensure that requests do not languish in the queue
+ when connections are broken.
+ - Setting the trace mask or trace I/O mask for a port now also sets the trace mask
+ or trace I/O mask for every device associated with that port.
+ - Passing a NULL pasynUser argument to the setTraceMask and setTraceIOMask will set
+ the asynBase (default) trace mask or trace I/O mask. To do this from the iocsh pass
+ a zero length portName string to the iocsh commands asynSetTraceMask or asynSetTraceIOMask.
+- asynDriver.h
+ - Add new version macros (ASYN_VERSION, ASYN_REVISION and ASYN_MODIFICATION). These
+ are guaranteed to be numeric.
+ - Add new asynStatus codes, asynDisconnected and asynDisabled.
+ Attempts to queue a request to a disconnected or disabled port return these codes,
+ respectively. Future changes to record support may propogate these to the record
+ alarm status field.
+- asynInterposeEOS
+ - Increased the size of the input buffer from 600 to 2048 bytes.
+- VXI-11
+ - Fix from Takashi Asakawa, Yokogawa Electric Corporation, Japan to allow link identifiers
+ with a value of zero.
+- devEpics (devAsynInt32, devAsynFloat64, devAsynUInt32Digital)
+ - Ignore callbacks when interruptAccept=0, because waiting for interruptAccept (the
+ previous behavior) hangs iocInit with synchronous drivers. The first record process
+ on input records will now read directly from driver, which will get the latest value.
+ - Added mutex around epicsRingBytes calls
+ - Added ASYN_TRACEIO_DEVICE when reading value from ring buffer
+- testIPServerApp
+ - Add some cleanup code to eliminate memory/socket leaks.
+- asynOctetSyncIO
+ - The asynOctetSyncIO openSocket method will be removed in the next
+ release. This method is redundant since it is no different than calling the
+ connect method with the port name from a previous drvAsynIPPortConfigure
+ command.
+- asynPortDriver
+ - A new C++ base class called asynPortDriver from which real asyn
+ port drivers can be derived. It greatly simplifies the code required to write a
+ new asyn port driver. It is documented here.
+- testAsynPortDriverApp
+ - A new test application to demonstrate the use of the new asynPortDriver C++ class.
+ This driver simulates a simple digital oscilloscope, and includes a C++ driver,
+ EPICS database, medm screen, and an example iocBoot directory in ioctestAsynPortDriver.
+ It is described in the documentation for asynPortDriver.
+
+## Release 4-10 (Sept. 2, 2008)
+- asynOctet
+ - Ths asynOctet writeRaw and readRaw methods have
+ been removed. In most cases, if your code now calls readRaw or writeRaw it should
+ be safe to simply change these calls to their non-Raw equivalent. If you're paranoid
+ about someone interposing the end-of-string processing layer you could add something
+ like the following to ensure that there is no end-of-string to match:
+ ```
+ pasynOctet->setInputEos(asynOctetPvt,pasynUser,NULL,0);
+ ```
+ - If you need to switch to 'raw' mode for a while and then back to 'eos mode', you
+ can use code similar to that in devGpib.c:readArbitraryBlockProgramData:
+```
+char saveEosBuf[5];
+int saveEosLen;
+.
+.
+.
+status = pasynOctet->getInputEos(asynOctetPvt,pasynUser,saveEosBuf,sizeof saveEosBuf,&saveEosLen);
+if (status != asynSuccess) {
+ epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,"Device EOS too long!");
+ return -1;
+}
+if (saveEosLen)
+pasynOctet->setInputEos(asynOctetPvt,pasynUser,NULL,0);
+.
+.
+.
+.
+if (saveEosLen)
+ pasynOctet->setInputEos(asynOctetPvt,pasynUser,saveEos,saveEosLen);
+```
+ When compiling your code against this new version of asyn you should pay particular
+ attention to warning messages of the form "warning: initialization from incompatible
+ pointer type". These are a good indication that you're initializing an asynOctet
+ structure with the old-style I/O methods.
+
+- asynManager
+ - Add a strStatus method to convert an asynStatus code to a string.
+- drvAsynIPPort
+ - Cleaned up timeout handling.
+ - Fix memory leak (one epicsAtExit entry was allocated for every connect).
+ - asynReport no longer reports as connected a port which has successfully disconnected.
+ - Improved diagnostic messages.
+- drvAsynIPServerPort
+ - Fixed bugs that caused the thread that listened for new connections to exit when
+ errors occurred. Such errors included too many simultaneous connections.
+- interfaces
+ - Added three new array interfaces, asynInt8Array, asynInt16Array, and asynFloat32Array.
+ asynInt8Array and asynInt16Array are the same as asynInt32Array except that the
+ data types are for epicsInt8 and epicsInt16 respectively. asynFloat32Array is the
+ same as asynFloat64Array except that the data type is for epicsFloat32.
+ - Added asyn(XXX)ArraySyncIO for synchronous I/O to all array interfaces.
+ - Added new asynGenericPointer interface. The datatype for this interface is void*,
+ so it can be used to pass a pointer to anything. Includes asynGenericPointerSyncIO
+ for synchronous I/O.
+ - Added asynStandardInterfaces.h and asynStandardInterfacesBase.c to simplify driver
+ initialization when using the standard asyn interfaces defined in asyn/interfaces
+ (common, octet, int32, etc.)
+- devEpics
+ - Undid the change that was done in R4-9 with direct calls to dbScanLock and process
+ in the interrupt callback functions. This could lead to deadlocks in some circumstances.
+ The original reason for changing from scanIoRequest to (dbScanLock, process) was
+ because callback values would be lost if the callbacks came so close together in
+ time that the single callback value stored in device support was overwritten before
+ scanIoRequest could process the record. This problem has been fixed by adding a
+ FIFO (ring buffer) to the device support for the scalar interfaces asynInt32, asynUInt32Digital,
+ and asynFloat64. The ring buffer is only created when the record is put into I/O
+ Intr scan, so the storage is not allocated for records that are not I/O Intr scanned.
+ The ring buffer default size is 10 values, but this can be changed on a per-record
+ basis using the dbInfo string "FIFO" with a value such as "100".
+ - Added support for bi and bo records for asynInt32 interface. Previously these records
+ were only supported for the asynUInt32Digital interface.
+ - Added waveform record device support for the asynInt8Array, asynInt16Array, and
+ asynFloat32Array interfaces. These are the same as devAsynInt32Array and devAsynFloat64Array
+ with changes to the data types.
+- asynShellCommands
+ - Remove duplicate windows function decorations.
+- asynInterposeEos
+ - Improved diagnostic messages.
+- testIPServerApp/ipSNCServer.st
+ - Fixed timeout bug introduced in R4-6 when timeouts of 0.0 and -1.0 were defined.
+
+## Release 4-9 (October 19, 2007)
+- devEpics
+ - Replaced scanIoRequest with direct call to rset->process in interrupt callback
+ routines in all device support. Without this fix if another interrupt occurred before
+ the first scanIoRequest was complete bad things could happen. The data from the
+ first interrupt would be lost, and the read function in the driver would be called
+ when it should not have been.
+- drvAsynSerialPort
+ - Added support for 28,800 baud for those architectures which support this unusual
+ speed.
+ - Added stub routines for WIN32 so that a separate DBD file is no longer needed.
+- drvAsynIpPort
+ - Added short delay in cleanup routine so sockets would close cleanly.
+- asynInterposeEos.c
+ - Fixed bug which caused asynOctetRead() to return prematurely with eomReason=ASYN_EOM_CNT
+ if the port driver returned 600 bytes in readRaw().
+- RTEMS
+ - Build driver for Greensprings IP-488 if IPAC is defined in configure/RELEASE.
+- VXI11
+ - Added stub routines for WIN32 so that a separate DBD file is no longer needed.
+- VXI-11
+ - Avoid duplicate clnt_destroy operations.
+
+## Release 4-8 (April 28, 2007)
+- devEpics/devAsynInt32
+ - Added support for link specification of
+ ```
+ @asynMask(portName,addr,nbits,timeout)drvParams
+ ```
+ in addition to the previous support for
+ ```
+ @asyn(portName,addr,timeout)drvParams
+ ```
+ This allows device support to work with drivers that cannot return meaningful values
+ in pasynInt32->getBounds because they do not know the range of the device. This
+ is true, for example of Modbus ADCs. The nbits parameter is defined as follows:
+ ```
+ nbits > 0 Device is unipolar with a range from 0 to 2^nbits-1
+ nbits < 0 Device is bipolar with a range from -2^(abs(nbits)-1) to 2^((abs(nbits)-1)-1
+ Values returned on the asynInt32 interface will be sign extended
+ using the sign bit (e.g. bit abs(nbits)-1 starting at bit 0).
+ ```
+- devEpics/devAsynInt32Array, devAsynFloat64Array
+ - Added support for callbacks from driver to device support. This allows waveform
+ records to have I/O Intr scanning, as already supported for other records in devEpics.
+- devEpics/asynEpicsUtils
+ - Changed parser so it requires an exact match to "asyn(" or "asynMask(". Previously
+ it tolerated other characters before the "(", and in particular it accepted "asynMask("
+ when "asyn(" was expected. Note that this change could cause problems with database
+ files if they did not follow the documented syntax, which has no white space between
+ "asyn" or "asynMask" and the "(" character.
+- asynManager
+ - Fix errors in format strings for asynPrint.
+ - Temporary fix to asynReport thread for Cygwin. If the amount of output is small
+ the thread exists for a very short time, and this causes a crash. The fix is a short
+ wait, but it should really be fixed in base/src/libCom/osi/os/posix/osdThread.c.
+- testIPServerApp
+ - Fix problem with Makefile.
+- devGpib
+ - Add more SCPI commands to devGpib template.
+- drvAsynIPPort
+ - Close sockets on application exit. This is very important for vxWorks, otherwise
+ sockets are not closed cleanly which often leads to problems when the IOC reboots.
+- drvGsIP488
+ - Hold off SRQ callbacks until iocInit.
+
+## Release 4-7 (February 28, 2007)
+- drvAsynSerialPort
+ - Clean up operation on POSIX/termios systems (everything but vxWorks). The old mechanism
+ was prone to polling during read operations rather than using the termios read timeout
+ mechanism.
+- devGpib
+ - asynRecord sets line-buffering on trace file.
+ - Peter Mueller provided code to remove/restore a device from/to the SRQ polling list.
+- drvGsIP488.c
+ - Clean up dangling 'default' statement.
+- devGpib
+ - Fixed error in GPIBACMD operations.
+- linuxGpib
+ - Patches from Gasper Jansa to improve option handling.
+- devEpics
+ - Fixed null pointer dereference for all device support when SCAN=I/O Intr and asyn
+ port could not be found.
+- asynRecord
+ - Fixed buffer overflow error when NRRD>40 and IFMT=ASCII.
+- asynGpib
+ - Read method now sets return status and *eomReason properly.
+- drvAsynIPPort/drvAsynSerialPort
+ - *eomReason now set to ASYN_EOM_CNT when read count has been satisfied.
+ - Fix timeout settings on RTEMS.
+ - Add support for UDP broadcasts. Specify "UDP*" and the network broadcast address
+ in the port configuration command:
+ `drvAsynIPPortConfigure("L0", "192.168.1.255:1234 UDP*", 0, 0, 0)`
+- drvAsynSerialPort
+ - Full support for new timeout semantics (timeout<0 means "wait forever for characters
+ to arrive", timeout=0 means "return characters immediately available", timeout>0
+ means "return a timeout status if no characters are received within the specified
+ number of seconds").
+
+## Release 4-6 (June 12, 2006)
+- drvAsynIPPort/drvAsynSerialPort
+ - Fixed NULL pointer dereference.
+- drvAsynIPPort
+ - Previous versions of drvAsynIPPort.c (1.29 and earlier, asyn R4-5 and earlier) attempted
+ to allow 2 things:
+ - Use an EPICS timer to time-out an I/O operation, such as send(), recv() and connect().
+ - Periodically check (every 5 seconds) during a long I/O operation to see if the
+ operation should be cancelled.
+ - Item 1) above was not really implemented because there is no portable robust way
+ to abort a pending I/O operation. So the timer set a flag which was checked after
+ the poll() was complete to see if the timeout had occured. This was not robust,
+ because there were competing timers (timeout timer and poll) which could fire in
+ the wrong order.
+ - Item 2) was not implemented, because asyn has no mechanism to issue a cancel request
+ to a driver which is blocked on an I/O operation.
+ - Since neither of these mechanisms was working as designed, the driver has been re-written
+ to simplify it. If one or both of these are to be implemented in the future the
+ code as of version 1.29 should be used as the starting point.
+ - If pasynUser->timeout < 0 an infinite timeout is now used.
+ - Fixed bug so that ports connected with a file descriptor in pasynUser->reason
+ execute code to set timeouts.
+ - Fixed bug to return error if pasynCommon->connect is called when port already
+ connected.
+- asynTrace
+ - Added two new functions which are related to pasynTrace->print and pasynTrace->printIO
+ the way vprintf is related to printf.
+ - pasynTrace->vprint Same as pasynTrace->print except that instead of a variable
+ of arguments it takes a va_list argument as its last parameter.
+ - pasynTrace->vprintIO Same as pasynTrace->printIO except that instead of
+ a variable of arguments it takes a va_list argument as its last parameter.
+- asynManager
+ - Changed pasynManager->connectDevice for ports which have the properties autoConnect=1
+ and isConnected=0. In this case a request is queued to call asynCommon->connect
+ for that port. This ensures that ports that have a pasynUser connected to them will
+ report being connected even if no I/O has yet been done. Previously such ports reported
+ a disconnected state until the first I/O or operation such as setTraceMask. This
+ was confusing.
+ - Clarify documentation on meaning of pasynUser->timeout. Previously there was
+ no documented method of specifying an "infinite" timeout to a driver, and the meaning
+ of timeout=0.0 was not defined. The new definitions are:
+
+ > 0.0 Wait for up to timeout seconds for the I/O to complete
+
+ = 0.0 Peform any I/O that can be done without blocking. Return timeout error if
+ no I/O can be done without blocking.
+
+ < 0.0 Infinite timeout. Wait forever for I/O to complete.
+- devEpics
+ - Fixed bugs with asynFloat64Average device support. The wrong interrupt function
+ was being called, and UDF was not being cleared.
+
+## Release 4-5 (April 17, 2006)
+- memMalloc/memFree
+ - memMalloc was allocating the amount of memory the caller requested rather than the
+ amount required for the freeList. If memFree was called and the memory reallocated
+ to a user requesting a larger size, memory corruption occured. This is fixed.
+- SyncIO routines
+ - If the connect call fails the asynUser is no longer freed. Instead a message is
+ put into asynUser.errorMessage. The caller must call disconnect in order to free
+ the storage for the asynUser.
+ - The SyncIO routines no longer call asynPrint if there is an error and there is a
+ valid asynUser available. Rather they return an error message in pasynUser->errorMessage.
+ The SyncIO*Once functions still call asynPrint for errors, because they do not have
+ a way of returning an error message.
+- Serial, TCP/UDP/IP
+ - Handle 0-length write requests.
+- TCP/UDP/IP
+ - Added drvAsynIPServerPort to support TCP and UDP socket servers.
+ - Added iocBoot/testIPServer to test TCP server support.
+ - drvAsynIPPort now closes TCP sockets when remote system closes connection.
+ - drvAsynIPPort connect function now uses pasynUser->reason as a file descriptor
+ if it is > 0. This allows drvAsynIPServerPort to re-use asyn ports it creates.
+ - Made drvAsynIPPort add null byte at end of input if there is room.
+ - Made drvAsynIPPort:readRaw set eomReason to 0. It was not setting eomReason at all
+ previously.
+- Serial
+ - Made drvAsynSerialPort add null byte at end of input if there is room.
+ - Made drvAsynSerialPort:readRaw set eomReason to 0. It was not setting eomReason
+ at all previously.
+- Interfaces
+ - Added asynCommonSyncIO for synchronous support of the asynCommon interface.
+- VME GPIB
+ - Add delay loops to get these boards to work with faster VME CPU modules.
+
+## Release 4-4 (December 15, 2005)
+- VXI11
+ - Better support was provided for VXI-11.3 controllers, i.e. talking directly to an
+ ethernet port on an instrument. In particular a TDS3054B was tested.
+ - WARNING: The VXI-11.1 ansd VXI-11.3 standards do NOT allow access to GPIB lines,
+ i.e. conmmands like Untalk/Unlisten are not possible. The previous support issued
+ these commands after each read or write. Some really old GPIB devices may fail.
+ If so the device specific code must be modified to sent these commands separately.
+- win32
+ - Changes were made to allow asyn to build on native Windows (win32-x86) architecture.
+ - There are two asyn components that do not yet work on win32-x86.
+ - Local serial ports. The asyn uses the "termios" API for serial ports, and termios
+ is not available for native Windows.
+ - VXI-11. The asyn VXI-11 support uses the Sun XDR API, which is not available for
+ native Windows.
+ - Users who want to use local serial ports or VXI-11 on Windows can use the Cygwin
+ EPICS build (cygwin-x86).
+- devGpib: devGpibConvertExample
+ - An example of how to implement convert routines for devGpib support modules is available
+ in asyn/devGpib/devGpibConvertExample.c
+- devAsynOctet.c
+ - The UDF field is now set FALSE when the VAL field is updated.
+
+## Release 4-3 (September 15, 2005)
+- asynManager
+ - lock/unlock renamed to blockProcessCallback/unblockProcessCallback
+ - The names have been changed and now these methods only work for asynchronous ports.
+ An error is returned if blockProcessCallback is called for a synchronous port.
+ - lockPort/unlockPort
+ - These are new asynManager methods. They can be used in place of queueRequest if
+ the caller can block. They have been added to make it easier to implement a driver
+ with one addressing scheme that is a asynUser of a driver with a different addressing
+ scheme. For example a multi-drop serial driver can be implemented that calls a standard
+ serial driver.
+ - asynLockPortNotify
+ - This is a new interface for driver's that call other drivers.
+- cancelInterruptUser
+ - The cancelInterruptUser methods of all interfaces has been changed from
+ ```
+ asynStatus (*cancelInterruptUser)(void *registrarPvt, asynUser *pasynUser);
+ ```
+ to
+ ```
+ asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser, void *registrarPvt);
+ ```
+- asynTrace
+ - The length and size arguments now have type `size_t`.
+- devGpib
+ - Several improvements were made to devSupportGpib.c. All changes should be transparent
+ to code that uses devGpib.
+- asynOctetBase
+ - The `maxchars` argument to `callInterruptUsers` has been removed.
+- asynReport
+ - The filename argument has been removed.
+- devAsynFloat64
+ - For `asynAoFloat64` it now uses `oval` instead of `val`.
+- asynFloat64Array, asynInt32Array, asynOctet, asynOctetSyncIO
+ - All length and size arguments now have type `size_t`.
+- asynFloat64SyncIO, asynInt32SyncIO, asynOctetSyncIO, and asynUInt32DigitalSyncIO
+ - These all use `lockPort/unlockPort` instead of `queueRequest`.
+
+## Release 4-2-1 (March 30, 2005)
+- devAsynFloat64
+ - Device support was not returning 2 (do not convert) for ai records when it should.
+ This meant that the VAL field was being set back to 0 by the record after device
+ support wrote to it. This bug is fixed.
+- asynRecord
+ - The record sometimes did not read the current input and output EOS values from the
+ driver when it connected. This bug is fixed.
+
+## Release 4-2 (February 15, 2005)
+- Acknowledgement
+ - Yevgeny A. Gusev has again reported some hard to recognize bugs. He must have spent
+ many hours looking at the code. His extra set of very good eyes are much appreciated!!.
+ He also thought of the way to handle support that uses one addressing scheme but
+ wants to use support that has a different addressing scheme. For example support
+ for mult-drop serial that wants to use the standard serial support
+- asynInterposeEos
+ - If read reads maxchars, it forced the last character to be 0 and returned asynOverflow
+ if it wasn't. This is fixed.
+- drvAsynSerialPort,drvAsynIPPort - Error reporting
+ - These did not properly set an error message in asynUser.errorMessage when they returned
+ asynError. This is fixed.
+- drvAsynSerialPort - serial port options
+ - Changes were made to the way serial port options are handled.
+ - initial values
+ - Previously defaults were assigned for all options. Now the initial values are fetched
+ from either the termios (POSIX) or sioLib (vxWorks).
+ - vxWorks clocal and crtscts
+ - The vxWorks sioLib uses clocal for what POSIX calls crtscts. The new serial support
+ for vxWorks accepts both clocal and crtscts to specify RTSCTS (Request to send,
+ Clear to send).
+- asynRecord - Serial Port Options
+ - This has a new option to set Modem Control.
+
+## Release 4-1 (December 20, 2004)
+ - The only code change was to fix the drvAsynIPPort and drvAsynSerialPort segmentation
+ faults on cygwin-x86.
+
+## Release 4-0 (November 22, 2004)
+- Incompatible Changes.
+ - APOLOGY: Many interfaces have changed since release 3-3. This is the reason this
+ release is called 4-0.
+ - asynManager - Only report has changed. Many new methods have been added. asynManager:report
+ takes an additional parameter, portName.
+ - asynOctet - The read/write methods are similar to before. The new version has
+ sepearate end of string methods for input and output.
+ - register based interfaces - Extensive changes have occured.
+ - devGpib - Unless special conversion routines call low level drivers, debGpib support
+ should work without any changes.
+ - devEpics -
+ - Extensive changes have occured. The support naming now follows the names of asyn
+ interfaces. For example devAsynInt32 contains device support for interface asynInt32.
+ - device definitions have changed.
+ - Blanks no longer appear in the menu choices. For example.
+ ```
+ device(ai,INST_IO,devAiAsynInt32,"asyn Int32")
+ ```
+ is now
+ ```
+ device(ai,INST_IO,asynAiInt32,"asynInt32")
+ ```
+ - asynOctetSyncIO
+ - All read and write methods now return asynStatus and have additional args to return
+ the number of bytes sent/received.
+ - asynRecord
+ - The IEOS and OEOS fields are set to the current values for the port when the record
+ connects to the port. If they are modified after the record connects to the port,
+ then the EOS strings will be changed using asynOctet->setOutputEos or asynOctet->setIbputEos.
+ IMPORTANT: The values of IEOS and OEOS in the database file are never used, because
+ they are modified when the record connects to the port.
+- New Features
+ - interrupt support -A major new feature is support for interrupts. See asynDriver.html
+ for details.
+ - linuxGpib - This is support for the linuxGpib open source project. It contains
+ support for many linux gpib kernel drivers. The asyn support was provided by Rok
+ Sabjan (cosyLab).
+ - cancelRequest - If cancelRequest is called while either the process or timeout
+ callback is active, it now waits until the callback completes.
+ - asynRecord
+ - Added PCNCT field to connect/disconnect from port, and to indicate if port is
+ currently connected.
+ - Added DRVINFO and REASON fields to provide control for the drvUser interface.
+ - Added support for register interfaces (asynInt32, asynUInt32Digital, and asynFloat64).
+ New I/O fields for this support are I32INP, I32OUT, UI32INP, UI32OUT, UI32MASK,
+ F64INP, and F64OUT. The new IFACE field is used to select the currently active interface.
+ - Added new fields to indicate if a particular interface is supported by the driver.
+ These fields are OCTETIV, I32IV, UI32IV, F64IV, OPTIONIV, and GPIBIV.
+ - Added support for I/O Intr scanning for any driver/interface that supports callbacks.
+ asynOctet does not yet support callbacks.
+
+## Release 3-3 (August 23, 2004)
+- Incompatible Changes.
+ - MAY BE MORE - This release has major new features. Implementing the new features
+ may have caused some imcompatibilities, This list is likely to grow as existing
+ users report problems.
+ - queueRequest - If the portDriver does not block then the queue callback is called
+ by queueRequest rather than by a separate thread. User code can call canBlock to
+ find out how the callback is called.
+ - registerPort - The argument multiDevice has been replaced by attributes. Attributes
+ currently has two bits ASYN_MULTIDEVICE and ASYN_CANBLOCK. The port driver is responsible
+ for setting both bits correctly.
+ - setOption/getOption have been moved from asynCommon to a new interface asynOption.
+- Major New Features
+ - Support for synchronous drivers.
+ - Support for register based drivers.
+ - Generic register based device support for EPICS records.
+ - Additional fields have been added to asynUser.
+ - Added pasynManager->memMalloc() and pasynManager->memFree() for allocating
+ and freeing memory with a freelist. This is primarily meant to be used with pasynManager->duplicateAsynUser()
+ and the new pasynUser->userData field.
+- asynDriver.h
+ - The following changes have been made
+ - userData - this is a new field in asynUser.
+ - registerPort - Field multiDevice is replaced by attributes. Currently two attributes
+ are defined: ASYN_MULTIDEVICE and ASYN_CANBLOCK.
+ - duplicateAsynUser - This is a new method that creates a new asynUser and initializes
+ it with values from an existing asynUser. freeAsynUser now puts the asynUser of
+ a free list rather than calling free.
+ - memMalloc/memFree - New methods that manage storage. It uses a set of free lists
+ of different sizes.
+ - asynCommon no longer has methods setOption/getOption.
+ - asynOctet is now defined in a separate header file.
+- asynRecord
+ - Removed the GOPT field. This is no longer necessary because the port options are
+ automatically read whenever connecting to a port. "special" requests are now queued
+ without changing the state of the record, using the new duplicateAsynUser, memMalloc(),
+ and memFree() methods. This means that there is no longer a possibility of a special
+ request being rejected because the record is busy. It is no longer possible to cancel
+ a special request.
+- asynGpib
+ - asynGpibPort:srqStatus returns asynStatus
+ - asynGpibPort:serialPoll returns asynStatus. It now only calls a registered callback
+ only if statusByte&0x40 is non zero.
+- devSupportGpib
+ - setEos is now a method.
+ - completeProcess is a new method. This was added to support synchronous drivers.
+ - Failures for GPIBREADW|GPIBEFASTIW were not handled properly. This could cause
+ and assert failure. This is fixed.
+- drvAsynSerialPortFlush
+ - Flushes input only.
+- asynInterposeEOS
+ - The EOS read method now calls the low-level read method only once and returns as
+ many characters as the low-level method supplies. This makes the EOS read semantics
+ match those of the low-level serial and IP drivers.
+- drvVxi11
+ - vxi11SetRpcTimeout - now handles fractions of a second properly
+- asynRecord
+ - A new field has beem added, AQR (Abort Queue Request)
+ - The semantics have been changed as follows: process is responsible for all and only
+ for I/O operations. Only I/O operations cause the alarm status and severity to change.
+ Special is responsible for all other operations performed by asynRecord.
+
+## Release 3-2 (June 22, 2004)
+- Changed and obsolete features
+ - INCOMPATIBLE CHANGE -- The units of the `respond2Writes`
+ field, if greater than 0, are now seconds rather than milliseconds. This change
+ was made so that all time values set in the instrument support initialization routine
+ are specified uniformly in units of seconds. Very few instrument support files are
+ likely to be affected by this change
+ - The contents of asynRecDevDrv.dbd have been placed in asyn.dbd and asynRecDevDrv.dbd
+ has been removed. This allows applications to get correct dbior reports and access
+ to asynRecords by including any low-level driver .dbd file.
+ - The drvAsynTCPPort driver has been renamed drvAsynIPPort since it now supports
+ both UDP and TCP protocols. The protocol is selected by adding a "UDP" or "TCP"
+ after the "hostname:port" in the drvAsynIPPortConfigure command. A missing protocol
+ is taken to be "TCP".
+ - Work around 'missing SPD' bug in HP E2050 GPIB/LAN adapter. SRQ handling is much
+ more robust on all supported hardware.
+- Major New Features
+ - National Instruments NI1014 VME GPIB interface is now supported.
+ - GPIB - All low level GPIB support (vxi11, gsip488, and ni1014) now fully support
+ the GPIB specific features defined by asynGpibDriver.h
+ - Implementation of asynTrace is more consistent across the low level drivers.
+ - Added makeSupport script and template instrument support. Updated tutorials to
+ reflect these additions.
+
+## Release 3-1 (April 29, 2004)
+- Changed and obsolete features
+ - The drvGenericSerial driver has been split into drvAsynSerialPort and drvAsynTCPPort
+ drivers for local and remote serial ports, respectively. End-of-string processing
+ has been moved to an interposed interface.
+ - The diagnostic facilities previously provided by asynTrace.db have been replaced
+ with the much more general asynRecord.db
+ - All asynManager,asynCommon, and asynOctet methods except report now return asynStatus.
+ Methods that previously returned a different value now have an additional argument
+ for this value.
+ - Low-level driver read and write methods now return asynStatus and are passed an
+ additional argument through which they store the actual number of characters read
+ or written.
+ - The createSocket method in the asynSyncIO interface has been replaced by openSocket.
+ openSocket does not call asynSyncIO->connect(), that must now be done by the
+ caller.
+ - Removed code for "flush" from gpib drivers. The implementation caused infinite
+ loops on devices that speak when not spoken to.
+ - asynRecord
+ - asynOctetRecord has been renamed to asynRecord
+ - TIOM, TMSK, TSIZ, TFIL, AUCT, ENBL, CNCT, ERRS, TINP, NAWT fields have been added
+ - Default values of OMAX and IMAX decreased from 512 to 80
+ - Options that are unknown for a device (e.g. baud on a Moxa terminal server) are
+ shown as Unknown.
+ - Many bug fixes and improvements in logic and functionality
+
+## Release 2-1 (April 2, 2004)
+- Major New Features
+ - Connection Management - A framework for connection management is provided. It
+ provides the ability to connect/disconnect to/from a port or port,addr. It also
+ provides enable/disable and autoConnect/noAutoConnect. See the asynDriver for details.
+ - devAsyn - Generic device support for connect management for a specific device.
+ - devAsynGeneric - Generic support for connection management and traceing. This
+ support dynamically attaches to a port,addr. Thus one set of records and one medm
+ display can be used for all devices connected to an ioc.
+ - asynOctetRecord - A generic record and medm display that allows interactive access
+ to many asynDriver features.
+ - asynSyncIO - A synchronous interface to asynDriver. This can be used by code,
+ e.g. SNC programs, that are willing to wait instead of following an asynchronous
+ model.
+- Changed and obsolete features
+ - devAsynTrace is replaced by devAsyn and devAsynGeneric.
+ - asynManager.h
+ - disconnectDevice has been renamed to disconnect.
+ - The interface to low level drivers has been drastically modified in order to support
+ the new connection management features. See the asynDriver documentation for details.
+ - asynGpib
+ - registerPort has additional arguments multiDevice and autoConnect.
+ - setPortOption,getPortOption are setOption,getOption
+
+## Release 1-2 (April 1, 2004)
+- Promote VXI-11 RPC definition files to vxi11 directory. Use rpcgen to build RPC
+ support files for targets for which this is possible.
+- Run rpcgen on Solaris with 'multi-thread' flag.
+- Use separate GPIB message/response buffer for each port instance.
+- Use sscanf to convert GPIB stringin response.
+- Fix race condition in GPIB finish routines.
+
+## Release 1-1 (February 5, 2004)
+- This release includes support for the following:
+ - asynTrace - A trace facility is now implemented.
+ - gsIP488 - The Greensprings Industry Pack IP488 is now supported
+- Modifications include:
+ - Added asynSetPortOption and asynGetPortOption to manipulate port options.
+ - Changed serial support to use asynSetPortOption/asynGetPortOption.
+ - Added devGPIB GPIBCVTIO commmand type to allow custom conversion routine to perform
+ all I/O operations.
+ - Changed rules for return value from devGPIB custom conversion routines.
+ - Added dbior support.
+ - Changed devGPIB to no longer cache EOS.
+
+## Release 1-0alpha2 (November 17, 2003)
+- Support Provided in addition to asynDriver and asynGpib
+ - devGpib - The Winans/Franksen gpib device support.
+ - vxi11 - Support for instruments that support the VXI-11 standard.
+ - drvGenericSerial - Support for devices connected to serial ports or to Ethernet/Serial
+ converter.
+- Future Support
+ - Other device support methods especially streams, devSerial, and mpfSerial.
+ - NI1014 VME Gpib driver.
+ - Industry Pack IP488 Gpib driver.
+ - Successor to GI (GPIB Interact).
+- Testing
+ - The vxi11 support has been tested on the following platforms: Solaris, Linux (redhat
+ 9), Darwin, Windows XP (Cygwin), and vxWorks. It has been tested with the following
+ vxi11 controllers:
+ - Agilent E2050A LAN/GPIB Gateway.
+ - It's vxiName must start with "hpib" rather than "gpib".
+ - Agilent E5810A LAN/GPIB Gateway.
+ - Tektronix TDS3014B Scope.
+ - When communicating with the Ethernet port it acts like a VXI-11.2 rather than a
+ VXI-11.3 device. It seems to just accept any GPIB address. SRQs did not work when
+ connecting via the ethernet port but did when communicating via a LAN/GPIB gateway.
+ - The generic serial support has been tested with the following:
+ - xvWorks with a GreenSprings Octal UART Industry-Pack module on a VME carrier.
+ - Linux and Windows XP (Cygwin) with PC hardware serial port (/dev/ttyS0).
+ - Solaris hardware serial port (/dev/cua/a).
+ - Linux, Solaris, Darwin, vxWorks, and Windows XP (Cygwin) with a Moxa NPort Ethernet/Serial
+ converter.
+ - Two Device Support modules have been converted from the 3.13 gpib support: DG535
+ and TDS3014B Scope.
diff --git a/asyn/Makefile b/asyn/Makefile
index 35c7124..e0cdd44 100644
--- a/asyn/Makefile
+++ b/asyn/Makefile
@@ -12,6 +12,9 @@ include $(TOP)/configure/CONFIG
ASYN = $(TOP)/asyn
#USR_CFLAGS += -DDEBUG
+USR_CFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET -DUSE_TYPED_DRVET
+USR_CPPFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET -DUSE_TYPED_DRVET
+
USR_INCLUDES_cygwin32 += -I/usr/include/tirpc
# The following gets rid of the -fno-implicit-templates flag on vxWorks,
@@ -23,11 +26,7 @@ endif
USR_CXXFLAGS_solaris-sparc=-instances=global
LIBRARY_IOC += asyn
-ifeq ($(EPICS_LIBCOM_ONLY),YES)
- asyn_LIBS += Com
-else
- asyn_LIBS += $(EPICS_BASE_IOC_LIBS)
-endif
+
asyn_SYS_LIBS_WIN32 = ws2_32 winmm
asyn_SYS_LIBS_cygwin32 = $(CYGWIN_RPC_LIB)
@@ -39,6 +38,7 @@ ifeq ($(TIRPC),YES)
endif
SRC_DIRS += $(ASYN)/asynDriver
+INC += asynAPI.h
INC += asynDriver.h
INC += epicsInterruptibleSyscall.h
asyn_SRCS += asynManager.c
@@ -64,11 +64,13 @@ INC += drvAsynIPServerPort.h
SRC_DIRS += $(ASYN)/interfaces
INC += asynInt32.h asynInt32SyncIO.h
+INC += asynInt64.h asynInt64SyncIO.h
INC += asynUInt32Digital.h asynUInt32DigitalSyncIO.h
INC += asynFloat64.h asynFloat64SyncIO.h
INC += asynInt8Array.h asynInt8ArraySyncIO.h
INC += asynInt16Array.h asynInt16ArraySyncIO.h
INC += asynInt32Array.h asynInt32ArraySyncIO.h
+INC += asynInt64Array.h asynInt64ArraySyncIO.h
INC += asynFloat32Array.h asynFloat32ArraySyncIO.h
INC += asynFloat64Array.h asynFloat64ArraySyncIO.h
INC += asynOctet.h asynOctetSyncIO.h
@@ -79,9 +81,11 @@ INC += asynOption.h asynOptionSyncIO.h
INC += asynDrvUser.h
INC += asynStandardInterfaces.h
asyn_SRCS += asynInt32Base.c asynInt32SyncIO.c
+asyn_SRCS += asynInt64Base.c asynInt64SyncIO.c
asyn_SRCS += asynInt8ArrayBase.c asynInt8ArraySyncIO.c
asyn_SRCS += asynInt16ArrayBase.c asynInt16ArraySyncIO.c
asyn_SRCS += asynInt32ArrayBase.c asynInt32ArraySyncIO.c
+asyn_SRCS += asynInt64ArrayBase.c asynInt64ArraySyncIO.c
asyn_SRCS += asynUInt32DigitalBase.c asynUInt32DigitalSyncIO.c
asyn_SRCS += asynFloat64Base.c asynFloat64SyncIO.c
asyn_SRCS += asynFloat32ArrayBase.c asynFloat32ArraySyncIO.c
@@ -129,6 +133,7 @@ ifeq ($(EPICS_LIBCOM_ONLY),YES)
endif
INC += asynParamType.h
INC += paramErrors.h
+INC += asynParamSet.h
INC += asynPortDriver.h
asyn_SRCS += paramVal.cpp
asyn_SRCS += asynPortDriver.cpp
@@ -138,34 +143,69 @@ INC += asynPortClient.h
asyn_SRCS += asynPortClient.cpp
ifneq ($(EPICS_LIBCOM_ONLY),YES)
+ ifdef CAT
+ DBDCAT += devEpics.dbd
+ else
+ INSTALL_DBDS += $(INSTALL_DBD)/devEpics.dbd
+ endif
SRC_DIRS += $(ASYN)/devEpics
- DBD += devAsynOctet.dbd
- DBD += devAsynInt32.dbd
- DBD += devAsynInt8Array.dbd
- DBD += devAsynInt16Array.dbd
- DBD += devAsynInt32Array.dbd
- DBD += devAsynInt32TimeSeries.dbd
- DBD += devAsynUInt32Digital.dbd
- DBD += devAsynFloat64.dbd
- DBD += devAsynFloat32Array.dbd
- DBD += devAsynFloat64Array.dbd
- DBD += devAsynFloat64TimeSeries.dbd
- DBD += devEpics.dbd
+ devEpics_DBD += devAsynOctet.dbd
+ devEpics_DBD += devAsynInt32.dbd
+ devEpics_DBD += devAsynXXXArray.dbd
+ devEpics_DBD += devAsynInt32TimeSeries.dbd
+ devEpics_DBD += devAsynUInt32Digital.dbd
+ devEpics_DBD += devAsynFloat64.dbd
+ devEpics_DBD += devAsynFloat64TimeSeries.dbd
+ devEpics_DBD += devAsynRecord.dbd
DB += asynInt32TimeSeries.db
DB += asynFloat64TimeSeries.db
INC += asynEpicsUtils.h
asyn_SRCS += devAsynOctet.c
asyn_SRCS += asynEpicsUtils.c
asyn_SRCS += devAsynInt32.c
- asyn_SRCS += devAsynInt8Array.c
- asyn_SRCS += devAsynInt16Array.c
- asyn_SRCS += devAsynInt32Array.c
asyn_SRCS += devAsynInt32TimeSeries.c
asyn_SRCS += devAsynUInt32Digital.c
asyn_SRCS += devAsynFloat64.c
- asyn_SRCS += devAsynFloat32Array.c
- asyn_SRCS += devAsynFloat64Array.c
+ asyn_SRCS += devAsynXXXArray.cpp
asyn_SRCS += devAsynFloat64TimeSeries.c
+ asyn_SRCS += devEpicsPvt.c
+
+ # These require 64-bit support
+ ifdef BASE_7_0
+ HAVE_DEVINT64=YES
+ endif
+ ifdef BASE_3_16
+ ifneq ($(EPICS_MODIFICATION),0)
+ HAVE_DEVINT64=YES
+ endif
+ endif
+
+ # 3.15 and above support lsi, lso and printf records
+ ifdef BASE_3_15
+ USR_CFLAGS += -DHAVE_LSREC
+ devEpics_DBD += devAsynOctetLs.dbd
+ endif
+
+ # do we have EPICS calc module (scalcout etc.)
+ # applications should include asynCalc.dbd as well as asyn.dbd if support is needed
+ ifdef CALC
+ USR_CFLAGS += -DHAVE_CALCMOD
+ ASYN_LIBS += calc
+ DBD += asynCalc.dbd
+ endif
+
+ ifdef HAVE_DEVINT64
+ USR_CFLAGS += -DHAVE_DEVINT64
+ USR_CXXFLAGS += -DHAVE_DEVINT64
+ devEpics_DBD += devAsynInt64.dbd
+ devEpics_DBD += devAsynInt64Array.dbd
+ devEpics_DBD += devAsynInt64TimeSeries.dbd
+ asyn_SRCS += devAsynInt64TimeSeries.c
+ endif
+ devEpics_DBD += devAsynInt64Misc.dbd
+ asyn_SRCS += devAsynInt64.c
+
+ DBD += $(devEpics_DBD)
SRC_DIRS += $(ASYN)/asynRecord
DBDINC += asynRecord
@@ -187,6 +227,10 @@ asyn_SRCS += E2050Reboot.c
asyn_SRCS += TDS3000Reboot.c
DBD += drvVxi11.dbd
+SRC_DIRS += $(ASYN)/drvPrologixGPIB
+asyn_SRCS += drvPrologixGPIB.c
+DBD += drvPrologixGPIB.dbd
+
ifdef IPAC
SRC_DIRS += $(ASYN)/gsIP488
asyn_SRCS_vxWorks += drvGsIP488.c
@@ -209,6 +253,20 @@ ifeq ($(DRV_USBTMC),YES)
DBD += drvAsynUSBTMC.dbd
endif
+ifeq ($(DRV_FTDI),YES)
+ SRC_DIRS += $(ASYN)/drvAsynFTDI
+ asyn_SRCS += ftdiDriver.cpp drvAsynFTDIPort.cpp
+ asyn_SYS_LIBS += usb-1.0
+ INC += drvAsynFTDIPort.h
+ ifeq ($(DRV_FTDI_USE_LIBFTDI1),YES)
+ asyn_SYS_LIBS += ftdi1
+ USR_CXXFLAGS += -DHAVE_LIBFTDI1
+ else
+ asyn_SYS_LIBS += ftdi
+ endif
+ DBD += drvAsynFTDIPort.dbd
+endif
+
SRC_DIRS += $(ASYN)/ni1014
asyn_SRCS_vxWorks += drvNi1014.c
asyn_SRCS_RTEMS += drvNi1014.c
@@ -232,6 +290,12 @@ ifneq ($(EPICS_LIBCOM_ONLY),YES)
endif
asyn_SRCS += boSRQonOff.c
+ifeq ($(EPICS_LIBCOM_ONLY),YES)
+ asyn_LIBS += Com
+else
+ asyn_LIBS += $(EPICS_BASE_IOC_LIBS)
+endif
+
include $(TOP)/configure/RULES
# For 3.14
@@ -263,7 +327,28 @@ RPCGEN_FLAGS_solaris = -M
endif
-
# Parallel build sometimes fails.
# Make dependences on new records explicit.
asynRecord$(OBJ): $(COMMON_DIR)/asynRecord.h
+
+devEpics.dbd$(DEP): $(TOP)/asyn/Makefile
+ @$(RM) $@
+ @echo "$(COMMON_DIR)/devEpics.dbd:" > $@
+
+$(COMMON_DIR)/devEpics.dbd: $(TOP)/asyn/Makefile
+
+ifdef DBDCAT_COMMAND
+ # Override the default command when generating devEpics.dbd
+ $(COMMON_DIR)/devEpics.dbd: DBDCAT_COMMAND = \
+ $(PERL) $(TOOLS)/makeIncludeDbd.pl $(devEpics_DBD) $(notdir $@)
+else
+ # 3.14 didn't have the DBDCAT rule:
+ build: $(COMMON_DIR)/devEpics.dbd
+ $(COMMON_DIR)/devEpics.dbd: $(devEpics_DBD)
+ $(ECHO) "Creating dbd file $(notdir $@)"
+ @$(RM) $(notdir $@)
+ $(PERL) $(TOOLS)/makeIncludeDbd.pl $(devEpics_DBD) $(notdir $@)
+ @$(MV) $(notdir $@) $@
+endif
+
+USR_CPPFLAGS += -DBUILDING_asyn_API
diff --git a/asyn/asynDriver/asynAPI.h b/asyn/asynDriver/asynAPI.h
new file mode 100644
index 0000000..622bd88
--- /dev/null
+++ b/asyn/asynDriver/asynAPI.h
@@ -0,0 +1,47 @@
+#ifndef INC_asynAPI_H
+#define INC_asynAPI_H
+
+#include
+
+#ifndef VERSION_INT
+//! Construct version number constant.
+# define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
+#endif
+
+#ifndef EPICS_VERSION_INT
+# define EPICS_VERSION_INT VERSION_INT(EPICS_VERSION, EPICS_REVISION, EPICS_MODIFICATION, EPICS_PATCH_LEVEL)
+#endif
+
+#if defined(_WIN32) && EPICS_VERSION_INT= 4
+# define ASYN_API __attribute__ ((visibility("default")))
+#endif
+
+#if !defined(ASYN_API)
+# define ASYN_API
+#endif
+
+#if !defined(epicsStdCall)
+# define epicsStdCall
+#endif
+
+#endif /* INC_asynAPI_H */
+
diff --git a/asyn/asynDriver/asynDriver.h b/asyn/asynDriver/asynDriver.h
index 4d07bc2..446bad3 100644
--- a/asyn/asynDriver/asynDriver.h
+++ b/asyn/asynDriver/asynDriver.h
@@ -18,13 +18,27 @@
#include
#include
#include
-#include
+#include
+#include
/* Version number names similar to those provide by base
* These macros are always numeric */
#define ASYN_VERSION 4
-#define ASYN_REVISION 36
-#define ASYN_MODIFICATION 0
+#define ASYN_REVISION 44
+#define ASYN_MODIFICATION 2
+
+#ifndef EPICS_VERSION_INT
+#define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
+#define EPICS_VERSION_INT VERSION_INT(EPICS_VERSION, EPICS_REVISION, EPICS_MODIFICATION, EPICS_PATCH_LEVEL)
+#endif
+#define LT_EPICSBASE(V,R,M,P) (EPICS_VERSION_INT < VERSION_INT((V),(R),(M),(P)))
+
+#if LT_EPICSBASE(3,15,0,2)
+ #if __STDC_VERSION__ < 199901L
+ typedef long long epicsInt64;
+ typedef unsigned long long epicsUInt64;
+ #endif
+#endif
#ifdef __cplusplus
extern "C" {
@@ -51,14 +65,14 @@ typedef enum {
asynQueuePriorityLow,asynQueuePriorityMedium,asynQueuePriorityHigh,
asynQueuePriorityConnect
}asynQueuePriority;
-
+
typedef struct asynUser {
char *errorMessage;
int errorMessageSize;
/* timeout must be set by the user */
double timeout; /* Timeout for I/O operations*/
- void *userPvt;
- void *userData;
+ void *userPvt;
+ void *userData;
/* The following is for use by driver */
void *drvUser;
/* The following is normally set by driver via asynDrvUser->create() */
@@ -96,7 +110,7 @@ typedef struct interruptNode{
ELLNODE node;
void *drvPvt;
}interruptNode;
-
+
typedef struct asynManager {
void (*report)(FILE *fp,int details,const char*portName);
asynUser *(*createAsynUser)(userCallback process,userCallback timeout);
@@ -170,8 +184,8 @@ typedef struct asynManager {
const char *(*strStatus)(asynStatus status);
}asynManager;
-epicsShareExtern asynManager *pasynManager;
-
+ASYN_API extern asynManager *pasynManager;
+
/* Interface supported by ALL asyn drivers*/
#define asynCommonType "asynCommon"
typedef struct asynCommon {
@@ -187,7 +201,7 @@ typedef struct asynLockPortNotify {
asynStatus (*lock)(void *drvPvt,asynUser *pasynUser);
asynStatus (*unlock)(void *drvPvt,asynUser *pasynUser);
}asynLockPortNotify;
-
+
/*asynTrace is implemented by asynManager*/
/*All asynTrace methods can be called from any thread*/
/* traceMask definitions*/
@@ -211,9 +225,9 @@ typedef struct asynLockPortNotify {
#define ASYN_TRACEINFO_THREAD 0x0008
/* asynPrint and asynPrintIO are macros that act like
- int asynPrint(asynUser *pasynUser,int reason, const char *format, ... );
+ int asynPrint(asynUser *pasynUser,int reason, const char *format, ... );
int asynPrintIO(asynUser *pasynUser,int reason,
- const char *buffer, size_t len, const char *format, ... );
+ const char *buffer, size_t len, const char *format, ... );
*/
typedef struct asynTrace {
/* lock/unlock are only necessary if caller performs I/O other than */
@@ -259,7 +273,7 @@ typedef struct asynTrace {
const char *buffer, size_t len,const char *file, int line, const char *pformat, va_list pvar) EPICS_PRINTF_STYLE(7,0);
#endif
}asynTrace;
-epicsShareExtern asynTrace *pasynTrace;
+ASYN_API extern asynTrace *pasynTrace;
#if (defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L) || defined(_WIN32)
#define asynPrint(pasynUser,reason, ...) \
diff --git a/asyn/asynDriver/asynManager.c b/asyn/asynDriver/asynManager.c
index 1c8a4a0..e063a4f 100644
--- a/asyn/asynDriver/asynManager.c
+++ b/asyn/asynDriver/asynManager.c
@@ -94,7 +94,7 @@ typedef struct memNode {
* Ensure adequate alignment
*/
#define NODESIZE (((sizeof(memNode)+15)/16)*16)
-
+
typedef struct asynBase {
ELLLIST asynPortList;
ELLLIST asynUserFreeList;
@@ -158,7 +158,7 @@ typedef struct exceptionUser {
asynUser *pasynUser;
epicsEventId notify;
}exceptionUser;
-
+
typedef enum {callbackIdle,callbackActive,callbackCanceled}callbackState;
struct userPvt {
ELLNODE node; /*For asynPort.queueList*/
@@ -243,7 +243,7 @@ typedef struct queueLockPortPvt {
#define notifyNodeToExceptionUser(p) \
((exceptionUser *) ((char *)(p) \
- ( (char *)&(((exceptionUser *)0)->notifyNode) - (char *)0 ) ) )
-
+
/* internal methods */
static void tracePvtInit(tracePvt *ptracePvt);
static void tracePvtFree(tracePvt *ptracePvt);
@@ -266,7 +266,7 @@ static void portThread(port *pport);
static void initPortConnect(port *ppport);
static void portConnectTimerCallback(void *pvt);
static void portConnectProcessCallback(asynUser *pasynUser);
-
+
/* asynManager methods */
static void report(FILE *fp,int details,const char*portName);
static asynUser *createAsynUser(userCallback process, userCallback timeout);
@@ -333,7 +333,7 @@ static asynStatus updateTimeStamp(asynUser *pasynUser);
static asynStatus getTimeStamp(asynUser *pasynUser, epicsTimeStamp *pTimeStamp);
static asynStatus setTimeStamp(asynUser *pasynUser, const epicsTimeStamp *pTimeStamp);
static const char *strStatus(asynStatus status);
-
+
static asynManager manager = {
report,
createAsynUser,
@@ -386,7 +386,7 @@ static asynManager manager = {
setTimeStamp,
strStatus
};
-epicsShareDef asynManager *pasynManager = &manager;
+asynManager *pasynManager = &manager;
/* asynTrace methods */
static asynStatus traceLock(asynUser *pasynUser);
@@ -439,8 +439,8 @@ static asynTrace asynTraceManager = {
traceVprintIO,
traceVprintIOSource
};
-epicsShareDef asynTrace *pasynTrace = &asynTraceManager;
-
+asynTrace *pasynTrace = &asynTraceManager;
+
/*internal methods */
static void tracePvtInit(tracePvt *ptracePvt)
{
@@ -472,6 +472,17 @@ static void reportConnectStatus(port *pport, portConnectStatus status, const cha
}
}
+static const char *asynStripPath(const char *file)
+{
+ const char *ret = strrchr(file, '/');
+ if (ret) return ret + 1;
+#if (defined(CYGWIN32) || defined(_WIN32))
+ ret = strrchr(file, '\\');
+ if (ret) return ret + 1;
+#endif
+ return file;
+}
+
static void asynInit(void)
{
int i;
@@ -516,7 +527,7 @@ static void dpCommonFree(dpCommon *pdpCommon)
{
tracePvtFree(&pdpCommon->trace);
}
-
+
static dpCommon *findDpCommon(userPvt *puserPvt)
{
port *pport = puserPvt->pport;
@@ -533,7 +544,7 @@ static tracePvt *findTracePvt(userPvt *puserPvt)
if(pdpCommon) return(&pdpCommon->trace);
return(&pasynBase->trace);
}
-
+
/*locatePort returns 0 if portName is not registered*/
static port *locatePort(const char *portName)
{
@@ -589,7 +600,7 @@ static interfaceNode *locateInterfaceNode(
}
return pinterfaceNode;
}
-
+
/* While an exceptionActive exceptionCallbackAdd and exceptionCallbackRemove
will wait to be notified that exceptionActive is no longer true. */
static void announceExceptionOccurred(port *pport, device *pdevice, asynException exception)
@@ -627,7 +638,7 @@ static void exceptionOccurred(asynUser *pasynUser,asynException exception)
announceExceptionOccurred(pport, pdevice, exception);
}
-
+
static void queueTimeoutCallback(void *pvt)
{
userPvt *puserPvt = (userPvt *)pvt;
@@ -683,7 +694,7 @@ static void queueTimeoutCallback(void *pvt)
epicsMutexUnlock(pport->asynManagerLock);
epicsEventSignal(pport->notifyPortThread);
}
-
+
/*autoConnectDevice must be called with asynManagerLock held*/
static BOOL autoConnectDevice(port *pport,device *pdevice)
{
@@ -695,11 +706,11 @@ static BOOL autoConnectDevice(port *pport,device *pdevice)
epicsTimeGetCurrent(&now);
if(epicsTimeDiffInSeconds(
&now,&pport->dpc.lastConnectDisconnect) < 2.0) return FALSE;
- epicsTimeGetCurrent(&pport->dpc.lastConnectDisconnect);
pport->dpc.autoConnectActive = TRUE;
epicsMutexUnlock(pport->asynManagerLock);
connectAttempt(&pport->dpc);
epicsMutexMustLock(pport->asynManagerLock);
+ epicsTimeGetCurrent(&pport->dpc.lastConnectDisconnect);
pport->dpc.autoConnectActive = FALSE;
}
if(!pport->dpc.connected) return FALSE;
@@ -712,16 +723,16 @@ static BOOL autoConnectDevice(port *pport,device *pdevice)
epicsTimeGetCurrent(&now);
if(epicsTimeDiffInSeconds(
&now,&pdevice->dpc.lastConnectDisconnect) < 2.0) return FALSE;
- epicsTimeGetCurrent(&pdevice->dpc.lastConnectDisconnect);
pdevice->dpc.autoConnectActive = TRUE;
epicsMutexUnlock(pport->asynManagerLock);
connectAttempt(&pdevice->dpc);
epicsMutexMustLock(pport->asynManagerLock);
+ epicsTimeGetCurrent(&pdevice->dpc.lastConnectDisconnect);
pdevice->dpc.autoConnectActive = FALSE;
}
return pdevice->dpc.connected;
}
-
+
static void connectAttempt(dpCommon *pdpCommon)
{
port *pport = pdpCommon->pport;
@@ -775,7 +786,7 @@ static void connectAttempt(dpCommon *pdpCommon)
pport->portName,addr);
}
}
-
+
static void portThread(port *pport)
{
userPvt *puserPvt;
@@ -907,7 +918,7 @@ static void portThread(port *pport)
if(status!=asynSuccess) asynPrint(pasynUser,ASYN_TRACE_ERROR,
"%s queueCallback pasynLockPortNotify:lock error %s\n",
pport->portName,pasynUser->errorMessage);
- }
+ }
epicsMutexUnlock(pport->synchronousLock);
epicsMutexMustLock(pport->asynManagerLock);
if(puserPvt->blockPortCount>0)
@@ -935,18 +946,18 @@ static void queueLockPortCallback(asynUser *pasynUser)
queueLockPortPvt *plockPortPvt = pasynUser->userPvt;
/* Signal the epicsEvent to let the waiting thread we have been called */
- asynPrint(pasynUser, ASYN_TRACE_FLOW,
- "%s asynManager::queueLockPortCallback signaling begin event\n",
+ asynPrint(pasynUser, ASYN_TRACE_FLOW,
+ "%s asynManager::queueLockPortCallback signaling begin event\n",
pport->portName);
epicsEventSignal(plockPortPvt->queueLockPortEvent);
/* Wait for mutex from queueUnlockPort */
- asynPrint(pasynUser, ASYN_TRACE_FLOW,
- "%s asynManager::queueLockPortCallback waiting for mutex from queueUnlockPort\n",
+ asynPrint(pasynUser, ASYN_TRACE_FLOW,
+ "%s asynManager::queueLockPortCallback waiting for mutex from queueUnlockPort\n",
pport->portName);
epicsMutexMustLock(plockPortPvt->queueLockPortMutex);
epicsMutexUnlock(plockPortPvt->queueLockPortMutex);
- asynPrint(pasynUser, ASYN_TRACE_FLOW,
- "%s asynManager::queueLockPortCallback got mutex from queueUnlockPort, signaling end event\n",
+ asynPrint(pasynUser, ASYN_TRACE_FLOW,
+ "%s asynManager::queueLockPortCallback got mutex from queueUnlockPort, signaling end event\n",
pport->portName);
epicsEventSignal(plockPortPvt->queueLockPortEvent);
}
@@ -957,19 +968,19 @@ static void queueLockPortTimeoutCallback(asynUser *pasynUser)
port *pport = puserPvt->pport;
queueLockPortPvt *plockPortPvt = pasynUser->userPvt;
- asynPrint(pasynUser, ASYN_TRACE_WARNING,
- "%s asynManager::queueLockPortTimeoutCallback WARNING: queueLockPort timeout\n",
+ asynPrint(pasynUser, ASYN_TRACE_WARNING,
+ "%s asynManager::queueLockPortTimeoutCallback WARNING: queueLockPort timeout\n",
pport->portName);
/* Set the pasynUser->auxStatus to asynTimeout to signal error to caller */
pasynUser->auxStatus = asynTimeout;
/* Signal the epicsEvent to let the waiting thread we have been called */
- asynPrint(pasynUser, ASYN_TRACE_FLOW,
- "%s asynManager::queueLockPortTimeoutCallback signaling begin event\n",
+ asynPrint(pasynUser, ASYN_TRACE_FLOW,
+ "%s asynManager::queueLockPortTimeoutCallback signaling begin event\n",
pport->portName);
epicsEventSignal(plockPortPvt->queueLockPortEvent);
-
+
/* queueUnlockPort is not going to be called because queueLockPort will have returned an error */
};
@@ -998,7 +1009,7 @@ typedef struct printPortArgs {
FILE *fp;
int details;
}printPortArgs;
-
+
static void reportPrintPort(printPortArgs *pprintPortArgs)
{
epicsEventId done = pprintPortArgs->done;
@@ -1017,7 +1028,7 @@ static void reportPrintPort(printPortArgs *pprintPortArgs)
showDevices = 0;
details = -details;
}
- for(i=asynQueuePriorityLow; i<=asynQueuePriorityConnect; i++)
+ for(i=asynQueuePriorityLow; i<=asynQueuePriorityConnect; i++)
nQueued += ellCount(&pport->queueList[i]);
pdpc = &pport->dpc;
fprintf(fp,"%s multiDevice:%s canBlock:%s autoConnect:%s\n",
@@ -1148,7 +1159,7 @@ static void report(FILE *fp,int details,const char *portName)
}
epicsEventDestroy(done);
}
-
+
static asynUser *createAsynUser(userCallback process, userCallback timeout)
{
userPvt *puserPvt;
@@ -1191,7 +1202,7 @@ static asynUser *createAsynUser(userCallback process, userCallback timeout)
pasynUser->auxStatus = 0;
return pasynUser;
}
-
+
static asynUser *duplicateAsynUser(asynUser *pasynUser,
userCallback process, userCallback timeout)
{
@@ -1230,13 +1241,13 @@ static asynStatus freeAsynUser(asynUser *pasynUser)
epicsMutexUnlock(pasynBase->lock);
return asynSuccess;
}
-
+
static void *memMalloc(size_t size)
{
int ind;
ELLLIST *pmemList;
memNode *pmemNode;
-
+
if(!pasynBase) asynInit();
for(ind=0; ind0);
if(!pasynBase) asynInit();
if(size>memListSize[nMemList-1]) {
@@ -1282,7 +1293,7 @@ static void memFree(void *pmem,size_t size)
ellAdd(pmemList,&pmemNode->node);
epicsMutexUnlock(pasynBase->lock);
}
-
+
static asynStatus isMultiDevice(asynUser *pasynUser,
const char *portName,int *yesNo)
{
@@ -1323,7 +1334,7 @@ static asynStatus connectDevice(asynUser *pasynUser,
epicsMutexUnlock(pport->asynManagerLock);
return asynSuccess;
}
-
+
static asynStatus disconnect(asynUser *pasynUser)
{
userPvt *puserPvt = asynUserToUserPvt(pasynUser);
@@ -1358,7 +1369,7 @@ static asynStatus disconnect(asynUser *pasynUser)
epicsMutexUnlock(pport->asynManagerLock);
return status;
}
-
+
static asynStatus exceptionCallbackAdd(asynUser *pasynUser,
exceptionCallback callback)
{
@@ -1434,7 +1445,7 @@ static asynStatus exceptionCallbackRemove(asynUser *pasynUser)
epicsMutexUnlock(pport->asynManagerLock);
return asynSuccess;
}
-
+
static asynInterface *findInterface(asynUser *pasynUser,
const char *interfaceType,int interposeInterfaceOK)
{
@@ -1464,7 +1475,7 @@ static asynInterface *findInterface(asynUser *pasynUser,
if(pinterfaceNode) return(pinterfaceNode->pasynInterface);
return 0;
}
-
+
static asynStatus queueRequest(asynUser *pasynUser,
asynQueuePriority priority,double timeout)
{
@@ -1508,7 +1519,7 @@ static asynStatus queueRequest(asynUser *pasynUser,
device *pdevice = puserPvt->pdevice;
int addr = (pdevice ? pdevice->addr : -1);
dpCommon *pdpCommon;
-
+
pdpCommon = findDpCommon(puserPvt);
asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s queueRequest synchronous\n",
pport->portName);
@@ -1580,7 +1591,7 @@ static asynStatus queueRequest(asynUser *pasynUser,
epicsEventSignal(pport->notifyPortThread);
return asynSuccess;
}
-
+
static asynStatus cancelRequest(asynUser *pasynUser,int *wasQueued)
{
userPvt *puserPvt = asynUserToUserPvt(pasynUser);
@@ -1642,7 +1653,7 @@ static asynStatus cancelRequest(asynUser *pasynUser,int *wasQueued)
epicsEventSignal(pport->notifyPortThread);
return asynSuccess;
}
-
+
static asynStatus blockProcessCallback(asynUser *pasynUser, int allDevices)
{
userPvt *puserPvt = asynUserToUserPvt(pasynUser);
@@ -1668,14 +1679,14 @@ static asynStatus blockProcessCallback(asynUser *pasynUser, int allDevices)
epicsMutexUnlock(pport->asynManagerLock);
return asynError;
}
- if(allDevices)
+ if(allDevices)
puserPvt->blockPortCount++;
- else
+ else
puserPvt->blockDeviceCount++;
epicsMutexUnlock(pport->asynManagerLock);
return asynSuccess;
}
-
+
static asynStatus unblockProcessCallback(asynUser *pasynUser, int allDevices)
{
userPvt *puserPvt = asynUserToUserPvt(pasynUser);
@@ -1779,24 +1790,24 @@ static asynStatus queueLockPort(asynUser *pasynUser)
asynStatus status = asynSuccess;
double timeout;
- asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s asynManager::queueLockPort locking port\n", pport->portName);
if(!pport) {
epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
"asynManager::queueLockPort not connected");
return asynError;
}
+ asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s asynManager::queueLockPort locking port\n", pport->portName);
if (pport->attributes & ASYN_CANBLOCK) { /* Asynchronous driver */
plockPortPvt = epicsThreadPrivateGet(pport->queueLockPortId);
if (!plockPortPvt) {
/* This is the first time queueLockPort has been called for this thread */
plockPortPvt = callocMustSucceed(1,sizeof(queueLockPortPvt),"asynManager::queueLockPort");
- asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s asynManager::queueLockPort created queueLockPortPvt=%p\n",
+ asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s asynManager::queueLockPort created queueLockPortPvt=%p\n",
pport->portName, plockPortPvt);
plockPortPvt->queueLockPortEvent = epicsEventMustCreate(epicsEventEmpty);
plockPortPvt->queueLockPortMutex = epicsMutexMustCreate();
plockPortPvt->queueLockPortCount = 0;
epicsThreadPrivateSet(pport->queueLockPortId, plockPortPvt);
- asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s asynManager::queueLockPort created queueLockPortPvt=%p, event=%p, mutex=%p\n",
+ asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s asynManager::queueLockPort created queueLockPortPvt=%p, event=%p, mutex=%p\n",
pport->portName, plockPortPvt, plockPortPvt->queueLockPortEvent, plockPortPvt->queueLockPortMutex);
}
/* If queueLockPort has been called recursively, we already have the lock. */
@@ -1816,7 +1827,7 @@ static asynStatus queueLockPort(asynUser *pasynUser)
pasynUserCopy->auxStatus = asynSuccess;
/* Take the mutex which will block the callback port thread */
/* Wait until the queued request executes the callback */
- asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s asynManager::queueLockPort taking mutex %p\n",
+ asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s asynManager::queueLockPort taking mutex %p\n",
pport->portName, plockPortPvt->queueLockPortMutex);
epicsMutexMustLock(plockPortPvt->queueLockPortMutex);
asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s asynManager::queueLockPort queueing request\n", pport->portName);
@@ -1825,11 +1836,11 @@ static asynStatus queueLockPort(asynUser *pasynUser)
status = pasynManager->queueRequest(pasynUserCopy, asynQueuePriorityLow, timeout);
if (status) {
epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
- "asynManager::queueLockPort queueRequest failed: %s",
+ "asynManager::queueLockPort queueRequest failed: %s",
pasynUserCopy->errorMessage);
epicsMutexUnlock(plockPortPvt->queueLockPortMutex);
pasynManager->freeAsynUser(pasynUserCopy);
- return asynError;
+ return status;
}
/* Wait for event from the port thread in the queueLockPortCallback function */
asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s asynManager::queueLockPort waiting for event\n", pport->portName);
@@ -1840,7 +1851,7 @@ static asynStatus queueLockPort(asynUser *pasynUser)
"asynManager::queueLockPort queueRequest timed out");
epicsMutexUnlock(plockPortPvt->queueLockPortMutex);
pasynManager->freeAsynUser(pasynUserCopy);
- return asynError;
+ return asynTimeout;
}
pasynManager->freeAsynUser(pasynUserCopy);
asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s asynManager::queueLockPort got event from callback\n", pport->portName);
@@ -1864,12 +1875,12 @@ static asynStatus queueUnlockPort(asynUser *pasynUser)
queueLockPortPvt *plockPortPvt;
asynStatus status = asynSuccess;
- asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s queueUnlockPort\n", pport->portName);
if(!pport) {
epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
"asynManager::queueUnlockPort not connected");
return asynError;
}
+ asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s queueUnlockPort\n", pport->portName);
if(pport->pasynLockPortNotify) {
status = pport->pasynLockPortNotify->unlock(
pport->lockPortNotifyPvt,pasynUser);
@@ -1897,17 +1908,17 @@ static asynStatus queueUnlockPort(asynUser *pasynUser)
/* Wait for event from the port thread in the queueLockPortCallback function which signals it has freed mutex */
asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s asynManager::queueUnlockPort waiting for event\n", pport->portName);
epicsEventMustWait(plockPortPvt->queueLockPortEvent);
- asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s queueUnlockPort unlock mutex %p complete.\n",
+ asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s queueUnlockPort unlock mutex %p complete.\n",
pport->portName, plockPortPvt->queueLockPortMutex);
/* Remember the port is not locked any longer by this thread. */
plockPortPvt->queueLockPortCount--;
} else {
/* Synchronous driver */
epicsMutexUnlock(pport->synchronousLock);
- }
+ }
return status;
}
-
+
static asynStatus canBlock(asynUser *pasynUser,int *yesNo)
{
userPvt *puserPvt = asynUserToUserPvt(pasynUser);
@@ -1953,7 +1964,7 @@ static asynStatus getPortName(asynUser *pasynUser,const char **pportName)
*pportName = pport->portName;
return asynSuccess;
}
-
+
static asynStatus registerPort(const char *portName,
int attributes,int autoConnect,
unsigned int priority,unsigned int stackSize)
@@ -1988,7 +1999,7 @@ static asynStatus registerPort(const char *portName,
stackSize = stackSize ?
stackSize :
epicsThreadGetStackSize(epicsThreadStackMedium);
- pport->threadid = epicsThreadCreate(portName,priority,stackSize,
+ pport->threadid = epicsThreadCreate(portName,priority,stackSize,
(EPICSTHREADFUNC)portThread,pport);
if(!pport->threadid){
printf("asynCommon:registerDriver %s epicsThreadCreate failed \n",
@@ -2045,7 +2056,7 @@ static asynStatus registerInterface(const char *portName,
}
return asynSuccess;
}
-
+
static asynStatus exceptionConnect(asynUser *pasynUser)
{
userPvt *puserPvt = asynUserToUserPvt(pasynUser);
@@ -2093,9 +2104,9 @@ static asynStatus exceptionDisconnect(asynUser *pasynUser)
epicsTimeGetCurrent(&pdpCommon->lastConnectDisconnect);
exceptionOccurred(pasynUser,asynExceptionConnect);
return asynSuccess;
-
+
}
-
+
static asynStatus interposeInterface(const char *portName, int addr,
asynInterface *pasynInterface,asynInterface **ppPrev)
{
@@ -2127,7 +2138,7 @@ static asynStatus interposeInterface(const char *portName, int addr,
epicsMutexUnlock(pport->asynManagerLock);
return asynSuccess;
}
-
+
static asynStatus enable(asynUser *pasynUser,int yesNo)
{
userPvt *puserPvt = asynUserToUserPvt(pasynUser);
@@ -2201,7 +2212,7 @@ static asynStatus isAutoConnect(asynUser *pasynUser,int *yesNo)
*yesNo = pdpCommon->autoConnect;
return asynSuccess;
}
-
+
static asynStatus setAutoConnectTimeout(double timeout)
{
if(!pasynBase) asynInit();
@@ -2242,7 +2253,7 @@ static asynStatus registerInterruptSource(const char *portName,
epicsMutexMustLock(pport->asynManagerLock);
pinterfaceNode = locateInterfaceNode(
&pport->interfaceList,pasynInterface->interfaceType,FALSE);
- if(!pinterfaceNode)
+ if(!pinterfaceNode)
pinterfaceNode = locateInterfaceNode(
&pport->dpc.interposeInterfaceList,
pasynInterface->interfaceType,FALSE);
@@ -2269,7 +2280,7 @@ static asynStatus registerInterruptSource(const char *portName,
epicsMutexUnlock(pport->asynManagerLock);
return asynSuccess;
}
-
+
static asynStatus getInterruptPvt(asynUser *pasynUser,
const char *interfaceType, void **pasynPvt)
{
@@ -2285,7 +2296,7 @@ static asynStatus getInterruptPvt(asynUser *pasynUser,
epicsMutexMustLock(pport->asynManagerLock);
pinterfaceNode = locateInterfaceNode(
&pport->interfaceList,interfaceType,FALSE);
- if(!pinterfaceNode)
+ if(!pinterfaceNode)
pinterfaceNode = locateInterfaceNode(
&pport->dpc.interposeInterfaceList,interfaceType,FALSE);
if(!pinterfaceNode) {
@@ -2306,7 +2317,7 @@ static asynStatus getInterruptPvt(asynUser *pasynUser,
}
return asynSuccess;
}
-
+
static interruptNode *createInterruptNode(void *pasynPvt)
{
interruptBase *pinterruptBase = (interruptBase *)pasynPvt;
@@ -2338,7 +2349,7 @@ static asynStatus freeInterruptNode(asynUser *pasynUser,interruptNode *pinterrup
interruptNodePvt *pinterruptNodePvt = interruptNodeToPvt(pinterruptNode);
interruptBase *pinterruptBase = pinterruptNodePvt->pinterruptBase;
port *pport = pinterruptBase->pport;
-
+
epicsMutexMustLock(pport->asynManagerLock);
if(pinterruptNodePvt->isOnList) {
epicsMutexUnlock(pport->asynManagerLock);
@@ -2352,14 +2363,14 @@ static asynStatus freeInterruptNode(asynUser *pasynUser,interruptNode *pinterrup
epicsMutexUnlock(pasynBase->lock);
return asynSuccess;
}
-
+
static asynStatus addInterruptUser(asynUser *pasynUser,
interruptNode*pinterruptNode)
{
interruptNodePvt *pinterruptNodePvt = interruptNodeToPvt(pinterruptNode);
interruptBase *pinterruptBase = pinterruptNodePvt->pinterruptBase;
port *pport = pinterruptBase->pport;
-
+
epicsMutexMustLock(pport->asynManagerLock);
if(pinterruptNodePvt->isOnList) {
epicsMutexUnlock(pport->asynManagerLock);
@@ -2393,7 +2404,7 @@ static asynStatus removeInterruptUser(asynUser *pasynUser,
interruptNodePvt *pinterruptNodePvt = interruptNodeToPvt(pinterruptNode);
interruptBase *pinterruptBase = pinterruptNodePvt->pinterruptBase;
port *pport = pinterruptBase->pport;
-
+
epicsMutexMustLock(pport->asynManagerLock);
if(!pinterruptNodePvt->isOnList) {
epicsMutexUnlock(pport->asynManagerLock);
@@ -2420,7 +2431,7 @@ static asynStatus removeInterruptUser(asynUser *pasynUser,
epicsMutexUnlock(pport->asynManagerLock);
return asynSuccess;
}
-
+
static asynStatus interruptStart(void *pasynPvt,ELLLIST **plist)
{
interruptBase *pinterruptBase = (interruptBase *)pasynPvt;
@@ -2466,7 +2477,7 @@ static void defaultTimeStampSource(void *userPvt, epicsTimeStamp *pTimeStamp)
}
-static asynStatus registerTimeStampSource(asynUser *pasynUser, void *pPvt, timeStampCallback callback)
+static asynStatus registerTimeStampSource(asynUser *pasynUser, void *pPvt, timeStampCallback callback)
{
userPvt *puserPvt = asynUserToUserPvt(pasynUser);
port *pport = puserPvt->pport;
@@ -2483,7 +2494,7 @@ static asynStatus registerTimeStampSource(asynUser *pasynUser, void *pPvt, timeS
return asynSuccess;
}
-static asynStatus unregisterTimeStampSource(asynUser *pasynUser)
+static asynStatus unregisterTimeStampSource(asynUser *pasynUser)
{
userPvt *puserPvt = asynUserToUserPvt(pasynUser);
port *pport = puserPvt->pport;
@@ -2500,7 +2511,7 @@ static asynStatus unregisterTimeStampSource(asynUser *pasynUser)
return asynSuccess;
}
-static asynStatus updateTimeStamp(asynUser *pasynUser)
+static asynStatus updateTimeStamp(asynUser *pasynUser)
{
userPvt *puserPvt = asynUserToUserPvt(pasynUser);
port *pport = puserPvt->pport;
@@ -2521,7 +2532,7 @@ static asynStatus updateTimeStamp(asynUser *pasynUser)
return status;
}
-static asynStatus getTimeStamp(asynUser *pasynUser, epicsTimeStamp *pTimeStamp)
+static asynStatus getTimeStamp(asynUser *pasynUser, epicsTimeStamp *pTimeStamp)
{
userPvt *puserPvt = asynUserToUserPvt(pasynUser);
port *pport = puserPvt->pport;
@@ -2538,7 +2549,7 @@ static asynStatus getTimeStamp(asynUser *pasynUser, epicsTimeStamp *pTimeStamp)
return asynSuccess;
}
-static asynStatus setTimeStamp(asynUser *pasynUser, const epicsTimeStamp *pTimeStamp)
+static asynStatus setTimeStamp(asynUser *pasynUser, const epicsTimeStamp *pTimeStamp)
{
userPvt *puserPvt = asynUserToUserPvt(pasynUser);
port *pport = puserPvt->pport;
@@ -2556,7 +2567,7 @@ static asynStatus setTimeStamp(asynUser *pasynUser, const epicsTimeStamp *pTimeS
}
-
+
static asynStatus traceLock(asynUser *pasynUser)
{
if(!pasynBase) asynInit();
@@ -2654,7 +2665,7 @@ static int getTraceIOMask(asynUser *pasynUser)
return ptracePvt->traceIOMask;
}
-
+
static asynStatus setTraceInfoMask(asynUser *pasynUser,int mask)
{
if(!pasynBase) asynInit();
@@ -2696,7 +2707,7 @@ static int getTraceInfoMask(asynUser *pasynUser)
return ptracePvt->traceInfoMask;
}
-
+
static asynStatus setTraceFile(asynUser *pasynUser,FILE *fp)
{
userPvt *puserPvt = asynUserToUserPvt(pasynUser);
@@ -2774,15 +2785,15 @@ static size_t printThread(FILE *fp)
unsigned int threadPriority = epicsThreadGetPrioritySelf();
epicsThreadId threadId = epicsThreadGetIdSelf();
if(fp) {
- nout = fprintf(fp,"[%s,%p,%d] ",epicsThreadGetNameSelf(),
+ nout = fprintf(fp,"[%s,%p,%u] ",epicsThreadGetNameSelf(),
(void*)threadId,threadPriority);
} else {
- nout = errlogPrintf("[%s,%p,%d] ",epicsThreadGetNameSelf(),
+ nout = errlogPrintf("[%s,%p,%u] ",epicsThreadGetNameSelf(),
(void*)threadId,threadPriority);
}
return nout;
}
-
+
static size_t printTime(FILE *fp)
{
epicsTimeStamp now;
@@ -2810,11 +2821,11 @@ static size_t printPort(FILE *fp, asynUser *pasynUser)
port *pport = puserPvt->pport;
int addr;
size_t nout = 0;
-
+
if(!pport) {
return nout;
}
-
+
getAddr(pasynUser, &addr);
if(fp) {
nout = fprintf(fp,"[%s,%d,%d] ",pport->portName, addr, pasynUser->reason);
@@ -2827,6 +2838,7 @@ static size_t printPort(FILE *fp, asynUser *pasynUser)
static size_t printSource(FILE *fp, const char *file, int line)
{
int nout = 0;
+ file = asynStripPath(file);
if(fp) {
nout = fprintf(fp,"[%s:%d] ", file, line);
@@ -2870,6 +2882,7 @@ static int traceVprintSource(asynUser *pasynUser,int reason, const char *file, i
int nout = 0;
FILE *fp;
+ file = asynStripPath(file);
if(!(reason & ptracePvt->traceMask)) return 0;
epicsMutexMustLock(pasynBase->lockTrace);
fp = getTraceFile(pasynUser);
@@ -2886,7 +2899,7 @@ static int traceVprintSource(asynUser *pasynUser,int reason, const char *file, i
epicsMutexUnlock(pasynBase->lockTrace);
return nout;
}
-
+
static int tracePrintIO(asynUser *pasynUser,int reason,
const char *buffer, size_t len,const char *pformat, ...)
{
@@ -3005,16 +3018,19 @@ static int traceVprintIOSource(asynUser *pasynUser,int reason,
static const char *strStatus(asynStatus status)
{
switch (status) {
- case asynSuccess: return "asynSuccess";
- case asynTimeout: return "asynTimeout";
- case asynOverflow: return "asynOverflow";
- case asynError: return "asynError";
- default: return "asyn????";
+ case asynSuccess: return "asynSuccess";
+ case asynTimeout: return "asynTimeout";
+ case asynOverflow: return "asynOverflow";
+ case asynError: return "asynError";
+ case asynDisconnected: return "asynDisconnected";
+ case asynDisabled: return "asynDisabled";
}
+
+ return "asyn????";
}
/*
- * functions for portConnect
+ * functions for portConnect
*/
static void initPortConnect(port *pport)
{
@@ -3112,12 +3128,12 @@ static asynStatus waitConnect(asynUser *pasynUser, double timeout)
pasynUserCopy->userPvt = connectEvent;
status = pasynManager->exceptionCallbackAdd(pasynUserCopy, waitConnectExceptionHandler);
if (status) {
- asynPrint(pasynUser, ASYN_TRACE_ERROR,
+ asynPrint(pasynUser, ASYN_TRACE_ERROR,
"asynManager:waitConnect port=%s error calling exceptionCallbackAdd\n",
pport->portName);
return asynError;
}
- asynPrint(pasynUser, ASYN_TRACE_FLOW,
+ asynPrint(pasynUser, ASYN_TRACE_FLOW,
"asynManager:waitConnect port=%s waiting for connection event\n",
pport->portName);
waitStatus = epicsEventWaitWithTimeout(connectEvent, timeout);
@@ -3125,10 +3141,10 @@ static asynStatus waitConnect(asynUser *pasynUser, double timeout)
pasynManager->exceptionCallbackRemove(pasynUserCopy);
epicsEventDestroy(connectEvent);
- asynPrint(pasynUser, ASYN_TRACE_FLOW,
- "asynManager:waitConnect port=%s exit, isConnected=%d\n",
+ asynPrint(pasynUser, ASYN_TRACE_FLOW,
+ "asynManager:waitConnect port=%s exit, isConnected=%d\n",
pport->portName, isConnected);
pasynManager->freeAsynUser(pasynUserCopy);
- if (isConnected) return asynSuccess;
+ if (isConnected) return asynSuccess;
return asynError;
}
diff --git a/asyn/asynDriver/epicsInterruptibleSyscall.c b/asyn/asynDriver/epicsInterruptibleSyscall.c
index 54e86d1..56b3517 100644
--- a/asyn/asynDriver/epicsInterruptibleSyscall.c
+++ b/asyn/asynDriver/epicsInterruptibleSyscall.c
@@ -1,6 +1,6 @@
/**********************************************************************
* OSI support for interruptible system calls *
-**********************************************************************/
+**********************************************************************/
/***********************************************************************
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory, and the Regents of the University of
diff --git a/asyn/asynDriver/epicsInterruptibleSyscall.h b/asyn/asynDriver/epicsInterruptibleSyscall.h
index fd1a280..35e8cd2 100644
--- a/asyn/asynDriver/epicsInterruptibleSyscall.h
+++ b/asyn/asynDriver/epicsInterruptibleSyscall.h
@@ -18,7 +18,7 @@
* Once epicsInterruptibleSyscallWasInterrupted() returns TRUE it will
* continue to do so until epicsInterruptibleSyscallArm() has been called
* to rearm the mechanism.
- *
+ *
* Some systems close the file descriptor as a side effect of unblocking
* the slow system call. The epicsInterruptibleSyscallWasClosed() function
* is provided to detect this condition.
@@ -41,7 +41,7 @@
* close(pdev->fd);
* return -1;
* }
- *
+ *
* 4) In the device support timer handler:
* epicsInterruptibleSyscallInterrupt(pdev->intrContext);
* epicsTimerStartDelay(pdev->timer, 10.0);
@@ -49,7 +49,7 @@
* (a) the timer first times out before the read is entered and
* (b) that the read operation times out.
*/
-
+
struct epicsInterruptibleSyscallContext;
typedef struct epicsInterruptibleSyscallContext epicsInterruptibleSyscallContext;
diff --git a/asyn/asynGpib/asynGpib.c b/asyn/asynGpib/asynGpib.c
index 5a8cb4c..65baab9 100644
--- a/asyn/asynGpib/asynGpib.c
+++ b/asyn/asynGpib/asynGpib.c
@@ -38,7 +38,7 @@
#endif
#define SRQTIMEOUT .01
#define MAX_POLL 5
-
+
typedef struct gpibBase {
ELLLIST gpibPvtList;
epicsTimerQueueId timerQueue;
@@ -78,7 +78,7 @@ typedef struct gpibPvt {
char eos;
void *pasynPvt; /*For registerInterruptSource*/
}gpibPvt;
-
+
#define GETgpibPvtasynGpibPort \
gpibPvt *pgpibPvt = (gpibPvt *)drvPvt; \
asynGpibPort *pasynGpibPort; \
@@ -139,8 +139,8 @@ static asynGpib gpib = {
/*asynInt32Base implements all asynInt32 methods*/
static asynInt32 int32 = {0,0,0,0,0};
-epicsShareDef asynGpib *pasynGpib = &gpib;
-
+asynGpib *pasynGpib = &gpib;
+
/*internal methods */
static void gpibInit(void)
{
@@ -212,7 +212,7 @@ static void exceptionHandler(asynUser *pasynUser,asynException exception)
pgpibPvt->portName,pasynUser->errorMessage);
}
}
-
+
/* NOTE FOR SINGLE ADDRESS CONTROLLER
* The asynUser must specify addr = 0 or SRQs will not work.
*/
@@ -222,7 +222,7 @@ static void pollOne(asynUser *pasynUser,gpibPvt *pgpibPvt,
asynStatus status;
int statusByte = 0;
int isConnected=0, isEnabled=0, isAutoConnect = 0;
-
+
status = pasynManager->isEnabled(ppollNode->pasynUser,&isEnabled);
if(status==asynSuccess)
status = pasynManager->isConnected(ppollNode->pasynUser,&isConnected);
@@ -299,7 +299,7 @@ static void pollOne(asynUser *pasynUser,gpibPvt *pgpibPvt,
pasynManager->interruptEnd(pgpibPvt->asynInt32Pvt);
}
}
-
+
static void srqPoll(asynUser *pasynUser)
{
void *drvPvt = pasynUser->userPvt;
@@ -309,7 +309,7 @@ static void srqPoll(asynUser *pasynUser)
GETgpibPvtasynGpibPort
epicsMutexMustLock(pgpibPvt->lock);
- if(!pgpibPvt->pollRequestIsQueued)
+ if(!pgpibPvt->pollRequestIsQueued)
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s asynGpib:srqPoll but !pollRequestIsQueued. Why?\n",
pgpibPvt->portName);
@@ -354,7 +354,7 @@ static void srqPoll(asynUser *pasynUser)
pgpibPvt->portName,srqStatus,ntrys);
}
}
-
+
/*asynCommon methods */
static void report(void *drvPvt,FILE *fd,int details)
{
@@ -386,7 +386,7 @@ static asynStatus disconnect(void *drvPvt,asynUser *pasynUser)
GETgpibPvtasynGpibPort
return(pasynGpibPort->disconnect(pgpibPvt->asynGpibPortPvt,pasynUser));
}
-
+
/*asynOctet methods */
static asynStatus writeIt(void *drvPvt,asynUser *pasynUser,
const char *data,size_t numchars,size_t *nbytesTransfered)
@@ -431,13 +431,13 @@ static asynStatus gpibFlush(void *drvPvt,asynUser *pasynUser)
GETgpibPvtasynGpibPort
return(pasynGpibPort->flush(pgpibPvt->asynGpibPortPvt,pasynUser));
}
-
+
static asynStatus setInputEos(void *drvPvt,asynUser *pasynUser,
const char *eos,int eoslen)
{
asynStatus status;
GETgpibPvtasynGpibPort
-
+
if(eoslen>1) {
epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
"%s asynGpib:setInputEos eoslen %d too long. only 1 is allowed",
@@ -467,7 +467,7 @@ static asynStatus getInputEos(void *drvPvt,asynUser *pasynUser,
return asynSuccess;
}
-
+
/*asynGpib methods */
static asynStatus addressedCmd(void *drvPvt,asynUser *pasynUser,
const char *data, int length)
@@ -494,7 +494,7 @@ static asynStatus ren (void *drvPvt,asynUser *pasynUser, int onOff)
GETgpibPvtasynGpibPort
return(pasynGpibPort->ren(pgpibPvt->asynGpibPortPvt,pasynUser,onOff));
}
-
+
static asynStatus pollAddr(void *drvPvt,asynUser *pasynUser, int onOff)
{
int addr,primary,secondary;
@@ -557,7 +557,7 @@ static asynStatus pollAddr(void *drvPvt,asynUser *pasynUser, int onOff)
}
return asynSuccess;
}
-
+
/* The following are called by low level gpib drivers */
static void *registerPort(
const char *portName,
@@ -629,7 +629,7 @@ static void *registerPort(
}
return (void *)pgpibPvt;
}
-
+
static void srqHappened(void *drvPvt)
{
asynStatus status;
@@ -653,4 +653,4 @@ static void srqHappened(void *drvPvt)
"%s asynGpib:srqHappened queueRequest failed %s\n",
pgpibPvt->portName,pasynUser->errorMessage);
}
-}
+}
diff --git a/asyn/asynGpib/asynGpibDriver.h b/asyn/asynGpib/asynGpibDriver.h
index 7b95206..5559695 100644
--- a/asyn/asynGpib/asynGpibDriver.h
+++ b/asyn/asynGpib/asynGpibDriver.h
@@ -10,7 +10,6 @@
#ifndef INCasynGpibh
#define INCasynGpibh
-#include
#ifdef __cplusplus
extern "C" {
@@ -61,8 +60,8 @@ struct asynGpib{
unsigned int priority, unsigned int stackSize);
void (*srqHappened)(void *asynGpibPvt);
};
-epicsShareExtern asynGpib *pasynGpib;
-
+ASYN_API extern asynGpib *pasynGpib;
+
struct asynGpibPort {
/*asynCommon methods */
void (*report)(void *drvPvt,FILE *fd,int details);
diff --git a/asyn/asynGpib/drvSkeleton.c b/asyn/asynGpib/drvSkeleton.c
index 377a201..b7b393d 100644
--- a/asyn/asynGpib/drvSkeleton.c
+++ b/asyn/asynGpib/drvSkeleton.c
@@ -34,12 +34,12 @@ static asynStatus disconnect(void *pdrvPvt,asynUser *pasynUser);
/*asynOctet methods */
static int gpibRead(void *pdrvPvt,asynUser *pasynUser,int addr,char *data,int maxchars);
static int gpibWrite(void *pdrvPvt,asynUser *pasynUser,
- int addr,const char *data,int numchars;
+ int addr,const char *data,int numchars);
static asynStatus gpibFlush(void *pdrvPvt,asynUser *pasynUser,int addr);
static asynStatus setEos(void *pdrvPvt,asynUser *pasynUser,const char *eos,int eoslen);
/*asynGpib methods*/
static asynStatus addressedCmd (void *pdrvPvt,asynUser *pasynUser,
- int addr, char *data, int length;
+ int addr, char *data, int length);
static asynStatus universalCmd (void *pdrvPvt, asynUser *pasynUser, int cmd);
static asynStatus ifc (void *pdrvPvt,asynUser *pasynUser);
static asynStatus ren (void *pdrvPvt,asynUser *pasynUser, int onOff);
@@ -48,7 +48,7 @@ static asynStatus srqEnable (void *pdrvPvt, int onOff);
static asynStatus serialPollBegin (void *pdrvPvt);
static int serialPoll (void *pdrvPvt, int addr, double timeout);
static asynStatus serialPollEnd (void *pdrvPvt);
-
+
static void report(void *pdrvPvt,FILE *fd,int details)
{
}
@@ -67,7 +67,7 @@ static int gpibRead(void *pdrvPvt,asynUser *pasynUser,int addr,char *data,int ma
}
static int gpibWrite(void *pdrvPvt,asynUser *pasynUser,
- int addr,const char *data,int numchars
+ int addr,const char *data,int numchars)
{
}
@@ -80,7 +80,7 @@ static asynStatus setEos(void *pdrvPvt,asynUser *pasynUser,const char *eos,int e
}
static asynStatus addressedCmd (void *pdrvPvt,asynUser *pasynUser,
- int addr, char *data, int length
+ int addr, char *data, int length)
{
}
@@ -115,7 +115,7 @@ static int serialPoll (void *pdrvPvt, int addr, double timeout)
static asynStatus serialPollEnd (void *pdrvPvt)
{
}
-
+
static asynGpib skeletonDriver = {
report,
connect,
diff --git a/asyn/asynPortClient/asynPortClient.cpp b/asyn/asynPortClient/asynPortClient.cpp
index 908d4d5..cc3b932 100644
--- a/asyn/asynPortClient/asynPortClient.cpp
+++ b/asyn/asynPortClient/asynPortClient.cpp
@@ -1,6 +1,6 @@
/*
* asynPortClient.cpp
- *
+ *
* Classes for asyn clients to communicate with asyn drivers
*
* Author: Mark Rivers
@@ -14,8 +14,6 @@
#include
#include
-#define epicsExportSharedSymbols
-#include
#include "asynPortDriver.h"
#include "asynPortClient.h"
@@ -26,9 +24,9 @@
* \param[in] addr The address on the asyn port to connect to
* \param[in] asynInterfaceType The name of the asynInterface to connect to (e.g.asynInt32, asynOctet, etc.)
* \param[in] drvInfo The drvInfo string to identify which property of the port is being connected to
- * \param[in] timeout The default timeout for all communications between the client and the port driver
+ * \param[in] timeout The default timeout for all communications between the client and the port driver
*/
-asynParamClient::asynParamClient(const char *portName, int addr, const char *asynInterfaceType, const char *drvInfo,
+asynParamClient::asynParamClient(const char *portName, int addr, const char *asynInterfaceType, const char *drvInfo,
double timeout)
: pasynUser_(NULL), pasynUserSyncIO_(NULL), timeout_(timeout), portName_(epicsStrDup(portName)),
addr_(addr), asynInterfaceType_(epicsStrDup(asynInterfaceType)), drvInfo_(NULL)
@@ -59,7 +57,7 @@ asynParamClient::asynParamClient(const char *portName, int addr, const char *asy
}
/** Destructor for asynParamClient class
- * Frees all allocated resources
+ * Frees all allocated resources
*/
asynParamClient::~asynParamClient()
{
@@ -88,9 +86,9 @@ asynPortClient::asynPortClient(const char *portName, double timeout)
if (!pPort_) {
throw std::runtime_error(std::string("findAsynPortDriver cannot find port driver: ").append(portName));
}
-
+
paramMaps_ = (paramMap_t**)calloc(pPort_->maxAddr, sizeof(paramMap_t*));
-
+
for (int list=0; listmaxAddr; list++) {
int numParams;
pPort_->getNumParams(list, &numParams);
@@ -146,7 +144,7 @@ asynPortClient::asynPortClient(const char *portName, double timeout)
asynPortClient::~asynPortClient()
{
}
-
+
void asynPortClient::report(FILE *fp, int details)
{
for (int list=0; listmaxAddr; list++) {
diff --git a/asyn/asynPortClient/asynPortClient.h b/asyn/asynPortClient/asynPortClient.h
index 3c6f27c..8b3df4c 100644
--- a/asyn/asynPortClient/asynPortClient.h
+++ b/asyn/asynPortClient/asynPortClient.h
@@ -42,7 +42,7 @@
/** Base class for asyn port clients; handles most of the bookkeeping for writing an asyn port client
* with standard asyn interfaces. */
-class epicsShareClass asynParamClient {
+class ASYN_API asynParamClient {
public:
asynParamClient(const char *portName, int addr, const char* asynInterfaceType, const char *drvInfo, double timeout);
virtual ~asynParamClient();
@@ -52,7 +52,7 @@ class epicsShareClass asynParamClient {
char *getPortName() {
return portName_;
}
- char *getAsynInterfaceType()
+ char *getAsynInterfaceType()
{
return asynInterfaceType_;
}
@@ -71,56 +71,56 @@ class epicsShareClass asynParamClient {
/** Class for asyn port clients to communicate on the asynInt32 interface */
-class epicsShareClass asynInt32Client : public asynParamClient {
+class ASYN_API asynInt32Client : public asynParamClient {
public:
/** Constructor for asynInt32Client class
* \param[in] portName The name of the asyn port to connect to
* \param[in] addr The address on the asyn port to connect to
* \param[in] drvInfo The drvInfo string to identify which property of the port is being connected to
- * \param[in] timeout The default timeout for all communications between the client and the port driver
+ * \param[in] timeout The default timeout for all communications between the client and the port driver
*/
asynInt32Client(const char *portName, int addr, const char *drvInfo, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynInt32Type, drvInfo, timeout) {
pInterface_ = (asynInt32 *)pasynInterface_->pinterface;
- if (pasynInt32SyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynInt32SyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynInt32SyncIO->connect failed"));
};
asynInt32Client(const char *portName, const char *drvInfo, int addr=0, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynInt32Type, drvInfo, timeout) {
pInterface_ = (asynInt32 *)pasynInterface_->pinterface;
- if (pasynInt32SyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynInt32SyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynInt32SyncIO->connect failed"));
};
/** Destructor for asynInt32Client class. Disconnects from port, frees resources. */
- virtual ~asynInt32Client() {
+ virtual ~asynInt32Client() {
if (pInterface_ && interruptPvt_)
pInterface_->cancelInterruptUser(pasynInterface_->drvPvt, pasynUser_, interruptPvt_);
- pasynInt32SyncIO->disconnect(pasynUserSyncIO_);
- };
+ pasynInt32SyncIO->disconnect(pasynUserSyncIO_);
+ };
/** Reads an epicsInt32 value from the port driver
* \param[out] value The value read from the port driver */
- virtual asynStatus read(epicsInt32 *value) {
+ virtual asynStatus read(epicsInt32 *value) {
return pasynInt32SyncIO->read(pasynUserSyncIO_, value, timeout_);
};
/** Writes an epicsInt32 value to the port driver
* \param[in] value The value to write to the port driver */
- virtual asynStatus write(epicsInt32 value) {
- return pasynInt32SyncIO->write(pasynUserSyncIO_, value, timeout_);
+ virtual asynStatus write(epicsInt32 value) {
+ return pasynInt32SyncIO->write(pasynUserSyncIO_, value, timeout_);
};
/** Returns the lower and upper limits of the range of values from the port driver
* \param[out] low The low limit
* \param[out] high The high limit */
- virtual asynStatus getBounds(epicsInt32 *low, epicsInt32 *high) {
- return pasynInt32SyncIO->getBounds(pasynUserSyncIO_, low, high);
+ virtual asynStatus getBounds(epicsInt32 *low, epicsInt32 *high) {
+ return pasynInt32SyncIO->getBounds(pasynUserSyncIO_, low, high);
};
/** Registers an interruptCallbackInt32 function that the driver will call when there is a new value
* \param[in] pCallback The address of the callback function
* \param[in] userPvt The user-defined pointer to be passed to the callback function */
- virtual asynStatus registerInterruptUser(interruptCallbackInt32 pCallback, void *userPvt=0) {
+ virtual asynStatus registerInterruptUser(interruptCallbackInt32 pCallback, void *userPvt=0) {
if(interruptPvt_!=NULL) return asynError;
if (!userPvt) userPvt=this;
return pInterface_->registerInterruptUser(pasynInterface_->drvPvt, pasynUser_,
- pCallback, userPvt, &interruptPvt_);
+ pCallback, userPvt, &interruptPvt_);
};
private:
asynInt32 *pInterface_;
@@ -128,13 +128,13 @@ class epicsShareClass asynInt32Client : public asynParamClient {
/** Class for asyn port clients to communicate on the asynUInt32Digital interface */
-class epicsShareClass asynUInt32DigitalClient : public asynParamClient {
+class ASYN_API asynUInt32DigitalClient : public asynParamClient {
public:
/** Constructor for asynUInt32DigitalClient class
* \param[in] portName The name of the asyn port to connect to
* \param[in] addr The address on the asyn port to connect to
* \param[in] drvInfo The drvInfo string to identify which property of the port is being connected to
- * \param[in] timeout The default timeout for all communications between the client and the port driver
+ * \param[in] timeout The default timeout for all communications between the client and the port driver
*/
asynUInt32DigitalClient(const char *portName, int addr, const char *drvInfo, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynUInt32DigitalType, drvInfo, timeout) {
@@ -150,45 +150,45 @@ class epicsShareClass asynUInt32DigitalClient : public asynParamClient {
};
/** Destructor for asynInt32Client class. Disconnects from port, frees resources. */
virtual ~asynUInt32DigitalClient() {
- pasynUInt32DigitalSyncIO->disconnect(pasynUserSyncIO_);
- };
+ pasynUInt32DigitalSyncIO->disconnect(pasynUserSyncIO_);
+ };
/** Reads an epicsUInt32 value from the port driver
- * \param[out] value The value read from the port driver
+ * \param[out] value The value read from the port driver
* \param[in] mask The mask to use when reading the value */
- virtual asynStatus read(epicsUInt32 *value, epicsUInt32 mask) {
- return pasynUInt32DigitalSyncIO->read(pasynUserSyncIO_, value, mask, timeout_);
+ virtual asynStatus read(epicsUInt32 *value, epicsUInt32 mask) {
+ return pasynUInt32DigitalSyncIO->read(pasynUserSyncIO_, value, mask, timeout_);
};
/** Writes an epicsUInt32 value to the port driver
* \param[in] value The value to write to the port driver
* \param[in] mask The mask to use when writing the value */
- virtual asynStatus write(epicsUInt32 value, epicsUInt32 mask){
- return pasynUInt32DigitalSyncIO->write(pasynUserSyncIO_, value, mask, timeout_);
+ virtual asynStatus write(epicsUInt32 value, epicsUInt32 mask){
+ return pasynUInt32DigitalSyncIO->write(pasynUserSyncIO_, value, mask, timeout_);
};
/** Sets the interrupt mask for the specified interrupt reason in the driver
* \param[in] mask The interrupt mask
* \param[in] reason The interrupt reason */
- virtual asynStatus setInterrupt(epicsUInt32 mask, interruptReason reason) {
- return pasynUInt32DigitalSyncIO->setInterrupt(pasynUserSyncIO_, mask, reason, timeout_);
+ virtual asynStatus setInterrupt(epicsUInt32 mask, interruptReason reason) {
+ return pasynUInt32DigitalSyncIO->setInterrupt(pasynUserSyncIO_, mask, reason, timeout_);
};
/** Clears the interrupt mask in the driver
* \param[in] mask The interrupt mask */
- virtual asynStatus clearInterrupt(epicsUInt32 mask) {
- return pasynUInt32DigitalSyncIO->clearInterrupt(pasynUserSyncIO_, mask, timeout_);
+ virtual asynStatus clearInterrupt(epicsUInt32 mask) {
+ return pasynUInt32DigitalSyncIO->clearInterrupt(pasynUserSyncIO_, mask, timeout_);
};
/** Gets the current interrupt mask for the specified reason from the driver
* \param[out] mask The interrupt mask
* \param[in] reason The interrupt reason */
- virtual asynStatus getInterrupt(epicsUInt32 *mask, interruptReason reason) {
- return pasynUInt32DigitalSyncIO->getInterrupt(pasynUserSyncIO_, mask, reason, timeout_);
+ virtual asynStatus getInterrupt(epicsUInt32 *mask, interruptReason reason) {
+ return pasynUInt32DigitalSyncIO->getInterrupt(pasynUserSyncIO_, mask, reason, timeout_);
};
/** Registers an interruptCallbackUInt32Digital function that the driver will call when there is a new value
* \param[in] pCallback The address of the callback function
* \param[in] mask The mask to use when determining whether to do the callback
* \param[in] userPvt The user-defined pointer to be passed to the callback function */
- virtual asynStatus registerInterruptUser(interruptCallbackUInt32Digital pCallback, epicsUInt32 mask, void* userPvt=0) {
+ virtual asynStatus registerInterruptUser(interruptCallbackUInt32Digital pCallback, epicsUInt32 mask, void* userPvt=0) {
if (!userPvt) userPvt=this;
return pInterface_->registerInterruptUser(pasynInterface_->drvPvt, pasynUser_,
- pCallback, this, mask, &interruptPvt_);
+ pCallback, userPvt, mask, &interruptPvt_);
};
private:
asynUInt32Digital *pInterface_;
@@ -196,13 +196,13 @@ class epicsShareClass asynUInt32DigitalClient : public asynParamClient {
/** Class for asyn port clients to communicate on the asynFloat64 interface */
-class epicsShareClass asynFloat64Client : public asynParamClient {
+class ASYN_API asynFloat64Client : public asynParamClient {
public:
/** Constructor for asynFloat64Client class
* \param[in] portName The name of the asyn port to connect to
* \param[in] addr The address on the asyn port to connect to
* \param[in] drvInfo The drvInfo string to identify which property of the port is being connected to
- * \param[in] timeout The default timeout for all communications between the client and the port driver
+ * \param[in] timeout The default timeout for all communications between the client and the port driver
*/
asynFloat64Client(const char *portName, int addr, const char *drvInfo, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynFloat64Type, drvInfo, timeout) {
@@ -217,26 +217,26 @@ class epicsShareClass asynFloat64Client : public asynParamClient {
throw std::runtime_error(std::string("pasynFloat64SyncIO->connect failed"));
};
/** Destructor for asynFloat64Client class. Disconnects from port, frees resources. */
- virtual ~asynFloat64Client() {
- pasynFloat64SyncIO->disconnect(pasynUserSyncIO_);
- };
+ virtual ~asynFloat64Client() {
+ pasynFloat64SyncIO->disconnect(pasynUserSyncIO_);
+ };
/** Reads an epicsFloat64 value from the port driver
* \param[out] value The value read from the port driver */
virtual asynStatus read(epicsFloat64 *value) {
- return pasynFloat64SyncIO->read(pasynUserSyncIO_, value, timeout_);
+ return pasynFloat64SyncIO->read(pasynUserSyncIO_, value, timeout_);
};
/** Writes an epicsFloat64 value to the port driver
* \param[in] value The value to write to the port driver */
- virtual asynStatus write(epicsFloat64 value) {
- return pasynFloat64SyncIO->write(pasynUserSyncIO_, value, timeout_);
+ virtual asynStatus write(epicsFloat64 value) {
+ return pasynFloat64SyncIO->write(pasynUserSyncIO_, value, timeout_);
};
/** Registers an interruptCallbackFloat64 function that the driver will call when there is a new value
* \param[in] pCallback The address of the callback function
* \param[in] userPvt The user-defined pointer to be passed to the callback function */
- virtual asynStatus registerInterruptUser(interruptCallbackFloat64 pCallback, void *userPvt=0) {
+ virtual asynStatus registerInterruptUser(interruptCallbackFloat64 pCallback, void *userPvt=0) {
if (!userPvt) userPvt=this;
return pInterface_->registerInterruptUser(pasynInterface_->drvPvt, pasynUser_,
- pCallback, userPvt, &interruptPvt_);
+ pCallback, userPvt, &interruptPvt_);
};
private:
asynFloat64 *pInterface_;
@@ -244,43 +244,43 @@ class epicsShareClass asynFloat64Client : public asynParamClient {
/** Class for asyn port clients to communicate on the asynOctet interface */
-class epicsShareClass asynOctetClient : public asynParamClient {
+class ASYN_API asynOctetClient : public asynParamClient {
public:
/** Constructor for asynOctetClient class
* \param[in] portName The name of the asyn port to connect to
* \param[in] addr The address on the asyn port to connect to
* \param[in] drvInfo The drvInfo string to identify which property of the port is being connected to
- * \param[in] timeout The default timeout for all communications between the client and the port driver
+ * \param[in] timeout The default timeout for all communications between the client and the port driver
*/
asynOctetClient(const char *portName, int addr, const char *drvInfo, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynOctetType, drvInfo, timeout) {
pInterface_ = (asynOctet *)pasynInterface_->pinterface;
- if (pasynOctetSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynOctetSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynOctetSyncIO->connect failed"));
};
asynOctetClient(const char *portName, const char* drvInfo, int addr=0, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynOctetType, drvInfo, timeout) {
pInterface_ = (asynOctet *)pasynInterface_->pinterface;
- if (pasynOctetSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynOctetSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynOctetSyncIO->connect failed"));
};
/** Destructor for asynOctetClient class. Disconnects from port, frees resources. */
- virtual ~asynOctetClient() {
- pasynOctetSyncIO->disconnect(pasynUserSyncIO_);
- };
+ virtual ~asynOctetClient() {
+ pasynOctetSyncIO->disconnect(pasynUserSyncIO_);
+ };
/** Writes a char buffer to the port driver
* \param[in] buffer The characters to write to the port driver
* \param[in] bufferLen The size of the buffer
* \param[out] nActual The number of characters actually written */
- virtual asynStatus write(const char *buffer, size_t bufferLen, size_t *nActual) {
- return pasynOctetSyncIO->write(pasynUserSyncIO_, buffer, bufferLen, timeout_, nActual);
+ virtual asynStatus write(const char *buffer, size_t bufferLen, size_t *nActual) {
+ return pasynOctetSyncIO->write(pasynUserSyncIO_, buffer, bufferLen, timeout_, nActual);
};
/** Writes a char buffer to the port driver
* \param[in] buffer The characters to write to the port driver */
virtual asynStatus write(const char *buffer) {
size_t bufferLen = strlen(buffer);
- size_t nActual;
- return pasynOctetSyncIO->write(pasynUserSyncIO_, buffer, bufferLen, timeout_, &nActual);
+ size_t nActual;
+ return pasynOctetSyncIO->write(pasynUserSyncIO_, buffer, bufferLen, timeout_, &nActual);
};
/** Reads a char buffer from the port driver
* \param[out] buffer The characters read from the port driver
@@ -288,7 +288,7 @@ class epicsShareClass asynOctetClient : public asynParamClient {
* \param[out] nActual The number of characters actually read
* \param[out] eomReason The end of message reason, i.e. why the read terminated */
virtual asynStatus read(char *buffer, size_t bufferLen, size_t *nActual, int *eomReason) {
- return pasynOctetSyncIO->read(pasynUserSyncIO_, buffer, bufferLen, timeout_, nActual, eomReason);
+ return pasynOctetSyncIO->read(pasynUserSyncIO_, buffer, bufferLen, timeout_, nActual, eomReason);
};
/** Writes a char buffer to the port driver and reads the response as an atomic operation
* \param[in] writeBuffer The characters to write to the port driver
@@ -298,73 +298,73 @@ class epicsShareClass asynOctetClient : public asynParamClient {
* \param[out] nBytesOut The number of characters actually written
* \param[out] nBytesIn The number of characters actually read
* \param[out] eomReason The end of message reason, i.e. why the read terminated */
- virtual asynStatus writeRead(const char *writeBuffer, size_t writeBufferLen, char *readBuffer, size_t readBufferLen,
- size_t *nBytesOut, size_t *nBytesIn, int *eomReason) {
+ virtual asynStatus writeRead(const char *writeBuffer, size_t writeBufferLen, char *readBuffer, size_t readBufferLen,
+ size_t *nBytesOut, size_t *nBytesIn, int *eomReason) {
return pasynOctetSyncIO->writeRead(pasynUserSyncIO_, writeBuffer, writeBufferLen, readBuffer, readBufferLen,
- timeout_, nBytesOut, nBytesIn, eomReason);
+ timeout_, nBytesOut, nBytesIn, eomReason);
};
/** Flushes the input buffer in the port driver */
- virtual asynStatus flush() {
- return pasynOctetSyncIO->flush(pasynUserSyncIO_);
+ virtual asynStatus flush() {
+ return pasynOctetSyncIO->flush(pasynUserSyncIO_);
};
/** Sets the input end-of-string terminator in the driver
* \param[in] eos The input EOS string
* \param[in] eosLen The size of the EOS string */
- virtual asynStatus setInputEos(const char *eos, int eosLen) {
- return pasynOctetSyncIO->setInputEos(pasynUserSyncIO_, eos, eosLen);
+ virtual asynStatus setInputEos(const char *eos, int eosLen) {
+ return pasynOctetSyncIO->setInputEos(pasynUserSyncIO_, eos, eosLen);
};
/** Gets the input end-of-string terminator from the driver
* \param[out] eos The input EOS string
* \param[out] eosSize The maximum size of the EOS string
* \param[out] eosLen The actual size of the EOS string */
- virtual asynStatus getInputEos(char *eos, int eosSize, int *eosLen) {
- return pasynOctetSyncIO->getInputEos(pasynUserSyncIO_, eos, eosSize, eosLen);
+ virtual asynStatus getInputEos(char *eos, int eosSize, int *eosLen) {
+ return pasynOctetSyncIO->getInputEos(pasynUserSyncIO_, eos, eosSize, eosLen);
};
/** Sets the output end-of-string terminator in the driver
* \param[in] eos The output EOS string
* \param[in] eosLen The size of the EOS string */
- virtual asynStatus setOutputEos(const char *eos, int eosLen) {
- return pasynOctetSyncIO->setOutputEos(pasynUserSyncIO_, eos, eosLen);
+ virtual asynStatus setOutputEos(const char *eos, int eosLen) {
+ return pasynOctetSyncIO->setOutputEos(pasynUserSyncIO_, eos, eosLen);
};
/** Gets the output end-of-string terminator from the driver
* \param[out] eos The output EOS string
* \param[out] eosSize The maximum size of the EOS string
* \param[out] eosLen The actual size of the EOS string */
- virtual asynStatus getOutputEos(char *eos, int eosSize, int *eosLen) {
- return pasynOctetSyncIO->getOutputEos(pasynUserSyncIO_, eos, eosSize, eosLen);
+ virtual asynStatus getOutputEos(char *eos, int eosSize, int *eosLen) {
+ return pasynOctetSyncIO->getOutputEos(pasynUserSyncIO_, eos, eosSize, eosLen);
};
/** Registers an interruptCallbackOctet function that the driver will call when there is a new value
* \param[in] pCallback The address of the callback function
* \param[in] userPvt The user-defined pointer to be passed to the callback function */
- virtual asynStatus registerInterruptUser(interruptCallbackOctet pCallback, void *userPvt=0) {
+ virtual asynStatus registerInterruptUser(interruptCallbackOctet pCallback, void *userPvt=0) {
if (!userPvt) userPvt=this;
return pInterface_->registerInterruptUser(pasynInterface_->drvPvt, pasynUser_,
- pCallback, userPvt, &interruptPvt_);
+ pCallback, userPvt, &interruptPvt_);
};
private:
asynOctet *pInterface_;
};
-
+
/** Class for asyn port clients to communicate on the asynInt8Array interface */
-class epicsShareClass asynInt8ArrayClient : public asynParamClient {
+class ASYN_API asynInt8ArrayClient : public asynParamClient {
public:
/** Constructor for asynInt8Array class
* \param[in] portName The name of the asyn port to connect to
* \param[in] addr The address on the asyn port to connect to
* \param[in] drvInfo The drvInfo string to identify which property of the port is being connected to
- * \param[in] timeout The default timeout for all communications between the client and the port driver
+ * \param[in] timeout The default timeout for all communications between the client and the port driver
*/
asynInt8ArrayClient(const char *portName, int addr, const char *drvInfo, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynInt8ArrayType, drvInfo, timeout) {
pInterface_ = (asynInt8Array *)pasynInterface_->pinterface;
- if (pasynInt8ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynInt8ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynInt8ArraySyncIO->connect failed"));
};
asynInt8ArrayClient(const char *portName, const char* drvInfo, int addr=0, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynInt8ArrayType, drvInfo, timeout) {
pInterface_ = (asynInt8Array *)pasynInterface_->pinterface;
- if (pasynInt8ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynInt8ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynInt8ArraySyncIO->connect failed"));
};
/** Destructor for asynInt8Array class. Disconnects from port, frees resources. */
@@ -372,14 +372,14 @@ class epicsShareClass asynInt8ArrayClient : public asynParamClient {
pasynInt8ArraySyncIO->disconnect(pasynUserSyncIO_);
};
/** Reads an epicsInt8 array from the port driver
- * \param[out] value The array to read from the port driver
- * \param[in] nElements The number of elements in the array
+ * \param[out] value The array to read from the port driver
+ * \param[in] nElements The number of elements in the array
* \param[out] nIn The number of array elements actual read */
virtual asynStatus read(epicsInt8 *value, size_t nElements, size_t *nIn) {
return pasynInt8ArraySyncIO->read(pasynUserSyncIO_, value, nElements, nIn, timeout_);
};
/** Writes an epicsInt8 array to the port driver
- * \param[in] value The array to write to the port driver
+ * \param[in] value The array to write to the port driver
* \param[in] nElements The number of elements in the array */
virtual asynStatus write(epicsInt8 *value, size_t nElements) {
return pasynInt8ArraySyncIO->write(pasynUserSyncIO_, value, nElements, timeout_);
@@ -387,10 +387,10 @@ class epicsShareClass asynInt8ArrayClient : public asynParamClient {
/** Registers an interruptCallbackInt8Array function that the driver will call when there is a new value
* \param[in] pCallback The address of the callback function
* \param[in] userPvt The user-defined pointer to be passed to the callback function */
- virtual asynStatus registerInterruptUser(interruptCallbackInt8Array pCallback, void *userPvt=0) {
+ virtual asynStatus registerInterruptUser(interruptCallbackInt8Array pCallback, void *userPvt=0) {
if (!userPvt) userPvt=this;
return pInterface_->registerInterruptUser(pasynInterface_->drvPvt, pasynUser_,
- pCallback, userPvt, &interruptPvt_);
+ pCallback, userPvt, &interruptPvt_);
};
private:
asynInt8Array *pInterface_;
@@ -398,24 +398,24 @@ class epicsShareClass asynInt8ArrayClient : public asynParamClient {
/** Class for asyn port clients to communicate on the asynInt16Array interface */
-class epicsShareClass asynInt16ArrayClient : public asynParamClient {
+class ASYN_API asynInt16ArrayClient : public asynParamClient {
public:
/** Constructor for asynInt16Array class
* \param[in] portName The name of the asyn port to connect to
* \param[in] addr The address on the asyn port to connect to
* \param[in] drvInfo The drvInfo string to identify which property of the port is being connected to
- * \param[in] timeout The default timeout for all communications between the client and the port driver
+ * \param[in] timeout The default timeout for all communications between the client and the port driver
*/
asynInt16ArrayClient(const char *portName, int addr, const char *drvInfo, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynInt16ArrayType, drvInfo, timeout) {
pInterface_ = (asynInt16Array *)pasynInterface_->pinterface;
- if (pasynInt16ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynInt16ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynInt16ArraySyncIO->connect failed"));
};
asynInt16ArrayClient(const char *portName, const char* drvInfo, int addr=0, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynInt16ArrayType, drvInfo, timeout) {
pInterface_ = (asynInt16Array *)pasynInterface_->pinterface;
- if (pasynInt16ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynInt16ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynInt16ArraySyncIO->connect failed"));
};
/** Destructor for asynInt16Array class. Disconnects from port, frees resources. */
@@ -423,14 +423,14 @@ class epicsShareClass asynInt16ArrayClient : public asynParamClient {
pasynInt16ArraySyncIO->disconnect(pasynUserSyncIO_);
};
/** Reads an epicsInt16 array from the port driver
- * \param[out] value The array to read from the port driver
- * \param[in] nElements The number of elements in the array
+ * \param[out] value The array to read from the port driver
+ * \param[in] nElements The number of elements in the array
* \param[out] nIn The number of array elements actual read */
virtual asynStatus read(epicsInt16 *value, size_t nElements, size_t *nIn) {
return pasynInt16ArraySyncIO->read(pasynUserSyncIO_, value, nElements, nIn, timeout_);
};
/** Writes an epicsInt16 array to the port driver
- * \param[in] value The array to write to the port driver
+ * \param[in] value The array to write to the port driver
* \param[in] nElements The number of elements in the array */
virtual asynStatus write(epicsInt16 *value, size_t nElements) {
return pasynInt16ArraySyncIO->write(pasynUserSyncIO_, value, nElements, timeout_);
@@ -438,10 +438,10 @@ class epicsShareClass asynInt16ArrayClient : public asynParamClient {
/** Registers an interruptCallbackInt16Array function that the driver will call when there is a new value
* \param[in] pCallback The address of the callback function
* \param[in] userPvt The user-defined pointer to be passed to the callback function */
- virtual asynStatus registerInterruptUser(interruptCallbackInt16Array pCallback, void *userPvt=0) {
+ virtual asynStatus registerInterruptUser(interruptCallbackInt16Array pCallback, void *userPvt=0) {
if (!userPvt) userPvt=this;
return pInterface_->registerInterruptUser(pasynInterface_->drvPvt, pasynUser_,
- pCallback, userPvt, &interruptPvt_);
+ pCallback, userPvt, &interruptPvt_);
};
private:
asynInt16Array *pInterface_;
@@ -449,24 +449,24 @@ class epicsShareClass asynInt16ArrayClient : public asynParamClient {
/** Class for asyn port clients to communicate on the asynInt32Array interface */
-class epicsShareClass asynInt32ArrayClient : public asynParamClient {
+class ASYN_API asynInt32ArrayClient : public asynParamClient {
public:
/** Constructor for asynInt32Array class
* \param[in] portName The name of the asyn port to connect to
* \param[in] addr The address on the asyn port to connect to
* \param[in] drvInfo The drvInfo string to identify which property of the port is being connected to
- * \param[in] timeout The default timeout for all communications between the client and the port driver
+ * \param[in] timeout The default timeout for all communications between the client and the port driver
*/
asynInt32ArrayClient(const char *portName, int addr, const char *drvInfo, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynInt32ArrayType, drvInfo, timeout) {
pInterface_ = (asynInt32Array *)pasynInterface_->pinterface;
- if (pasynInt32ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynInt32ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynInt32ArraySyncIO->connect failed"));
};
asynInt32ArrayClient(const char *portName, const char* drvInfo, int addr=0, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynInt32ArrayType, drvInfo, timeout) {
pInterface_ = (asynInt32Array *)pasynInterface_->pinterface;
- if (pasynInt32ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynInt32ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynInt32ArraySyncIO->connect failed"));
};
/** Destructor for asynInt32Array class. Disconnects from port, frees resources. */
@@ -474,14 +474,14 @@ class epicsShareClass asynInt32ArrayClient : public asynParamClient {
pasynInt32ArraySyncIO->disconnect(pasynUserSyncIO_);
};
/** Reads an epicsInt32 array from the port driver
- * \param[out] value The array to read from the port driver
- * \param[in] nElements The number of elements in the array
+ * \param[out] value The array to read from the port driver
+ * \param[in] nElements The number of elements in the array
* \param[out] nIn The number of array elements actual read */
virtual asynStatus read(epicsInt32 *value, size_t nElements, size_t *nIn) {
return pasynInt32ArraySyncIO->read(pasynUserSyncIO_, value, nElements, nIn, timeout_);
};
/** Writes an epicsInt32 array to the port driver
- * \param[in] value The array to write to the port driver
+ * \param[in] value The array to write to the port driver
* \param[in] nElements The number of elements in the array */
virtual asynStatus write(epicsInt32 *value, size_t nElements) {
return pasynInt32ArraySyncIO->write(pasynUserSyncIO_, value, nElements, timeout_);
@@ -489,10 +489,10 @@ class epicsShareClass asynInt32ArrayClient : public asynParamClient {
/** Registers an interruptCallbackInt32Array function that the driver will call when there is a new value
* \param[in] pCallback The address of the callback function
* \param[in] userPvt The user-defined pointer to be passed to the callback function */
- virtual asynStatus registerInterruptUser(interruptCallbackInt32Array pCallback, void *userPvt=0) {
+ virtual asynStatus registerInterruptUser(interruptCallbackInt32Array pCallback, void *userPvt=0) {
if (!userPvt) userPvt=this;
return pInterface_->registerInterruptUser(pasynInterface_->drvPvt, pasynUser_,
- pCallback, userPvt, &interruptPvt_);
+ pCallback, userPvt, &interruptPvt_);
};
private:
asynInt32Array *pInterface_;
@@ -500,24 +500,24 @@ class epicsShareClass asynInt32ArrayClient : public asynParamClient {
/** Class for asyn port clients to communicate on the asynFloat32Array interface */
-class epicsShareClass asynFloat32ArrayClient : public asynParamClient {
+class ASYN_API asynFloat32ArrayClient : public asynParamClient {
public:
/** Constructor for asynFloat32Array class
* \param[in] portName The name of the asyn port to connect to
* \param[in] addr The address on the asyn port to connect to
* \param[in] drvInfo The drvInfo string to identify which property of the port is being connected to
- * \param[in] timeout The default timeout for all communications between the client and the port driver
+ * \param[in] timeout The default timeout for all communications between the client and the port driver
*/
asynFloat32ArrayClient(const char *portName, int addr, const char *drvInfo, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynFloat32ArrayType, drvInfo, timeout) {
pInterface_ = (asynFloat32Array *)pasynInterface_->pinterface;
- if (pasynFloat32ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynFloat32ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynFloat64ArraySyncIO->connect failed"));
};
asynFloat32ArrayClient(const char *portName, const char* drvInfo, int addr=0, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynFloat32ArrayType, drvInfo, timeout) {
pInterface_ = (asynFloat32Array *)pasynInterface_->pinterface;
- if (pasynFloat32ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynFloat32ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynFloat64ArraySyncIO->connect failed"));
};
/** Destructor for asynFloat32Array class. Disconnects from port, frees resources. */
@@ -525,14 +525,14 @@ class epicsShareClass asynFloat32ArrayClient : public asynParamClient {
pasynFloat32ArraySyncIO->disconnect(pasynUserSyncIO_);
};
/** Reads an epicsFloat32 array from the port driver
- * \param[out] value The array to read from the port driver
- * \param[in] nElements The number of elements in the array
+ * \param[out] value The array to read from the port driver
+ * \param[in] nElements The number of elements in the array
* \param[out] nIn The number of array elements actual read */
virtual asynStatus read(epicsFloat32 *value, size_t nElements, size_t *nIn) {
return pasynFloat32ArraySyncIO->read(pasynUserSyncIO_, value, nElements, nIn, timeout_);
};
/** Writes an epicsFloat32 array to the port driver
- * \param[in] value The array to write to the port driver
+ * \param[in] value The array to write to the port driver
* \param[in] nElements The number of elements in the array */
virtual asynStatus write(epicsFloat32 *value, size_t nElements) {
return pasynFloat32ArraySyncIO->write(pasynUserSyncIO_, value, nElements, timeout_);
@@ -540,10 +540,10 @@ class epicsShareClass asynFloat32ArrayClient : public asynParamClient {
/** Registers an interruptCallbackFloat32Array function that the driver will call when there is a new value
* \param[in] pCallback The address of the callback function
* \param[in] userPvt The user-defined pointer to be passed to the callback function */
- virtual asynStatus registerInterruptUser(interruptCallbackFloat32Array pCallback, void *userPvt=0) {
+ virtual asynStatus registerInterruptUser(interruptCallbackFloat32Array pCallback, void *userPvt=0) {
if (!userPvt) userPvt=this;
return pInterface_->registerInterruptUser(pasynInterface_->drvPvt, pasynUser_,
- pCallback, userPvt, &interruptPvt_);
+ pCallback, userPvt, &interruptPvt_);
};
private:
asynFloat32Array *pInterface_;
@@ -551,24 +551,24 @@ class epicsShareClass asynFloat32ArrayClient : public asynParamClient {
/** Class for asyn port clients to communicate on the asynFloat64Array interface */
-class epicsShareClass asynFloat64ArrayClient : public asynParamClient {
+class ASYN_API asynFloat64ArrayClient : public asynParamClient {
public:
/** Constructor for asynFloat64Array class
* \param[in] portName The name of the asyn port to connect to
* \param[in] addr The address on the asyn port to connect to
* \param[in] drvInfo The drvInfo string to identify which property of the port is being connected to
- * \param[in] timeout The default timeout for all communications between the client and the port driver
+ * \param[in] timeout The default timeout for all communications between the client and the port driver
*/
asynFloat64ArrayClient(const char *portName, int addr, const char *drvInfo, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynFloat64ArrayType, drvInfo, timeout) {
pInterface_ = (asynFloat64Array *)pasynInterface_->pinterface;
- if (pasynFloat64ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynFloat64ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynFloat64ArraySyncIO->connect failed"));
};
asynFloat64ArrayClient(const char *portName, const char* drvInfo, int addr=0, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynFloat64ArrayType, drvInfo, timeout) {
pInterface_ = (asynFloat64Array *)pasynInterface_->pinterface;
- if (pasynFloat64ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynFloat64ArraySyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynFloat64ArraySyncIO->connect failed"));
};
/** Destructor for asynFloat64Array class. Disconnects from port, frees resources. */
@@ -576,14 +576,14 @@ class epicsShareClass asynFloat64ArrayClient : public asynParamClient {
pasynFloat64ArraySyncIO->disconnect(pasynUserSyncIO_);
};
/** Reads an epicsFloat64 array from the port driver
- * \param[out] value The array to read from the port driver
- * \param[in] nElements The number of elements in the array
+ * \param[out] value The array to read from the port driver
+ * \param[in] nElements The number of elements in the array
* \param[out] nIn The number of array elements actual read */
virtual asynStatus read(epicsFloat64 *value, size_t nElements, size_t *nIn) {
return pasynFloat64ArraySyncIO->read(pasynUserSyncIO_, value, nElements, nIn, timeout_);
};
/** Writes an epicsFloat64 array to the port driver
- * \param[in] value The array to write to the port driver
+ * \param[in] value The array to write to the port driver
* \param[in] nElements The number of elements in the array */
virtual asynStatus write(epicsFloat64 *value, size_t nElements) {
return pasynFloat64ArraySyncIO->write(pasynUserSyncIO_, value, nElements, timeout_);
@@ -591,10 +591,10 @@ class epicsShareClass asynFloat64ArrayClient : public asynParamClient {
/** Registers an interruptCallbackFloat64Array function that the driver will call when there is a new value
* \param[in] pCallback The address of the callback function
* \param[in] userPvt The user-defined pointer to be passed to the callback function */
- virtual asynStatus registerInterruptUser(interruptCallbackFloat64Array pCallback, void *userPvt=0) {
+ virtual asynStatus registerInterruptUser(interruptCallbackFloat64Array pCallback, void *userPvt=0) {
if (!userPvt) userPvt=this;
return pInterface_->registerInterruptUser(pasynInterface_->drvPvt, pasynUser_,
- pCallback, userPvt, &interruptPvt_);
+ pCallback, userPvt, &interruptPvt_);
};
private:
asynFloat64Array *pInterface_;
@@ -602,24 +602,24 @@ class epicsShareClass asynFloat64ArrayClient : public asynParamClient {
/** Class for asyn port clients to communicate on the asynGenericPointer interface */
-class epicsShareClass asynGenericPointerClient : public asynParamClient {
+class ASYN_API asynGenericPointerClient : public asynParamClient {
public:
/** Constructor for asynGenericPointer class
* \param[in] portName The name of the asyn port to connect to
* \param[in] addr The address on the asyn port to connect to
* \param[in] drvInfo The drvInfo string to identify which property of the port is being connected to
- * \param[in] timeout The default timeout for all communications between the client and the port driver
+ * \param[in] timeout The default timeout for all communications between the client and the port driver
*/
asynGenericPointerClient(const char *portName, int addr, const char *drvInfo, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynGenericPointerType, drvInfo, timeout) {
pInterface_ = (asynGenericPointer *)pasynInterface_->pinterface;
- if (pasynGenericPointerSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynGenericPointerSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynGenericPointerSyncIO->connect failed"));
};
asynGenericPointerClient(const char *portName, const char* drvInfo, int addr=0, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynGenericPointerType, drvInfo, timeout) {
pInterface_ = (asynGenericPointer *)pasynInterface_->pinterface;
- if (pasynGenericPointerSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynGenericPointerSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynGenericPointerSyncIO->connect failed"));
};
/** Destructor for asynGenericPointer class. Disconnects from port, frees resources. */
@@ -639,10 +639,10 @@ class epicsShareClass asynGenericPointerClient : public asynParamClient {
/** Registers an interruptCallbackGenericPointer function that the driver will call when there is a new value
* \param[in] pCallback The address of the callback function
* \param[in] userPvt The user-defined pointer to be passed to the callback function */
- virtual asynStatus registerInterruptUser(interruptCallbackGenericPointer pCallback, void *userPvt=0) {
+ virtual asynStatus registerInterruptUser(interruptCallbackGenericPointer pCallback, void *userPvt=0) {
if (!userPvt) userPvt=this;
return pInterface_->registerInterruptUser(pasynInterface_->drvPvt, pasynUser_,
- pCallback, userPvt, &interruptPvt_);
+ pCallback, userPvt, &interruptPvt_);
};
private:
asynGenericPointer *pInterface_;
@@ -650,24 +650,24 @@ class epicsShareClass asynGenericPointerClient : public asynParamClient {
/** Class for asyn port clients to communicate on the asynOption interface */
-class epicsShareClass asynOptionClient : public asynParamClient {
+class ASYN_API asynOptionClient : public asynParamClient {
public:
/** Constructor for asynOption class
* \param[in] portName The name of the asyn port to connect to
* \param[in] addr The address on the asyn port to connect to
* \param[in] drvInfo The drvInfo string to identify which property of the port is being connected to
- * \param[in] timeout The default timeout for all communications between the client and the port driver
+ * \param[in] timeout The default timeout for all communications between the client and the port driver
*/
asynOptionClient(const char *portName, int addr, const char *drvInfo, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynOptionType, drvInfo, timeout) {
pInterface_ = (asynOption *)pasynInterface_->pinterface;
- if (pasynOptionSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynOptionSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynOptionSyncIO->connect failed"));
};
asynOptionClient(const char *portName, const char* drvInfo, int addr=0, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynOptionType, drvInfo, timeout) {
pInterface_ = (asynOption *)pasynInterface_->pinterface;
- if (pasynOptionSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynOptionSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynOptionSyncIO->connect failed"));
};
/** Destructor for asynOption class. Disconnects from port, frees resources. */
@@ -693,24 +693,24 @@ class epicsShareClass asynOptionClient : public asynParamClient {
/** Class for asyn port clients to communicate on the asynEnum interface */
-class epicsShareClass asynEnumClient : public asynParamClient {
+class ASYN_API asynEnumClient : public asynParamClient {
public:
/** Constructor for asynEnum class
* \param[in] portName The name of the asyn port to connect to
* \param[in] addr The address on the asyn port to connect to
* \param[in] drvInfo The drvInfo string to identify which property of the port is being connected to
- * \param[in] timeout The default timeout for all communications between the client and the port driver
+ * \param[in] timeout The default timeout for all communications between the client and the port driver
*/
asynEnumClient(const char *portName, int addr, const char *drvInfo, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynEnumType, drvInfo, timeout) {
pInterface_ = (asynEnum *)pasynInterface_->pinterface;
- if (pasynEnumSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynEnumSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynEnumSyncIO->connect failed"));
};
asynEnumClient(const char *portName, const char* drvInfo, int addr=0, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynEnumType, drvInfo, timeout) {
pInterface_ = (asynEnum *)pasynInterface_->pinterface;
- if (pasynEnumSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynEnumSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynEnumSyncIO->connect failed"));
};
/** Destructor for asynEnum class. Disconnects from port, frees resources. */
@@ -740,31 +740,31 @@ class epicsShareClass asynEnumClient : public asynParamClient {
/** Class for asyn port clients to communicate on the asynCommon interface */
-class epicsShareClass asynCommonClient : public asynParamClient {
+class ASYN_API asynCommonClient : public asynParamClient {
public:
/** Constructor for asynCommon class
* \param[in] portName The name of the asyn port to connect to
* \param[in] addr The address on the asyn port to connect to
* \param[in] drvInfo The drvInfo string to identify which property of the port is being connected to
- * \param[in] timeout The default timeout for all communications between the client and the port driver
+ * \param[in] timeout The default timeout for all communications between the client and the port driver
*/
asynCommonClient(const char *portName, int addr, const char *drvInfo, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynCommonType, drvInfo, timeout) {
pInterface_ = (asynCommon *)pasynInterface_->pinterface;
- if (pasynCommonSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynCommonSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynCommonSyncIO->connect failed"));
};
asynCommonClient(const char *portName, const char* drvInfo, int addr=0, double timeout=DEFAULT_TIMEOUT)
: asynParamClient(portName, addr, asynCommonType, drvInfo, timeout) {
pInterface_ = (asynCommon *)pasynInterface_->pinterface;
- if (pasynCommonSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
+ if (pasynCommonSyncIO->connect(portName, addr, &pasynUserSyncIO_, drvInfo))
throw std::runtime_error(std::string("pasynCommonSyncIO->connect failed"));
};
/** Destructor for asynCommon class. Disconnects from port, frees resources. */
virtual ~asynCommonClient() {
pasynCommonSyncIO->disconnect(pasynUserSyncIO_);
};
- /** Calls the report method in the driver
+ /** Calls the report method in the driver
* \param[in] fp The file pointer to write the report to
* \param[in] details The level of detail for the report */
virtual void report(FILE *fp, int details) {
@@ -780,11 +780,11 @@ class epicsShareClass asynCommonClient : public asynParamClient {
};
private:
asynCommon *pInterface_;
-};
+};
typedef std::map paramMap_t;
-class epicsShareClass asynPortClient {
+class ASYN_API asynPortClient {
public:
asynPortClient(const char *portName, double timeout=1.0);
virtual ~asynPortClient();
@@ -795,7 +795,7 @@ class epicsShareClass asynPortClient {
asynStatus read(std::string paramName, epicsFloat64 *value, int addr=0);
asynStatus write(std::string paramName, const char *value, int addr=0);
asynStatus read(std::string paramName, char *value, size_t bufferLen, int addr=0);
-
+
asynParamClient* getParamClient(std::string paramName, int addr=0);
private:
diff --git a/asyn/asynPortDriver/asynParamSet.h b/asyn/asynPortDriver/asynParamSet.h
new file mode 100644
index 0000000..485b7d2
--- /dev/null
+++ b/asyn/asynPortDriver/asynParamSet.h
@@ -0,0 +1,34 @@
+#ifndef AsynParamSet_H
+#define AsynParamSet_H
+
+#include
+
+#include "asynParamType.h"
+
+struct asynParam {
+ const char* name;
+ asynParamType type;
+ int* index;
+};
+
+class asynParamSet {
+public:
+ std::vector getParamDefinitions() {
+ return paramDefinitions;
+ }
+
+protected:
+ void add(const char* name, asynParamType type, int* index) {
+ asynParam param;
+ param.name = name;
+ param.type = type;
+ param.index = index;
+
+ this->paramDefinitions.push_back(param);
+ }
+
+private:
+ std::vector paramDefinitions;
+};
+
+#endif // AsynParamSet_H
diff --git a/asyn/asynPortDriver/asynParamType.h b/asyn/asynPortDriver/asynParamType.h
index c261bc6..e7debf3 100644
--- a/asyn/asynPortDriver/asynParamType.h
+++ b/asyn/asynPortDriver/asynParamType.h
@@ -12,12 +12,14 @@
typedef enum {
asynParamNotDefined, /**< Undefined */
asynParamInt32,
+ asynParamInt64,
asynParamUInt32Digital,
asynParamFloat64,
asynParamOctet,
asynParamInt8Array,
asynParamInt16Array,
asynParamInt32Array,
+ asynParamInt64Array,
asynParamFloat32Array,
asynParamFloat64Array,
asynParamGenericPointer
diff --git a/asyn/asynPortDriver/asynPortDriver.cpp b/asyn/asynPortDriver/asynPortDriver.cpp
index 5a3f36a..714e60b 100644
--- a/asyn/asynPortDriver/asynPortDriver.cpp
+++ b/asyn/asynPortDriver/asynPortDriver.cpp
@@ -1,6 +1,6 @@
/*
* asynPortDriver.cpp
- *
+ *
* Base class that implements methods for asynStandardInterfaces with a parameter library.
*
* Author: Mark Rivers
@@ -23,12 +23,10 @@
/* NOTE: interruptAccept is define in dbAccess.h if using EPICS IOC, else set it to 1 */
#ifdef EPICS_LIBCOM_ONLY
static int interruptAccept=1;
-#else
+#else
#include
#endif
-#define epicsExportSharedSymbols
-#include
#include "paramVal.h"
#include "paramErrors.h"
#include "asynParamType.h"
@@ -54,11 +52,13 @@ class paramList {
asynStatus findParam(const char *name, int *index);
asynStatus getName(int index, const char **name);
asynStatus setInteger(int index, int value);
+ asynStatus setInteger64(int index, epicsInt64 value);
asynStatus setUInt32(int index, epicsUInt32 value, epicsUInt32 valueMask, epicsUInt32 interruptMask);
asynStatus setDouble(int index, double value);
asynStatus setString(int index, const char *string);
asynStatus setString(int index, const std::string& string);
asynStatus getInteger(int index, epicsInt32 *value);
+ asynStatus getInteger64(int index, epicsInt64 *value);
asynStatus getUInt32(int index, epicsUInt32 *value, epicsUInt32 mask);
asynStatus getDouble(int index, double *value);
asynStatus getString(int index, int maxChars, char *value);
@@ -79,6 +79,7 @@ class paramList {
private:
asynStatus setFlag(int index);
asynStatus int32Callback(int command, int addr);
+ asynStatus int64Callback(int command, int addr);
asynStatus uint32Callback(int command, int addr, epicsUInt32 interruptMask);
asynStatus float64Callback(int command, int addr);
asynStatus octetCallback(int command, int addr);
@@ -128,12 +129,11 @@ asynStatus paramList::createParam(const char *name, asynParamType type, int *ind
if (this->findParam(name, index) == asynSuccess) return asynParamAlreadyExists;
- std::auto_ptr param(new paramVal(name, type));
+ paramVal *param = new paramVal(name, type);
- vals.push_back(param.get());
+ vals.push_back(param);
flags.reserve(vals.size());
- param.release();
- *index = vals.size()-1;
+ *index = (int)vals.size()-1;
return asynSuccess;
}
@@ -141,7 +141,7 @@ asynStatus paramList::createParam(const char *name, asynParamType type, int *ind
* \param[out] numParams Number of parameters */
asynStatus paramList::getNumParams(int *numParams)
{
- *numParams = this->vals.size();
+ *numParams = (int)this->vals.size();
return asynSuccess;
}
@@ -152,7 +152,7 @@ asynStatus paramList::getNumParams(int *numParams)
* \return Returns asynParamNotFound if name is not found in the parameter list. */
asynStatus paramList::findParam(const char *name, int *index)
{
- for (size_t i=0; ivals.size(); i++) {
+ for (int i=0; i<(int)this->vals.size(); i++) {
if (this->vals[i]->nameEquals(name)) {
*index = i;
return asynSuccess;
@@ -190,7 +190,27 @@ asynStatus paramList::setInteger(int index, int value)
return asynSuccess;
}
-/** Sets the value for an integer in the parameter library.
+/** Sets the value for a 64-bit integer in the parameter library.
+ * \param[in] index The parameter number
+ * \param[in] value Value to set.
+ * \return Returns asynParamBadIndex if the index is not valid or asynParamWrongType if the parametertype is not asynParamInt64. */
+asynStatus paramList::setInteger64(int index, epicsInt64 value)
+{
+ try{
+ getParameter(index)->setInteger64(value);
+ registerParameterChange(getParameter(index), index);
+ }
+ catch (ParamValWrongType&) {
+ return asynParamWrongType;
+ }
+ catch (ParamListInvalidIndex&){
+ return asynParamBadIndex;
+ }
+
+ return asynSuccess;
+}
+
+/** Sets the value for a UInt32 in the parameter library.
* \param[in] index The parameter number
* \param[in] value Value to set.
* \param[in] valueMask Mask to use when setting the value.
@@ -282,7 +302,7 @@ asynStatus paramList::getInteger(int index, epicsInt32 *value)
{
asynStatus status;
*value = 0;
-
+
try {
paramVal *pVal = getParameter(index);
*value = pVal->getInteger();
@@ -300,7 +320,34 @@ asynStatus paramList::getInteger(int index, epicsInt32 *value)
return status;
}
-/** Returns the value for an integer from the parameter library.
+/** Returns the value for a 64-bit integer from the parameter library.
+ * \param[in] index The parameter number
+ * \param[out] value Address of value to get.
+ * \return Returns asynParamBadIndex if the index is not valid, asynParamWrongType if the parameter type is not asynParamInt64,
+ * or asynParamUndefined if the value has not been defined. */
+asynStatus paramList::getInteger64(int index, epicsInt64 *value)
+{
+ asynStatus status;
+ *value = 0;
+
+ try {
+ paramVal *pVal = getParameter(index);
+ *value = pVal->getInteger64();
+ status = pVal->getStatus();
+ }
+ catch (ParamValWrongType&){
+ return asynParamWrongType;
+ }
+ catch (ParamValNotDefined&){
+ return asynParamUndefined;
+ }
+ catch (ParamListInvalidIndex&) {
+ return asynParamBadIndex;
+ }
+ return status;
+}
+
+/** Returns the value for a UInt32 from the parameter library.
* \param[in] index The parameter number
* \param[out] value Address of value to get.
* \param[in] mask The mask to use when getting the value.
@@ -310,7 +357,7 @@ asynStatus paramList::getUInt32(int index, epicsUInt32 *value, epicsUInt32 mask)
{
asynStatus status;
*value = 0;
-
+
try {
paramVal *pVal = getParameter(index);
*value = pVal->getUInt32(mask);
@@ -337,7 +384,7 @@ asynStatus paramList::getDouble(int index, double *value)
{
asynStatus status;
*value = 0.;
-
+
try {
paramVal *pVal = getParameter(index);
*value = pVal->getDouble();
@@ -496,7 +543,7 @@ asynStatus paramList::getUInt32Interrupt(int index, epicsUInt32 *mask, interrupt
asynStatus paramList::getString(int index, int maxChars, char *value)
{
asynStatus status=asynSuccess;
-
+
try {
if (maxChars > 0) {
paramVal *pVal = getParameter(index);
@@ -525,7 +572,7 @@ asynStatus paramList::getString(int index, int maxChars, char *value)
asynStatus paramList::getString(int index, std::string& value)
{
asynStatus status=asynSuccess;
-
+
try {
paramVal *pVal = getParameter(index);
status = pVal->getStatus();
@@ -598,6 +645,50 @@ asynStatus paramList::int32Callback(int command, int addr)
return asynSuccess;
}
+/** Calls the registered asyn callback functions for all clients for a 64-bit integer parameter */
+asynStatus paramList::int64Callback(int command, int addr)
+{
+ ELLLIST *pclientList;
+ interruptNode *pnode;
+ asynStandardInterfaces *pInterfaces = this->pasynPortDriver->getAsynStdInterfaces();
+ epicsTimeStamp timeStamp;
+ this->pasynPortDriver->getTimeStamp(&timeStamp);
+ int address;
+ epicsInt64 value;
+ int alarmStatus=0;
+ int alarmSeverity=0;
+ asynStatus status=asynSuccess;
+
+ /* Pass int64 interrupts */
+ status = getInteger64(command, &value);
+ getAlarmStatus(command, &alarmStatus);
+ getAlarmSeverity(command, &alarmSeverity);
+ if (!pInterfaces->int64InterruptPvt) return asynParamNotFound;
+ pasynManager->interruptStart(pInterfaces->int64InterruptPvt, &pclientList);
+ pnode = (interruptNode *)ellFirst(pclientList);
+ while (pnode) {
+ asynInt64Interrupt *pInterrupt = (asynInt64Interrupt *) pnode->drvPvt;
+ this->pasynPortDriver->getAddress(pInterrupt->pasynUser, &address);
+ /* If this is not a multi-device then address is -1, change to 0 */
+ if (address == -1) address = 0;
+ if ((command == pInterrupt->pasynUser->reason) &&
+ (address == addr)) {
+ /* Set the status for the callback */
+ pInterrupt->pasynUser->auxStatus = status;
+ pInterrupt->pasynUser->alarmStatus = alarmStatus;
+ pInterrupt->pasynUser->alarmSeverity = alarmSeverity;
+ /* Set the timestamp for the callback */
+ pInterrupt->pasynUser->timestamp = timeStamp;
+ pInterrupt->callback(pInterrupt->userPvt,
+ pInterrupt->pasynUser,
+ value);
+ }
+ pnode = (interruptNode *)ellNext(&pnode->node);
+ }
+ pasynManager->interruptEnd(pInterfaces->int64InterruptPvt);
+ return asynSuccess;
+}
+
/** Calls the registered asyn callback functions for all clients for an UInt32 parameter */
asynStatus paramList::uint32Callback(int command, int addr, epicsUInt32 interruptMask)
{
@@ -756,6 +847,9 @@ asynStatus paramList::callCallbacks(int addr)
case asynParamInt32:
status = int32Callback(index, addr);
break;
+ case asynParamInt64:
+ status = int64Callback(index, addr);
+ break;
case asynParamUInt32Digital:
status = uint32Callback(index, addr, this->vals[index]->uInt32CallbackMask);
this->vals[index]->uInt32CallbackMask = 0;
@@ -791,7 +885,7 @@ asynStatus paramList::callCallbacks()
void paramList::report(FILE *fp, int details)
{
fprintf(fp, "Number of parameters is: %u\n", (unsigned)this->vals.size() );
- for (size_t i=0; ivals.size(); i++)
+ for (int i=0; i<(int)this->vals.size(); i++)
{
this->vals[i]->report(i, fp, details);
}
@@ -810,16 +904,16 @@ paramVal* paramList::getParameter(int index)
}
callbackThread::callbackThread(asynPortDriver *portDriver) :
- thread(*this, "asynPortDriverCallback", epicsThreadGetStackSize(epicsThreadStackMedium), epicsThreadPriorityMedium),
- pPortDriver(portDriver)
+ pThread(new epicsThread(*this, "asynPortDriverCallback", epicsThreadGetStackSize(epicsThreadStackMedium), epicsThreadPriorityMedium)),
+ pPortDriver(portDriver)
{
- thread.start();
+ pThread->start();
}
callbackThread::~callbackThread()
{
shutdown.signal();
- thread.exitWait();
+ doneEvent.wait();
}
/* I thought this would be a temporary fix until EPICS supported PINI after interruptAccept, which would then be used
@@ -837,6 +931,9 @@ void callbackThread::run()
pPortDriver->callParamCallbacks(addr, addr);
}
epicsMutexUnlock(pPortDriver->mutexId);
+ delete pThread;
+ pThread = NULL;
+ doneEvent.signal();
}
@@ -876,7 +973,7 @@ asynStatus asynPortDriver::createParam(const char *name, asynParamType type, int
{
int list;
asynStatus status;
-
+
/* All parameters lists support the same parameters, so add the parameter name to all lists */
for (list=0; listmaxAddr; list++) {
status = createParam(list, name, type, index);
@@ -895,8 +992,10 @@ asynStatus asynPortDriver::createParam(int list, const char *name, asynParamType
{
asynStatus status;
static const char *functionName = "createParam";
-
- status = this->params[list]->createParam(name, type, index);
+
+ paramList *pList=getParamList(list);
+ if (!pList) return asynParamInvalidList;
+ status = pList->createParam(name, type, index);
if (status == asynParamAlreadyExists) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%s:%s: port=%s error adding parameter %s to list %d, parameter already exists.\n",
@@ -925,7 +1024,9 @@ asynStatus asynPortDriver::getNumParams(int *numParams)
* \param[out] numParams Number of parameters */
asynStatus asynPortDriver::getNumParams(int list, int *numParams)
{
- return this->params[list]->getNumParams(numParams);
+ paramList *pList=getParamList(list);
+ if (!pList) return asynParamInvalidList;
+ return pList->getNumParams(numParams);
}
/** Finds a parameter in the parameter library.
@@ -944,7 +1045,9 @@ asynStatus asynPortDriver::findParam(const char *name, int *index)
* \param[out] index Parameter number */
asynStatus asynPortDriver::findParam(int list, const char *name, int *index)
{
- return this->params[list]->findParam(name, index);
+ paramList *pList=getParamList(list);
+ if (!pList) return asynParamInvalidList;
+ return pList->findParam(name, index);
}
/** Returns the name of a parameter in the parameter library.
@@ -963,7 +1066,9 @@ asynStatus asynPortDriver::getParamName(int index, const char **name)
* \param[out] name Parameter name */
asynStatus asynPortDriver::getParamName(int list, int index, const char **name)
{
- return this->params[list]->getName(index, name);
+ paramList *pList=getParamList(list);
+ if (!pList) return asynParamInvalidList;
+ return pList->getName(index, name);
}
/** Returns the asynParamType of a parameter in the parameter library*
@@ -980,11 +1085,13 @@ asynStatus asynPortDriver::getParamType( int index, asynParamType *type
* \param[out] type Parameter type */
asynStatus asynPortDriver::getParamType(int list, int index, asynParamType *type)
{
- *type = this->params[list]->getParameter(index)->type;
- return asynSuccess;
+ paramList *pList=getParamList(list);
+ if (!pList) return asynParamInvalidList;
+ *type = pList->getParameter(index)->type;
+ return asynSuccess;
}
-/** Reports errors when setting parameters.
+/** Reports errors when setting parameters.
* \param[in] status The error status.
* \param[in] index The parameter number
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
@@ -996,16 +1103,21 @@ void asynPortDriver::reportSetParamErrors(asynStatus status, int index, int list
"%s:%s: port=%s error setting parameter %d in list %d, bad index\n",
driverName, functionName, portName, index, list);
}
- if (status == asynParamWrongType) {
+ else if (status == asynParamWrongType) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%s:%s: port=%s error setting parameter %d in list %d, wrong type\n",
driverName, functionName, portName, index, list);
}
+ else if (status == asynParamInvalidList) {
+ asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
+ "%s:%s: port=%s error setting parameter %d in list %d, invalid list\n",
+ driverName, functionName, portName, index, list);
+ }
}
/** Sets the status for a parameter in the parameter library.
* Calls setParamStatus(0, index, status) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] status Status to set. */
asynStatus asynPortDriver::setParamStatus(int index, asynStatus status)
{
@@ -1015,21 +1127,25 @@ asynStatus asynPortDriver::setParamStatus(int index, asynStatus status)
/** Sets the status for a parameter in the parameter library.
* Calls paramList::setStatus(index, status) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] paramStatus Status to set. */
asynStatus asynPortDriver::setParamStatus(int list, int index, asynStatus paramStatus)
{
asynStatus status;
static const char *functionName = "setParamStatus";
-
- status = this->params[list]->setStatus(index, paramStatus);
+
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->setStatus(index, paramStatus);
if (status) reportSetParamErrors(status, index, list, functionName);
return status;
}
/** Gets the status for a parameter in the parameter library.
* Calls getParamStatus(0, index, status) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[out] status Address of tatus to get. */
asynStatus asynPortDriver::getParamStatus(int index, asynStatus *status)
{
@@ -1039,21 +1155,25 @@ asynStatus asynPortDriver::getParamStatus(int index, asynStatus *status)
/** Gets the status for a parameter in the parameter library.
* Calls paramList::setStatus(index, status) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[out] paramStatus Address of status to get. */
asynStatus asynPortDriver::getParamStatus(int list, int index, asynStatus *paramStatus)
{
asynStatus status;
static const char *functionName = "getParamStatus";
- status = this->params[list]->getStatus(index, paramStatus);
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->getStatus(index, paramStatus);
if (status) reportSetParamErrors(status, index, list, functionName);
return status;
}
/** Sets the alarmStatus for a parameter in the parameter library.
* Calls setParamAlarmStatus(0, index, status) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] alarmStatus Status to set. */
asynStatus asynPortDriver::setParamAlarmStatus(int index, int alarmStatus)
{
@@ -1063,21 +1183,25 @@ asynStatus asynPortDriver::setParamAlarmStatus(int index, int alarmStatus)
/** Sets the alarmStatus for a parameter in the parameter library.
* Calls paramList::setAlarmStatus(index, status) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] alarmStatus Status to set. */
asynStatus asynPortDriver::setParamAlarmStatus(int list, int index, int alarmStatus)
{
asynStatus status;
static const char *functionName = "setParamAlarmStatus";
-
- status = this->params[list]->setAlarmStatus(index, alarmStatus);
+
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->setAlarmStatus(index, alarmStatus);
if (status) reportSetParamErrors(status, index, list, functionName);
return status;
}
/** Gets the alarmStatus for a parameter in the parameter library.
* Calls getParamAlarmStatus(0, index, status) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[out] alarmStatus Address of alarmStatus to get. */
asynStatus asynPortDriver::getParamAlarmStatus(int index, int *alarmStatus)
{
@@ -1087,21 +1211,25 @@ asynStatus asynPortDriver::getParamAlarmStatus(int index, int *alarmStatus)
/** Gets the alarmStatus for a parameter in the parameter library.
* Calls paramList::getAlarmStatus(index, status) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[out] alarmStatus Address of status to get. */
asynStatus asynPortDriver::getParamAlarmStatus(int list, int index, int *alarmStatus)
{
asynStatus status;
static const char *functionName = "getParamAlarmStatus";
- status = this->params[list]->getAlarmStatus(index, alarmStatus);
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->getAlarmStatus(index, alarmStatus);
if (status) reportSetParamErrors(status, index, list, functionName);
return status;
}
/** Sets the alarmSeverity for a parameter in the parameter library.
* Calls setParamAlarmSeverity(0, index, status) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] alarmSeverity Severity to set. */
asynStatus asynPortDriver::setParamAlarmSeverity(int index, int alarmSeverity)
{
@@ -1111,21 +1239,25 @@ asynStatus asynPortDriver::setParamAlarmSeverity(int index, int alarmSeverity)
/** Sets the alarmSeverity for a parameter in the parameter library.
* Calls paramList::setAlarmSeverity(index, status) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] alarmSeverity Severity to set. */
asynStatus asynPortDriver::setParamAlarmSeverity(int list, int index, int alarmSeverity)
{
asynStatus status;
static const char *functionName = "setParamAlarmSeverity";
-
- status = this->params[list]->setAlarmSeverity(index, alarmSeverity);
+
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->setAlarmSeverity(index, alarmSeverity);
if (status) reportSetParamErrors(status, index, list, functionName);
return status;
}
/** Gets the alarmSeverity for a parameter in the parameter library.
* Calls getParamAlarmSeverity(0, index, status) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[out] alarmSeverity Address of alarmSeverity to get. */
asynStatus asynPortDriver::getParamAlarmSeverity(int index, int *alarmSeverity)
{
@@ -1135,21 +1267,25 @@ asynStatus asynPortDriver::getParamAlarmSeverity(int index, int *alarmSeverity)
/** Gets the alarmSeverity for a parameter in the parameter library.
* Calls paramList::getAlarmSeverity(index, status) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[out] alarmSeverity Address of status to get. */
asynStatus asynPortDriver::getParamAlarmSeverity(int list, int index, int *alarmSeverity)
{
asynStatus status;
static const char *functionName = "getParamAlarmSeverity";
- status = this->params[list]->getAlarmSeverity(index, alarmSeverity);
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->getAlarmSeverity(index, alarmSeverity);
if (status) reportSetParamErrors(status, index, list, functionName);
return status;
}
/** Sets the value for an integer in the parameter library.
* Calls setIntegerParam(0, index, value) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] value Value to set. */
asynStatus asynPortDriver::setIntegerParam(int index, int value)
{
@@ -1159,22 +1295,54 @@ asynStatus asynPortDriver::setIntegerParam(int index, int value)
/** Sets the value for an integer in the parameter library.
* Calls paramList::setInteger (index, value) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] value Value to set. */
asynStatus asynPortDriver::setIntegerParam(int list, int index, int value)
{
asynStatus status;
static const char *functionName = "setIntegerParam";
-
- status = this->params[list]->setInteger(index, value);
+
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->setInteger(index, value);
+ if (status) reportSetParamErrors(status, index, list, functionName);
+ return status;
+}
+
+/** Sets the value for a 64-bit integer in the parameter library.
+ * Calls setInteger64Param(0, index, value) i.e. for parameter list 0.
+ * \param[in] index The parameter number
+ * \param[in] value Value to set. */
+asynStatus asynPortDriver::setInteger64Param(int index, epicsInt64 value)
+{
+ return this->setInteger64Param(0, index, value);
+}
+
+/** Sets the value for a 64-bit integer in the parameter library.
+ * Calls paramList::setInteger64 (index, value) for the parameter list indexed by list.
+ * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
+ * \param[in] index The parameter number
+ * \param[in] value Value to set. */
+asynStatus asynPortDriver::setInteger64Param(int list, int index, epicsInt64 value)
+{
+ asynStatus status;
+ static const char *functionName = "setInteger64Param";
+
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->setInteger64(index, value);
if (status) reportSetParamErrors(status, index, list, functionName);
return status;
}
/** Sets the value for a UInt32Digital in the parameter library.
* Calls setUIntDigitalParam(0, index, value, valueMask, 0) i.e. for parameter list 0.
- * \param[in] index The parameter number
- * \param[in] value Value to set.
+ * \param[in] index The parameter number
+ * \param[in] value Value to set.
* \param[in] valueMask The mask to use when setting the value. */
asynStatus asynPortDriver::setUIntDigitalParam(int index, epicsUInt32 value, epicsUInt32 valueMask)
{
@@ -1184,8 +1352,8 @@ asynStatus asynPortDriver::setUIntDigitalParam(int index, epicsUInt32 value, epi
/** Sets the value for a UInt32Digital in the parameter library.
* Calls paramList::setUIntDigitalParam(list, index, value, valueMask, 0) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
- * \param[in] value Value to set.
+ * \param[in] index The parameter number
+ * \param[in] value Value to set.
* \param[in] valueMask The mask to use when setting the value. */
asynStatus asynPortDriver::setUIntDigitalParam(int list, int index, epicsUInt32 value, epicsUInt32 valueMask)
{
@@ -1194,9 +1362,9 @@ asynStatus asynPortDriver::setUIntDigitalParam(int list, int index, epicsUInt32
/** Sets the value for a UInt32Digital in the parameter library.
* Calls setUIntDigitalParam(0, index, value, valueMask, interruptMask) i.e. for parameter list 0.
- * \param[in] index The parameter number
- * \param[in] value Value to set.
- * \param[in] valueMask The mask to use when setting the value.
+ * \param[in] index The parameter number
+ * \param[in] value Value to set.
+ * \param[in] valueMask The mask to use when setting the value.
* \param[in] interruptMask A mask that indicates which bits have changed even if the value is the same, so callbacks will be done */
asynStatus asynPortDriver::setUIntDigitalParam(int index, epicsUInt32 value, epicsUInt32 valueMask, epicsUInt32 interruptMask)
{
@@ -1204,26 +1372,30 @@ asynStatus asynPortDriver::setUIntDigitalParam(int index, epicsUInt32 value, epi
}
/** Sets the value for a UInt32Digital in the parameter library.
- * Calls paramList::setInteger (index, value) for the parameter list indexed by list.
+ * Calls paramList::setUInt32 (index, value) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
- * \param[in] value Value to set
- * \param[in] valueMask The mask to use when setting the value.
+ * \param[in] index The parameter number
+ * \param[in] value Value to set
+ * \param[in] valueMask The mask to use when setting the value.
* \param[in] interruptMask A mask that indicates which bits have changed even if the value is the same, so callbacks will be done */
asynStatus asynPortDriver::setUIntDigitalParam(int list, int index, epicsUInt32 value, epicsUInt32 valueMask, epicsUInt32 interruptMask)
{
asynStatus status;
static const char *functionName = "setUIntDigitalParam";
-
- status = this->params[list]->setUInt32(index, value, valueMask, interruptMask);
+
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->setUInt32(index, value, valueMask, interruptMask);
if (status) reportSetParamErrors(status, index, list, functionName);
return status;
}
/** Sets the interrupt mask and reason in the parameter library
* Calls paramList::setUInt32Interrupt (0, index, mask, reason) i.e. for parameter list 0.
- * \param[in] index The parameter number
- * \param[in] mask Interrupt mask.
+ * \param[in] index The parameter number
+ * \param[in] mask Interrupt mask.
* \param[in] reason Interrupt reason. */
asynStatus asynPortDriver::setUInt32DigitalInterrupt(int index, epicsUInt32 mask, interruptReason reason)
{
@@ -1233,22 +1405,26 @@ asynStatus asynPortDriver::setUInt32DigitalInterrupt(int index, epicsUInt32 mask
/** Sets the interrupt mask and reason in the parameter library
* Calls paramList::setUInt32Interrupt (index, mask, reason) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
- * \param[in] mask Interrupt mask.
+ * \param[in] index The parameter number
+ * \param[in] mask Interrupt mask.
* \param[in] reason Interrupt reason. */
asynStatus asynPortDriver::setUInt32DigitalInterrupt(int list, int index, epicsUInt32 mask, interruptReason reason)
{
asynStatus status;
static const char *functionName = "setUIntDigitalInterrupt";
-
- status = this->params[list]->setUInt32Interrupt(index, mask, reason);
+
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->setUInt32Interrupt(index, mask, reason);
if (status) reportSetParamErrors(status, index, list, functionName);
return status;
}
/** Clears the interrupt mask in the parameter library
* Calls paramList::clearUInt32Interrupt (0, index, mask) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] mask Interrupt mask. */
asynStatus asynPortDriver::clearUInt32DigitalInterrupt(int index, epicsUInt32 mask)
{
@@ -1258,22 +1434,26 @@ asynStatus asynPortDriver::clearUInt32DigitalInterrupt(int index, epicsUInt32 ma
/** Clears the interrupt mask in the parameter library
* Calls paramList::clearUInt32Interrupt (index, mask) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] mask Interrupt mask. */
asynStatus asynPortDriver::clearUInt32DigitalInterrupt(int list, int index, epicsUInt32 mask)
{
asynStatus status;
static const char *functionName = "clearUIntDigitalInterrupt";
-
- status = this->params[list]->clearUInt32Interrupt(index, mask);
+
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->clearUInt32Interrupt(index, mask);
if (status) reportSetParamErrors(status, index, list, functionName);
return status;
}
/** Gets the interrupt mask and reason in the parameter library
* Calls paramList::getUInt32Interrupt (0, index, mask, reason) i.e. for parameter list 0.
- * \param[in] index The parameter number
- * \param[in] mask Interrupt mask.
+ * \param[in] index The parameter number
+ * \param[in] mask Interrupt mask.
* \param[in] reason Interrupt reason. */
asynStatus asynPortDriver::getUInt32DigitalInterrupt(int index, epicsUInt32 *mask, interruptReason reason)
{
@@ -1283,22 +1463,26 @@ asynStatus asynPortDriver::getUInt32DigitalInterrupt(int index, epicsUInt32 *mas
/** Gets the interrupt mask and reason in the parameter library
* Calls paramList::getUInt32Interrupt (index, mask, reason) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
- * \param[in] mask Interrupt mask.
+ * \param[in] index The parameter number
+ * \param[in] mask Interrupt mask.
* \param[in] reason Interrupt reason. */
asynStatus asynPortDriver::getUInt32DigitalInterrupt(int list, int index, epicsUInt32 *mask, interruptReason reason)
{
asynStatus status;
static const char *functionName = "getUIntDigitalInterrupt";
-
- status = this->params[list]->getUInt32Interrupt(index, mask, reason);
+
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->getUInt32Interrupt(index, mask, reason);
if (status) reportSetParamErrors(status, index, list, functionName);
return status;
}
/** Sets the value for a double in the parameter library.
* Calls setDoubleParam(0, index, value) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] value Value to set. */
asynStatus asynPortDriver::setDoubleParam(int index, double value)
{
@@ -1308,21 +1492,25 @@ asynStatus asynPortDriver::setDoubleParam(int index, double value)
/** Sets the value for a double in the parameter library.
* Calls paramList::setDouble (index, value) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] value Value to set. */
asynStatus asynPortDriver::setDoubleParam(int list, int index, double value)
{
asynStatus status;
static const char *functionName = "setDoubleParam";
-
- status = this->params[list]->setDouble(index, value);
+
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->setDouble(index, value);
if (status) reportSetParamErrors(status, index, list, functionName);
return status;
}
/** Sets the value for a string in the parameter library.
* Calls setStringParam(0, index, value) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] value Address of value to set. */
asynStatus asynPortDriver::setStringParam(int index, const char *value)
{
@@ -1332,21 +1520,25 @@ asynStatus asynPortDriver::setStringParam(int index, const char *value)
/** Sets the value for a string in the parameter library.
* Calls paramList::setString (index, value) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] value Address of value to set. */
asynStatus asynPortDriver::setStringParam(int list, int index, const char *value)
{
asynStatus status;
static const char *functionName = "setStringParam";
- status = this->params[list]->setString(index, value);
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->setString(index, value);
if (status) reportSetParamErrors(status, index, list, functionName);
return status;
}
/** Sets the value for a string in the parameter library.
* Calls setStringParam(0, index, value) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] value String value to set. */
asynStatus asynPortDriver::setStringParam(int index, const std::string& value)
{
@@ -1356,19 +1548,23 @@ asynStatus asynPortDriver::setStringParam(int index, const std::string& value)
/** Sets the value for a string in the parameter library.
* Calls paramList::setString (index, value) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] value String value to set. */
asynStatus asynPortDriver::setStringParam(int list, int index, const std::string& value)
{
asynStatus status;
static const char *functionName = "setStringParam";
- status = this->params[list]->setString(index, value);
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->setString(index, value);
if (status) reportSetParamErrors(status, index, list, functionName);
return status;
}
-/** Reports errors when getting parameters.
+/** Reports errors when getting parameters.
* asynParamBadIndex and asynParamWrongType are printed with ASYN_TRACE_ERROR because they should never happen.
* asynParamUndefined is printed with ASYN_TRACE_FLOW because it is an expected error if the value is read before it
* is defined, which device support can do.
@@ -1378,7 +1574,7 @@ asynStatus asynPortDriver::setStringParam(int list, int index, const std::string
* \param[in] functionName The name of the function that generated the error */
void asynPortDriver::reportGetParamErrors(asynStatus status, int index, int list, const char *functionName)
{
- if (status == asynParamBadIndex) {
+ if (status == asynParamBadIndex) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%s:%s: port=%s error getting parameter %d in list %d, bad index\n",
driverName, functionName, portName, index, list);
@@ -1401,7 +1597,7 @@ void asynPortDriver::reportGetParamErrors(asynStatus status, int index, int list
/** Returns the value for an integer from the parameter library.
* Calls getIntegerParam(0, index, value) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[out] value Address of value to get. */
asynStatus asynPortDriver::getIntegerParam(int index, epicsInt32 *value)
{
@@ -1411,21 +1607,53 @@ asynStatus asynPortDriver::getIntegerParam(int index, epicsInt32 *value)
/** Returns the value for an integer from the parameter library.
* Calls paramList::getInteger (index, value) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[out] value Address of value to get. */
asynStatus asynPortDriver::getIntegerParam(int list, int index, epicsInt32 *value)
{
asynStatus status;
static const char *functionName = "getIntegerParam";
- status = this->params[list]->getInteger(index, value);
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->getInteger(index, value);
+ if (status) reportGetParamErrors(status, index, list, functionName);
+ return status;
+}
+
+/** Returns the value for a 64-bit integer from the parameter library.
+ * Calls getInteger64Param(0, index, value) i.e. for parameter list 0.
+ * \param[in] index The parameter number
+ * \param[out] value Address of value to get. */
+asynStatus asynPortDriver::getInteger64Param(int index, epicsInt64 *value)
+{
+ return this->getInteger64Param(0, index, value);
+}
+
+/** Returns the value for a 64-bit integer from the parameter library.
+ * Calls paramList::getInteger64 (index, value) for the parameter list indexed by list.
+ * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
+ * \param[in] index The parameter number
+ * \param[out] value Address of value to get. */
+asynStatus asynPortDriver::getInteger64Param(int list, int index, epicsInt64 *value)
+{
+ asynStatus status;
+ static const char *functionName = "getInteger64Param";
+
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->getInteger64(index, value);
if (status) reportGetParamErrors(status, index, list, functionName);
return status;
}
/** Returns the value for an UInt32Digital parameter from the parameter library.
* Calls getUIntDigitalParam(0, index, value, mask) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[out] value Address of value to get.
* \param[in] mask The mask to apply when getting the value */
asynStatus asynPortDriver::getUIntDigitalParam(int index, epicsUInt32 *value, epicsUInt32 mask)
@@ -1436,7 +1664,7 @@ asynStatus asynPortDriver::getUIntDigitalParam(int index, epicsUInt32 *value, ep
/** Returns the value for an UInt32Digital parameter from the parameter library.
* Calls paramList::getUInt32 (index, value, mask) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[out] value Address of value to get.
* \param[in] mask The mask to apply when getting the value. */
asynStatus asynPortDriver::getUIntDigitalParam(int list, int index, epicsUInt32 *value, epicsUInt32 mask)
@@ -1444,14 +1672,18 @@ asynStatus asynPortDriver::getUIntDigitalParam(int list, int index, epicsUInt32
asynStatus status;
static const char *functionName = "getUIntDigitalParam";
- status = this->params[list]->getUInt32(index, value, mask);
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->getUInt32(index, value, mask);
if (status) reportGetParamErrors(status, index, list, functionName);
return status;
}
/** Returns the value for a double from the parameter library.
* Calls getDoubleParam(0, index, value) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[out] value Address of value to get. */
asynStatus asynPortDriver::getDoubleParam(int index, double *value)
{
@@ -1461,21 +1693,25 @@ asynStatus asynPortDriver::getDoubleParam(int index, double *value)
/** Returns the value for a double from the parameter library.
* Calls paramList::getDouble (index, value) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[out] value Address of value to get. */
asynStatus asynPortDriver::getDoubleParam(int list, int index, double *value)
{
asynStatus status;
static const char *functionName = "getDoubleParam";
- status = this->params[list]->getDouble(index, value);
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->getDouble(index, value);
if (status) reportGetParamErrors(status, index, list, functionName);
return status;
}
/** Returns the value for a string from the parameter library.
* Calls getStringParam(0, index, maxChars, value) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] maxChars Maximum number of characters to return.
* \param[out] value Address of value to get. */
asynStatus asynPortDriver::getStringParam(int index, int maxChars, char *value)
@@ -1486,7 +1722,7 @@ asynStatus asynPortDriver::getStringParam(int index, int maxChars, char *value)
/** Returns the value for a string from the parameter library.
* Calls paramList::getString (index, maxChars, value) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[in] maxChars Maximum number of characters to return.
* \param[out] value Address of value to get. */
asynStatus asynPortDriver::getStringParam(int list, int index, int maxChars, char *value)
@@ -1494,14 +1730,18 @@ asynStatus asynPortDriver::getStringParam(int list, int index, int maxChars, cha
asynStatus status;
static const char *functionName = "getStringParam";
- status = this->params[list]->getString(index, maxChars, value);
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->getString(index, maxChars, value);
if (status) reportGetParamErrors(status, index, list, functionName);
return status;
}
/** Returns the value for a string from the parameter library.
* Calls getStringParam(0, index, value) i.e. for parameter list 0.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[out] value String value to get. */
asynStatus asynPortDriver::getStringParam(int index, std::string& value)
{
@@ -1511,14 +1751,18 @@ asynStatus asynPortDriver::getStringParam(int index, std::string& value)
/** Returns the value for a string from the parameter library.
* Calls paramList::getString (index, value) for the parameter list indexed by list.
* \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
- * \param[in] index The parameter number
+ * \param[in] index The parameter number
* \param[out] value String value to get. */
asynStatus asynPortDriver::getStringParam(int list, int index, std::string& value)
{
asynStatus status;
static const char *functionName = "getStringParam";
- status = this->params[list]->getString(index, value);
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->getString(index, value);
if (status) reportGetParamErrors(status, index, list, functionName);
return status;
}
@@ -1540,17 +1784,23 @@ asynStatus asynPortDriver::callParamCallbacks(int addr)
* \param[in] addr The asyn address to be used in the callback. Typically the same value as list. */
asynStatus asynPortDriver::callParamCallbacks(int list, int addr)
{
- return this->params[list]->callCallbacks(addr);
+ asynStatus status;
+ paramList *pList=getParamList(list);
+ if (!pList)
+ status = asynParamInvalidList;
+ else
+ status = pList->callCallbacks(addr);
+ return status;
}
-/** Calls paramList::report(fp, details) for each parameter list that the driver supports.
+/** Calls paramList::report(fp, details) for each parameter list that the driver supports.
* \param[in] fp The file pointer on which report information will be written
* \param[in] details The level of report detail desired; always report details on address 0; >=2 report all addresses */
void asynPortDriver::reportParams(FILE *fp, int details)
{
int i;
int numAddr = 1;
-
+
if (details >= 2) numAddr = this->maxAddr;
for (i=0; i
+template
asynStatus readArray(asynUser *pasynUser, epicsType *value, size_t nElements, size_t *nIn)
{
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s:readArray not implemented", driverName);
return asynError;
}
-template
+template
asynStatus writeArray(asynUser *pasynUser, epicsType *value, size_t nElements)
{
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s:writeArray not implemented", driverName);
return asynError;
}
-template
+template
asynStatus asynPortDriver::doCallbacksArray(epicsType *value, size_t nElements,
int reason, int address, void *interruptPvt)
{
@@ -1616,12 +1866,12 @@ asynStatus asynPortDriver::doCallbacksArray(epicsType *value, size_t nElements,
return asynSuccess;
}
-template
+template
void reportInterrupt(FILE *fp, void *interruptPvt, const char *interruptTypeString)
{
ELLLIST *pclientList;
interruptNode *pnode;
-
+
if (interruptPvt) {
pasynManager->interruptStart(interruptPvt, &pclientList);
pnode = (interruptNode *)ellFirst(pclientList);
@@ -1646,12 +1896,12 @@ void reportInterrupt(FILE *fp, void *interruptPvt, const char *interruptTypeStri
/** Returns the asyn address associated with a pasynUser structure.
* Derived classes rarely need to reimplement this function.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
- * \param[out] address Returned address.
+ * \param[out] address Returned address.
* \return Returns asynError if the address is > maxAddr value passed to asynPortDriver::asynPortDriver. */
-asynStatus asynPortDriver::getAddress(asynUser *pasynUser, int *address)
+asynStatus asynPortDriver::getAddress(asynUser *pasynUser, int *address)
{
static const char *functionName = "getAddress";
-
+
pasynManager->getAddr(pasynUser, address);
/* If this is not a multi-device then address is -1, change to 0 */
if (*address == -1) *address = 0;
@@ -1667,11 +1917,11 @@ asynStatus asynPortDriver::getAddress(asynUser *pasynUser, int *address)
/** Returns the asyn reason, address, and parameter name associated with a pasynUser structure.
* Derived classes rarely need to reimplement this function.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
- * \param[out] reason Returned reason (pasynUser->reason)
+ * \param[out] reason Returned reason (pasynUser->reason)
* \param[out] address Returned address (this->getAddress())
* \param[out] paramName Returned parameter name (this->getParamName())
* \return Returns asynError if the address is < 0 or > maxAddr value passed to asynPortDriver::asynPortDriver. */
-asynStatus asynPortDriver::parseAsynUser(asynUser *pasynUser, int *reason, int *address, const char **paramName)
+asynStatus asynPortDriver::parseAsynUser(asynUser *pasynUser, int *reason, int *address, const char **paramName)
{
//static const char *functionName = "parseAsynUser";
asynStatus status;
@@ -1683,14 +1933,19 @@ asynStatus asynPortDriver::parseAsynUser(asynUser *pasynUser, int *reason, int *
return status;
}
-
+paramList* asynPortDriver::getParamList(int list)
+{
+ if ((list < 0) || (list >= this->maxAddr)) return NULL;
+ return this->params[list];
+}
+
/* asynInt32 interface methods */
-extern "C" {static asynStatus readInt32(void *drvPvt, asynUser *pasynUser,
+extern "C" {static asynStatus readInt32(void *drvPvt, asynUser *pasynUser,
epicsInt32 *value)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->readInt32(pasynUser, value);
pPvt->unlock();
@@ -1698,7 +1953,7 @@ extern "C" {static asynStatus readInt32(void *drvPvt, asynUser *pasynUser,
}}
/** Called when asyn clients call pasynInt32->read().
- * The base class implementation simply returns the value from the parameter library.
+ * The base class implementation simply returns the value from the parameter library.
* Derived classes rarely need to reimplement this function.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[out] value Address of the value to read. */
@@ -1710,8 +1965,8 @@ asynStatus asynPortDriver::readInt32(asynUser *pasynUser, epicsInt32 *value)
asynStatus status = asynSuccess;
epicsTimeStamp timeStamp; getTimeStamp(&timeStamp);
static const char *functionName = "readInt32";
-
- status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
+
+ status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
if (status != asynSuccess) return status;
/* We just read the current value of the parameter from the parameter library.
* Those values are updated whenever anything could cause them to change */
@@ -1720,23 +1975,23 @@ asynStatus asynPortDriver::readInt32(asynUser *pasynUser, epicsInt32 *value)
pasynUser->timestamp = timeStamp;
getParamAlarmStatus(addr, function, &pasynUser->alarmStatus);
getParamAlarmSeverity(addr, function, &pasynUser->alarmSeverity);
- if (status)
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
- "%s:%s: status=%d, function=%d, name=%s, value=%d",
+ if (status)
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ "%s:%s: status=%d, function=%d, name=%s, value=%d",
driverName, functionName, status, function, paramName, *value);
- else
- asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
- "%s:%s: function=%d, name=%s, value=%d\n",
+ else
+ asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
+ "%s:%s: function=%d, name=%s, value=%d\n",
driverName, functionName, function, paramName, *value);
return status;
}
-extern "C" {static asynStatus writeInt32(void *drvPvt, asynUser *pasynUser,
+extern "C" {static asynStatus writeInt32(void *drvPvt, asynUser *pasynUser,
epicsInt32 value)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->writeInt32(pasynUser, value);
pPvt->unlock();
@@ -1744,10 +1999,10 @@ extern "C" {static asynStatus writeInt32(void *drvPvt, asynUser *pasynUser,
}}
/** Called when asyn clients call pasynInt32->write().
- * The base class implementation simply sets the value in the parameter library and
- * calls any registered callbacks for this pasynUser->reason and address.
+ * The base class implementation simply sets the value in the parameter library and
+ * calls any registered callbacks for this pasynUser->reason and address.
* Derived classes will reimplement this function if they need to perform an action when an
- * asynInt32 value is written.
+ * asynInt32 value is written.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Value to write. */
asynStatus asynPortDriver::writeInt32(asynUser *pasynUser, epicsInt32 value)
@@ -1758,7 +2013,7 @@ asynStatus asynPortDriver::writeInt32(asynUser *pasynUser, epicsInt32 value)
asynStatus status = asynSuccess;
const char* functionName = "writeInt32";
- status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
+ status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
if (status != asynSuccess) return status;
/* Set the parameter in the parameter library. */
@@ -1766,14 +2021,14 @@ asynStatus asynPortDriver::writeInt32(asynUser *pasynUser, epicsInt32 value)
/* Do callbacks so higher layers see any changes */
status = (asynStatus) callParamCallbacks(addr, addr);
-
- if (status)
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
- "%s:%s: status=%d, function=%d, name=%s, value=%d",
+
+ if (status)
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ "%s:%s: status=%d, function=%d, name=%s, value=%d",
driverName, functionName, status, function, paramName, value);
- else
- asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
- "%s:%s: function=%d, name=%s, value=%d\n",
+ else
+ asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
+ "%s:%s: function=%d, name=%s, value=%d\n",
driverName, functionName, function, paramName, value);
return status;
}
@@ -1783,7 +2038,7 @@ extern "C" {static asynStatus getBounds(void *drvPvt, asynUser *pasynUser,
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->getBounds(pasynUser, low, high);
pPvt->unlock();
@@ -1793,7 +2048,7 @@ extern "C" {static asynStatus getBounds(void *drvPvt, asynUser *pasynUser,
/** Called when asyn clients call pasynInt32->getBounds(), returning the bounds on the asynInt32 interface
* for drivers that use raw units.
* Device support uses these values for unit conversion.
- * The base class implementation simply returns low=0, high=65535.
+ * The base class implementation simply returns low=0, high=65535.
* Derived classes can reimplement this function if they support raw units with different limits.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[out] low Address of the low limit.
@@ -1806,18 +2061,145 @@ asynStatus asynPortDriver::getBounds(asynUser *pasynUser,
*low = 0;
*high = 65535;
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
- "%s::getBounds,low=%d, high=%d\n",
+ "%s::getBounds,low=%d, high=%d\n",
+ driverName, *low, *high);
+ return asynSuccess;
+}
+
+/* asynInt64 interface methods */
+extern "C" {static asynStatus readInt64(void *drvPvt, asynUser *pasynUser,
+ epicsInt64 *value)
+{
+ asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
+ asynStatus status;
+
+ pPvt->lock();
+ status = pPvt->readInt64(pasynUser, value);
+ pPvt->unlock();
+ return status;
+}}
+
+/** Called when asyn clients call pasynInt64->read().
+ * The base class implementation simply returns the value from the parameter library.
+ * Derived classes rarely need to reimplement this function.
+ * \param[in] pasynUser pasynUser structure that encodes the reason and address.
+ * \param[out] value Address of the value to read. */
+asynStatus asynPortDriver::readInt64(asynUser *pasynUser, epicsInt64 *value)
+{
+ int function;
+ const char *paramName;
+ int addr;
+ asynStatus status = asynSuccess;
+ epicsTimeStamp timeStamp; getTimeStamp(&timeStamp);
+ static const char *functionName = "readInt64";
+
+ status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
+ if (status != asynSuccess) return status;
+ /* We just read the current value of the parameter from the parameter library.
+ * Those values are updated whenever anything could cause them to change */
+ status = (asynStatus) getInteger64Param(addr, function, value);
+ /* Set the timestamp */
+ pasynUser->timestamp = timeStamp;
+ getParamAlarmStatus(addr, function, &pasynUser->alarmStatus);
+ getParamAlarmSeverity(addr, function, &pasynUser->alarmSeverity);
+ if (status)
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ "%s:%s: status=%d, function=%d, name=%s, value=%lld",
+ driverName, functionName, status, function, paramName, *value);
+ else
+ asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
+ "%s:%s: function=%d, name=%s, value=%lld\n",
+ driverName, functionName, function, paramName, *value);
+ return status;
+}
+
+extern "C" {static asynStatus writeInt64(void *drvPvt, asynUser *pasynUser,
+ epicsInt64 value)
+{
+ asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
+ asynStatus status;
+
+ pPvt->lock();
+ status = pPvt->writeInt64(pasynUser, value);
+ pPvt->unlock();
+ return status;
+}}
+
+/** Called when asyn clients call pasynInt64->write().
+ * The base class implementation simply sets the value in the parameter library and
+ * calls any registered callbacks for this pasynUser->reason and address.
+ * Derived classes will reimplement this function if they need to perform an action when an
+ * asynInt64 value is written.
+ * \param[in] pasynUser pasynUser structure that encodes the reason and address.
+ * \param[in] value Value to write. */
+asynStatus asynPortDriver::writeInt64(asynUser *pasynUser, epicsInt64 value)
+{
+ int function ;
+ const char *paramName;
+ int addr;
+ asynStatus status = asynSuccess;
+ const char* functionName = "writeInt64";
+
+ status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
+ if (status != asynSuccess) return status;
+
+ /* Set the parameter in the parameter library. */
+ status = (asynStatus) setInteger64Param(addr, function, value);
+
+ /* Do callbacks so higher layers see any changes */
+ status = (asynStatus) callParamCallbacks(addr, addr);
+
+ if (status)
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ "%s:%s: status=%d, function=%d, name=%s, value=%lld",
+ driverName, functionName, status, function, paramName, value);
+ else
+ asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
+ "%s:%s: function=%d, name=%s, value=%lld\n",
+ driverName, functionName, function, paramName, value);
+ return status;
+}
+
+extern "C" {static asynStatus getBounds64(void *drvPvt, asynUser *pasynUser,
+ epicsInt64 *low, epicsInt64 *high)
+{
+ asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
+ asynStatus status;
+
+ pPvt->lock();
+ status = pPvt->getBounds64(pasynUser, low, high);
+ pPvt->unlock();
+ return status;
+}}
+
+/** Called when asyn clients call pasynInt64->getBounds(), returning the bounds on the asynInt64 interface
+ * for drivers that use raw units.
+ * Device support uses these values for unit conversion.
+ * The base class implementation simply returns low=0, high=65535.
+ * Derived classes can reimplement this function if they support raw units with different limits.
+ * \param[in] pasynUser pasynUser structure that encodes the reason and address.
+ * \param[out] low Address of the low limit.
+ * \param[out] high Address of the high limit. */
+asynStatus asynPortDriver::getBounds64(asynUser *pasynUser,
+ epicsInt64 *low, epicsInt64 *high)
+{
+ /* This is only needed for the asynInt64 interface when the device uses raw units.
+ Our interface is using engineering units. */
+ *low = 0;
+ *high = 65535;
+ asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
+ "%s::getBounds64,low=%lld, high=%lld\n",
driverName, *low, *high);
return asynSuccess;
}
/* asynUInt32Digital interface methods */
-extern "C" {static asynStatus readUInt32Digital(void *drvPvt, asynUser *pasynUser,
+extern "C" {static asynStatus readUInt32Digital(void *drvPvt, asynUser *pasynUser,
epicsUInt32 *value, epicsUInt32 mask)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->readUInt32Digital(pasynUser, value, mask);
pPvt->unlock();
@@ -1825,7 +2207,7 @@ extern "C" {static asynStatus readUInt32Digital(void *drvPvt, asynUser *pasynUse
}}
/** Called when asyn clients call pasynUInt32Digital->read().
- * The base class implementation simply returns the value from the parameter library.
+ * The base class implementation simply returns the value from the parameter library.
* Derived classes rarely need to reimplement this function.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[out] value Address of the value to read.
@@ -1838,8 +2220,8 @@ asynStatus asynPortDriver::readUInt32Digital(asynUser *pasynUser, epicsUInt32 *v
asynStatus status = asynSuccess;
epicsTimeStamp timeStamp; getTimeStamp(&timeStamp);
static const char *functionName = "readUInt32Digital";
-
- status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
+
+ status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
if (status != asynSuccess) return status;
/* We just read the current value of the parameter from the parameter library.
* Those values are updated whenever anything could cause them to change */
@@ -1848,23 +2230,23 @@ asynStatus asynPortDriver::readUInt32Digital(asynUser *pasynUser, epicsUInt32 *v
pasynUser->timestamp = timeStamp;
getParamAlarmStatus(addr, function, &pasynUser->alarmStatus);
getParamAlarmSeverity(addr, function, &pasynUser->alarmSeverity);
- if (status)
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
- "%s:%s: status=%d, function=%d, name=%s, value=%u mask=%u",
+ if (status)
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ "%s:%s: status=%d, function=%d, name=%s, value=%u mask=%u",
driverName, functionName, status, function, paramName, *value, mask);
- else
- asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
- "%s:%s: function=%d, name=%s, value=%u, mask=%u\n",
+ else
+ asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
+ "%s:%s: function=%d, name=%s, value=%u, mask=%u\n",
driverName, functionName, function, paramName, *value, mask);
return status;
}
-extern "C" {static asynStatus writeUInt32Digital(void *drvPvt, asynUser *pasynUser,
+extern "C" {static asynStatus writeUInt32Digital(void *drvPvt, asynUser *pasynUser,
epicsUInt32 value, epicsUInt32 mask)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->writeUInt32Digital(pasynUser, value, mask);
pPvt->unlock();
@@ -1872,10 +2254,10 @@ extern "C" {static asynStatus writeUInt32Digital(void *drvPvt, asynUser *pasynUs
}}
/** Called when asyn clients call pasynUInt32Digital->write().
- * The base class implementation simply sets the value in the parameter library and
- * calls any registered callbacks for this pasynUser->reason and address.
+ * The base class implementation simply sets the value in the parameter library and
+ * calls any registered callbacks for this pasynUser->reason and address.
* Derived classes will reimplement this function if they need to perform an action when an
- * asynInt32 value is written.
+ * asynInt32 value is written.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Value to write.
* \param[in] mask Mask value to use when writinging the value. */
@@ -1887,7 +2269,7 @@ asynStatus asynPortDriver::writeUInt32Digital(asynUser *pasynUser, epicsUInt32 v
asynStatus status = asynSuccess;
const char* functionName = "writeUInt32Digital";
- status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
+ status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
if (status != asynSuccess) return status;
/* Set the parameter in the parameter library. */
@@ -1895,14 +2277,14 @@ asynStatus asynPortDriver::writeUInt32Digital(asynUser *pasynUser, epicsUInt32 v
/* Do callbacks so higher layers see any changes */
status = (asynStatus) callParamCallbacks(addr, addr);
-
- if (status)
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
- "%s:%s: status=%d, function=%d, name=%s, value=%u, mask=%u",
+
+ if (status)
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ "%s:%s: status=%d, function=%d, name=%s, value=%u, mask=%u",
driverName, functionName, status, function, paramName, value, mask);
- else
- asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
- "%s:%s: function=%d, name=%s, value=%d, mask=%u\n",
+ else
+ asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
+ "%s:%s: function=%d, name=%s, value=%d, mask=%u\n",
driverName, functionName, function, paramName, value, mask);
return status;
}
@@ -1911,7 +2293,7 @@ extern "C" {static asynStatus setInterruptUInt32Digital(void *drvPvt, asynUser *
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->setInterruptUInt32Digital(pasynUser, mask, reason);
pPvt->unlock();
@@ -1919,11 +2301,11 @@ extern "C" {static asynStatus setInterruptUInt32Digital(void *drvPvt, asynUser *
}}
/** Called when asyn clients call pasynUInt32Digital->setInterrupt().
- * The base class implementation simply sets the value in the parameter library.
+ * The base class implementation simply sets the value in the parameter library.
* Derived classes will reimplement this function if they need to perform an action when an
- * setInterrupt is called.
+ * setInterrupt is called.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
- * \param[in] mask Interrupt mask.
+ * \param[in] mask Interrupt mask.
* \param[in] reason Interrupt reason. */
asynStatus asynPortDriver::setInterruptUInt32Digital(asynUser *pasynUser, epicsUInt32 mask, interruptReason reason)
{
@@ -1933,19 +2315,19 @@ asynStatus asynPortDriver::setInterruptUInt32Digital(asynUser *pasynUser, epicsU
asynStatus status = asynSuccess;
const char* functionName = "setInterruptUInt32Digital";
- status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
+ status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
if (status != asynSuccess) return status;
/* Set the parameters in the parameter library. */
status = this->params[addr]->setUInt32Interrupt(function, mask, reason);
- if (status)
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
- "%s:%s: status=%d, function=%d, name=%s, mask=%u, reason=%d",
+ if (status)
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ "%s:%s: status=%d, function=%d, name=%s, mask=%u, reason=%d",
driverName, functionName, status, function, paramName, mask, reason);
- else
- asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
- "%s:%s: function=%d, name=%s, mask=%u, reason=%d\n",
+ else
+ asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
+ "%s:%s: function=%d, name=%s, mask=%u, reason=%d\n",
driverName, functionName, function, paramName, mask, reason);
return status;
}
@@ -1954,7 +2336,7 @@ extern "C" {static asynStatus clearInterruptUInt32Digital(void *drvPvt, asynUser
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->clearInterruptUInt32Digital(pasynUser, mask);
pPvt->unlock();
@@ -1962,9 +2344,9 @@ extern "C" {static asynStatus clearInterruptUInt32Digital(void *drvPvt, asynUser
}}
/** Called when asyn clients call pasynUInt32Digital->clearInterrupt().
- * The base class implementation simply sets the value in the parameter library.
+ * The base class implementation simply sets the value in the parameter library.
* Derived classes will reimplement this function if they need to perform an action when an
- * clearInterrupt is called.
+ * clearInterrupt is called.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] mask Interrupt mask. */
asynStatus asynPortDriver::clearInterruptUInt32Digital(asynUser *pasynUser, epicsUInt32 mask)
@@ -1975,19 +2357,19 @@ asynStatus asynPortDriver::clearInterruptUInt32Digital(asynUser *pasynUser, epic
asynStatus status = asynSuccess;
const char* functionName = "clearInterruptUInt32Digital";
- status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
+ status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
if (status != asynSuccess) return status;
/* Set the parameters in the parameter library. */
status = this->params[addr]->clearUInt32Interrupt(function, mask);
- if (status)
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
- "%s:%s: status=%d, function=%d, name=%s, mask=%u",
+ if (status)
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ "%s:%s: status=%d, function=%d, name=%s, mask=%u",
driverName, functionName, status, function, paramName, mask);
- else
- asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
- "%s:%s: function=%d, name=%s, mask=%u\n",
+ else
+ asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
+ "%s:%s: function=%d, name=%s, mask=%u\n",
driverName, functionName, function, paramName, mask);
return status;
}
@@ -1996,7 +2378,7 @@ extern "C" {static asynStatus getInterruptUInt32Digital(void *drvPvt, asynUser *
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->getInterruptUInt32Digital(pasynUser, mask, reason);
pPvt->unlock();
@@ -2004,7 +2386,7 @@ extern "C" {static asynStatus getInterruptUInt32Digital(void *drvPvt, asynUser *
}}
/** Called when asyn clients call pasynUInt32Digital->getInterrupt().
- * The base class implementation simply returns the value from the parameter library.
+ * The base class implementation simply returns the value from the parameter library.
* Derived classes rarely need to reimplement this function.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[out] mask Interrupt mask address.
@@ -2017,31 +2399,31 @@ asynStatus asynPortDriver::getInterruptUInt32Digital(asynUser *pasynUser, epicsU
asynStatus status = asynSuccess;
const char* functionName = "getInterruptUInt32Digital";
- status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
+ status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
if (status != asynSuccess) return status;
/* Get the parameters in the parameter library. */
status = this->params[addr]->getUInt32Interrupt(function, mask, reason);
- if (status)
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
- "%s:%s: status=%d, function=%d, name=%s, mask=%u, reason=%d",
+ if (status)
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ "%s:%s: status=%d, function=%d, name=%s, mask=%u, reason=%d",
driverName, functionName, status, function, paramName, *mask, reason);
- else
- asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
- "%s:%s: function=%d, name=%s, mask=%u, reason=%d\n",
+ else
+ asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
+ "%s:%s: function=%d, name=%s, mask=%u, reason=%d\n",
driverName, functionName, function, paramName, *mask, reason);
return status;
}
-
+
/* asynFloat64 interface methods */
extern "C" {static asynStatus readFloat64(void *drvPvt, asynUser *pasynUser,
epicsFloat64 *value)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->readFloat64(pasynUser, value);
pPvt->unlock();
@@ -2049,7 +2431,7 @@ extern "C" {static asynStatus readFloat64(void *drvPvt, asynUser *pasynUser,
}}
/** Called when asyn clients call pasynFloat64->read().
- * The base class implementation simply returns the value from the parameter library.
+ * The base class implementation simply returns the value from the parameter library.
* Derived classes rarely need to reimplement this function.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Address of the value to read. */
@@ -2061,8 +2443,8 @@ asynStatus asynPortDriver::readFloat64(asynUser *pasynUser, epicsFloat64 *value)
asynStatus status = asynSuccess;
epicsTimeStamp timeStamp; getTimeStamp(&timeStamp);
static const char *functionName = "readFloat64";
-
- status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
+
+ status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
if (status != asynSuccess) return status;
/* We just read the current value of the parameter from the parameter library.
@@ -2072,18 +2454,18 @@ asynStatus asynPortDriver::readFloat64(asynUser *pasynUser, epicsFloat64 *value)
pasynUser->timestamp = timeStamp;
getParamAlarmStatus(addr, function, &pasynUser->alarmStatus);
getParamAlarmSeverity(addr, function, &pasynUser->alarmSeverity);
- if (status == asynParamUndefined)
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
- "%s:%s: status=%d, function=%d, name=%s, value is undefined",
+ if (status == asynParamUndefined)
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ "%s:%s: status=%d, function=%d, name=%s, value is undefined",
driverName, functionName, status, function, paramName );
-
- else if (status)
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
- "%s:%s: status=%d, function=%d, name=%s, value=%f",
+
+ else if (status)
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ "%s:%s: status=%d, function=%d, name=%s, value=%f",
driverName, functionName, status, function, paramName, *value);
- else
- asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
- "%s:%s: function=%d, name=%s, value=%f\n",
+ else
+ asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
+ "%s:%s: function=%d, name=%s, value=%f\n",
driverName, functionName, function, paramName, *value);
return status;
}
@@ -2093,7 +2475,7 @@ extern "C" {static asynStatus writeFloat64(void *drvPvt, asynUser *pasynUser,
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->writeFloat64(pasynUser, value);
pPvt->unlock();
@@ -2101,10 +2483,10 @@ extern "C" {static asynStatus writeFloat64(void *drvPvt, asynUser *pasynUser,
}}
/** Called when asyn clients call pasynFloat64->write().
- * The base class implementation simply sets the value in the parameter library and
- * calls any registered callbacks for this pasynUser->reason and address.
+ * The base class implementation simply sets the value in the parameter library and
+ * calls any registered callbacks for this pasynUser->reason and address.
* Derived classes will reimplement this function if they need to perform an action when an
- * asynFloat64 value is written.
+ * asynFloat64 value is written.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Value to write. */
asynStatus asynPortDriver::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
@@ -2115,27 +2497,27 @@ asynStatus asynPortDriver::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
int addr;
static const char *functionName = "writeFloat64";
- status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
+ status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
if (status != asynSuccess) return status;
-
+
/* Set the parameter and readback in the parameter library. */
status = setDoubleParam(addr, function, value);
/* Do callbacks so higher layers see any changes */
callParamCallbacks(addr, addr);
- if (status)
- asynPrint(pasynUser, ASYN_TRACE_ERROR,
- "%s:%s: error, status=%d function=%d, name=%s, value=%f\n",
+ if (status)
+ asynPrint(pasynUser, ASYN_TRACE_ERROR,
+ "%s:%s: error, status=%d function=%d, name=%s, value=%f\n",
driverName, functionName, status, function, paramName, value);
- else
- asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
- "%s:%s: function=%d, name=%s, value=%f\n",
+ else
+ asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
+ "%s:%s: function=%d, name=%s, value=%f\n",
driverName, functionName, function, paramName, value);
return status;
}
-
+
/* asynOctet interface methods */
extern "C" {static asynStatus readOctet(void *drvPvt, asynUser *pasynUser,
char *value, size_t maxChars, size_t *nActual,
@@ -2143,7 +2525,7 @@ extern "C" {static asynStatus readOctet(void *drvPvt, asynUser *pasynUser,
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->readOctet(pasynUser, value, maxChars, nActual, eomReason);
pPvt->unlock();
@@ -2151,7 +2533,7 @@ extern "C" {static asynStatus readOctet(void *drvPvt, asynUser *pasynUser,
}}
/** Called when asyn clients call pasynOctet->read().
- * The base class implementation simply returns the value from the parameter library.
+ * The base class implementation simply returns the value from the parameter library.
* Derived classes rarely need to reimplement this function.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Address of the string to read.
@@ -2168,8 +2550,8 @@ asynStatus asynPortDriver::readOctet(asynUser *pasynUser,
asynStatus status = asynSuccess;
epicsTimeStamp timeStamp; getTimeStamp(&timeStamp);
static const char *functionName = "readOctet";
-
- status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
+
+ status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
if (status != asynSuccess) return status;
/* We just read the current value of the parameter from the parameter library.
@@ -2179,13 +2561,13 @@ asynStatus asynPortDriver::readOctet(asynUser *pasynUser,
pasynUser->timestamp = timeStamp;
getParamAlarmStatus(addr, function, &pasynUser->alarmStatus);
getParamAlarmSeverity(addr, function, &pasynUser->alarmSeverity);
- if (status)
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
- "%s:%s: status=%d, function=%d, name=%s, value=%s",
+ if (status)
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ "%s:%s: status=%d, function=%d, name=%s, value=%s",
driverName, functionName, status, function, paramName, value);
- else
- asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
- "%s:%s: function=%d, name=%s, value=%s\n",
+ else
+ asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
+ "%s:%s: function=%d, name=%s, value=%s\n",
driverName, functionName, function, paramName, value);
if (eomReason) *eomReason = ASYN_EOM_END;
*nActual = strlen(value)+1;
@@ -2197,7 +2579,7 @@ extern "C" {static asynStatus writeOctet(void *drvPvt, asynUser *pasynUser,
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->writeOctet(pasynUser, value, maxChars, nActual);
pPvt->unlock();
@@ -2205,15 +2587,15 @@ extern "C" {static asynStatus writeOctet(void *drvPvt, asynUser *pasynUser,
}}
/** Called when asyn clients call pasynOctet->write().
- * The base class implementation simply sets the value in the parameter library and
- * calls any registered callbacks for this pasynUser->reason and address.
+ * The base class implementation simply sets the value in the parameter library and
+ * calls any registered callbacks for this pasynUser->reason and address.
* Derived classes will reimplement this function if they need to perform an action when an
* asynOctet value is written.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Address of the string to write.
* \param[in] nChars Number of characters to write.
* \param[out] nActual Number of characters actually written. */
-asynStatus asynPortDriver::writeOctet(asynUser *pasynUser, const char *value,
+asynStatus asynPortDriver::writeOctet(asynUser *pasynUser, const char *value,
size_t nChars, size_t *nActual)
{
int addr;
@@ -2222,7 +2604,7 @@ asynStatus asynPortDriver::writeOctet(asynUser *pasynUser, const char *value,
asynStatus status = asynSuccess;
static const char *functionName = "writeOctet";
- status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
+ status = parseAsynUser(pasynUser, &function, &addr, ¶mName);
if (status != asynSuccess) return status;
/* Set the parameter in the parameter library. */
@@ -2231,13 +2613,13 @@ asynStatus asynPortDriver::writeOctet(asynUser *pasynUser, const char *value,
/* Do callbacks so higher layers see any changes */
status = (asynStatus)callParamCallbacks(addr, addr);
- if (status)
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
- "%s:%s: status=%d, function=%d, name=%s, value=%s",
+ if (status)
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ "%s:%s: status=%d, function=%d, name=%s, value=%s",
driverName, functionName, status, function, paramName, value);
- else
- asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
- "%s:%s: function=%d, name=%s, value=%s\n",
+ else
+ asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
+ "%s:%s: function=%d, name=%s, value=%s\n",
driverName, functionName, function, paramName, value);
*nActual = nChars;
return status;
@@ -2247,7 +2629,7 @@ extern "C" {static asynStatus flushOctet(void *drvPvt, asynUser *pasynUser)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->flushOctet(pasynUser);
pPvt->unlock();
@@ -2257,13 +2639,13 @@ extern "C" {static asynStatus flushOctet(void *drvPvt, asynUser *pasynUser)
/** Called when asyn clients call pasynOctet->flush().
* The base class implementation duplicates the function in asynOctetBase.c, i.e.
* it does reads with a timeout of 0.05 seconds until the underlying driver returns
- * no more data.
+ * no more data.
* Derived classes will reimplement this function if they desire a different behavior.
* \param[in] pasynUser pasynUser structure that encodes the reason and address. */
asynStatus asynPortDriver::flushOctet(asynUser *pasynUser)
{
double savetimeout = pasynUser->timeout;
- char buffer[100];
+ char buffer[100];
size_t nbytesTransfered;
static const char *functionName = "flushOctet";
@@ -2279,12 +2661,12 @@ asynStatus asynPortDriver::flushOctet(asynUser *pasynUser)
return asynSuccess;
}
-extern "C" {static asynStatus setInputEosOctet(void *drvPvt, asynUser *pasynUser,
+extern "C" {static asynStatus setInputEosOctet(void *drvPvt, asynUser *pasynUser,
const char *eos, int eosLen)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->setInputEosOctet(pasynUser, eos, eosLen);
pPvt->unlock();
@@ -2292,7 +2674,7 @@ extern "C" {static asynStatus setInputEosOctet(void *drvPvt, asynUser *pasynUser
}}
/** Called when asyn clients call pasynOctet->setInputEos().
- * The base class implementation simply copies the inputEos to the class private data.
+ * The base class implementation simply copies the inputEos to the class private data.
* Derived classes will reimplement this function if they desire a different behavior.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] eos The input eos
@@ -2304,14 +2686,14 @@ asynStatus asynPortDriver::setInputEosOctet(asynUser *pasynUser, const char *eos
strncpy(inputEosOctet, eos, eosLen);
inputEosLenOctet = eosLen;
return asynSuccess;
-}
+}
-extern "C" {static asynStatus getInputEosOctet(void *drvPvt, asynUser *pasynUser,
+extern "C" {static asynStatus getInputEosOctet(void *drvPvt, asynUser *pasynUser,
char *eos, int eosSize, int *eosLen)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->getInputEosOctet(pasynUser, eos, eosSize, eosLen);
pPvt->unlock();
@@ -2319,7 +2701,7 @@ extern "C" {static asynStatus getInputEosOctet(void *drvPvt, asynUser *pasynUser
}}
/** Called when asyn clients call pasynOctet->getInputEos().
- * The base class implementation simply copies the inputEos from the class private data.
+ * The base class implementation simply copies the inputEos from the class private data.
* Derived classes will reimplement this function if they desire a different behavior.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[out] eos The input eos
@@ -2331,14 +2713,14 @@ asynStatus asynPortDriver::getInputEosOctet(asynUser *pasynUser, char *eos, int
if (*eosLen > eosSize) *eosLen = eosSize;
strncpy(eos, inputEosOctet, *eosLen);
return asynSuccess;
-}
+}
-extern "C" {static asynStatus setOutputEosOctet(void *drvPvt, asynUser *pasynUser,
+extern "C" {static asynStatus setOutputEosOctet(void *drvPvt, asynUser *pasynUser,
const char *eos, int eosLen)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->setOutputEosOctet(pasynUser, eos, eosLen);
pPvt->unlock();
@@ -2346,7 +2728,7 @@ extern "C" {static asynStatus setOutputEosOctet(void *drvPvt, asynUser *pasynUse
}}
/** Called when asyn clients call pasynOctet->setOutputEos().
- * The base class implementation simply copies the outputEos to the class private data.
+ * The base class implementation simply copies the outputEos to the class private data.
* Derived classes will reimplement this function if they desire a different behavior.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] eos The output eos
@@ -2358,14 +2740,14 @@ asynStatus asynPortDriver::setOutputEosOctet(asynUser *pasynUser, const char *eo
strncpy(outputEosOctet, eos, eosLen);
outputEosLenOctet = eosLen;
return asynSuccess;
-}
+}
-extern "C" {static asynStatus getOutputEosOctet(void *drvPvt, asynUser *pasynUser,
+extern "C" {static asynStatus getOutputEosOctet(void *drvPvt, asynUser *pasynUser,
char *eos, int eosSize, int *eosLen)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->getOutputEosOctet(pasynUser, eos, eosSize, eosLen);
pPvt->unlock();
@@ -2373,7 +2755,7 @@ extern "C" {static asynStatus getOutputEosOctet(void *drvPvt, asynUser *pasynUse
}}
/** Called when asyn clients call pasynOctet->getOutputEos().
- * The base class implementation simply copies the outputEos from the class private data.
+ * The base class implementation simply copies the outputEos from the class private data.
* Derived classes will reimplement this function if they desire a different behavior.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[out] eos The output eos
@@ -2385,18 +2767,18 @@ asynStatus asynPortDriver::getOutputEosOctet(asynUser *pasynUser, char *eos, int
if (*eosLen > eosSize) *eosLen = eosSize;
strncpy(eos, outputEosOctet, *eosLen);
return asynSuccess;
-}
+}
+
-
/* asynInt8Array interface methods */
extern "C" {static asynStatus readInt8Array(void *drvPvt, asynUser *pasynUser, epicsInt8 *value,
size_t nElements, size_t *nIn)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->readInt8Array(pasynUser, value, nElements, nIn);
pPvt->unlock();
@@ -2404,7 +2786,7 @@ extern "C" {static asynStatus readInt8Array(void *drvPvt, asynUser *pasynUser, e
}}
/** Called when asyn clients call pasynInt8Array->read().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Pointer to the array to read.
@@ -2421,15 +2803,15 @@ extern "C" {static asynStatus writeInt8Array(void *drvPvt, asynUser *pasynUser,
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->writeInt8Array(pasynUser, value, nElements);
pPvt->unlock();
- return status;
+ return status;
}}
/** Called when asyn clients call pasynInt8Array->write().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Pointer to the array to write.
@@ -2452,22 +2834,22 @@ asynStatus asynPortDriver::doCallbacksInt8Array(epicsInt8 *value,
this->asynStdInterfaces.int8ArrayInterruptPvt);
}
-
+
/* asynInt16Array interface methods */
extern "C" {static asynStatus readInt16Array(void *drvPvt, asynUser *pasynUser, epicsInt16 *value,
size_t nElements, size_t *nIn)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->readInt16Array(pasynUser, value, nElements, nIn);
pPvt->unlock();
- return status;
+ return status;
}}
/** Called when asyn clients call pasynInt16Array->read().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Pointer to the array to read.
@@ -2484,15 +2866,15 @@ extern "C" {static asynStatus writeInt16Array(void *drvPvt, asynUser *pasynUser,
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->writeInt16Array(pasynUser, value, nElements);
pPvt->unlock();
- return status;
+ return status;
}}
/** Called when asyn clients call pasynInt16Array->write().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Pointer to the array to write.
@@ -2515,14 +2897,14 @@ asynStatus asynPortDriver::doCallbacksInt16Array(epicsInt16 *value,
this->asynStdInterfaces.int16ArrayInterruptPvt);
}
-
+
/* asynInt32Array interface methods */
extern "C" {static asynStatus readInt32Array(void *drvPvt, asynUser *pasynUser, epicsInt32 *value,
size_t nElements, size_t *nIn)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->readInt32Array(pasynUser, value, nElements, nIn);
pPvt->unlock();
@@ -2530,7 +2912,7 @@ extern "C" {static asynStatus readInt32Array(void *drvPvt, asynUser *pasynUser,
}}
/** Called when asyn clients call pasynInt32Array->read().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Pointer to the array to read.
@@ -2547,15 +2929,15 @@ extern "C" {static asynStatus writeInt32Array(void *drvPvt, asynUser *pasynUser,
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->writeInt32Array(pasynUser, value, nElements);
pPvt->unlock();
- return status;
+ return status;
}}
/** Called when asyn clients call pasynInt32Array->write().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Pointer to the array to write.
@@ -2578,22 +2960,85 @@ asynStatus asynPortDriver::doCallbacksInt32Array(epicsInt32 *value,
this->asynStdInterfaces.int32ArrayInterruptPvt);
}
-
+
+/* asynInt64Array interface methods */
+extern "C" {static asynStatus readInt64Array(void *drvPvt, asynUser *pasynUser, epicsInt64 *value,
+ size_t nElements, size_t *nIn)
+{
+ asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
+ asynStatus status;
+
+ pPvt->lock();
+ status = pPvt->readInt64Array(pasynUser, value, nElements, nIn);
+ pPvt->unlock();
+ return status;
+}}
+
+/** Called when asyn clients call pasynInt64Array->read().
+ * The base class implementation simply prints an error message.
+ * Derived classes may reimplement this function if required.
+ * \param[in] pasynUser pasynUser structure that encodes the reason and address.
+ * \param[in] value Pointer to the array to read.
+ * \param[in] nElements Number of elements to read.
+ * \param[out] nIn Number of elements actually read. */
+asynStatus asynPortDriver::readInt64Array(asynUser *pasynUser, epicsInt64 *value,
+ size_t nElements, size_t *nIn)
+{
+ return readArray(pasynUser, value, nElements, nIn);
+}
+
+extern "C" {static asynStatus writeInt64Array(void *drvPvt, asynUser *pasynUser, epicsInt64 *value,
+ size_t nElements)
+{
+ asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
+ asynStatus status;
+
+ pPvt->lock();
+ status = pPvt->writeInt64Array(pasynUser, value, nElements);
+ pPvt->unlock();
+ return status;
+}}
+
+/** Called when asyn clients call pasynInt64Array->write().
+ * The base class implementation simply prints an error message.
+ * Derived classes may reimplement this function if required.
+ * \param[in] pasynUser pasynUser structure that encodes the reason and address.
+ * \param[in] value Pointer to the array to write.
+ * \param[in] nElements Number of elements to write. */
+asynStatus asynPortDriver::writeInt64Array(asynUser *pasynUser, epicsInt64 *value,
+ size_t nElements)
+{
+ return writeArray(pasynUser, value, nElements);
+}
+
+/** Called by driver to do the callbacks to registered clients on the asynInt64Array interface.
+ * \param[in] value Address of the array.
+ * \param[in] nElements Number of elements in the array.
+ * \param[in] reason A client will be called if reason matches pasynUser->reason registered for that client.
+ * \param[in] addr A client will be called if addr matches the asyn address registered for that client. */
+asynStatus asynPortDriver::doCallbacksInt64Array(epicsInt64 *value,
+ size_t nElements, int reason, int addr)
+{
+ return doCallbacksArray(value, nElements, reason, addr,
+ this->asynStdInterfaces.int64ArrayInterruptPvt);
+}
+
+
/* asynFloat32Array interface methods */
extern "C" {static asynStatus readFloat32Array(void *drvPvt, asynUser *pasynUser, epicsFloat32 *value,
size_t nElements, size_t *nIn)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->readFloat32Array(pasynUser, value, nElements, nIn);
pPvt->unlock();
- return status;
+ return status;
}}
/** Called when asyn clients call pasynFloat32Array->read().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Pointer to the array to read.
@@ -2610,15 +3055,15 @@ extern "C" {static asynStatus writeFloat32Array(void *drvPvt, asynUser *pasynUse
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->writeFloat32Array(pasynUser, value, nElements);
pPvt->unlock();
- return status;
+ return status;
}}
/** Called when asyn clients call pasynFloat32Array->write().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Pointer to the array to write.
@@ -2641,22 +3086,22 @@ asynStatus asynPortDriver::doCallbacksFloat32Array(epicsFloat32 *value,
this->asynStdInterfaces.float32ArrayInterruptPvt);
}
-
+
/* asynFloat64Array interface methods */
extern "C" {static asynStatus readFloat64Array(void *drvPvt, asynUser *pasynUser, epicsFloat64 *value,
size_t nElements, size_t *nIn)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->readFloat64Array(pasynUser, value, nElements, nIn);
pPvt->unlock();
- return status;
+ return status;
}}
/** Called when asyn clients call pasynFloat64Array->read().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Pointer to the array to read.
@@ -2673,15 +3118,15 @@ extern "C" {static asynStatus writeFloat64Array(void *drvPvt, asynUser *pasynUse
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->writeFloat64Array(pasynUser, value, nElements);
pPvt->unlock();
- return status;
+ return status;
}}
/** Called when asyn clients call pasynFloat64Array->write().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] value Pointer to the array to write.
@@ -2709,21 +3154,21 @@ extern "C" {static asynStatus readGenericPointer(void *drvPvt, asynUser *pasynUs
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status =pPvt->readGenericPointer(pasynUser, genericPointer);
pPvt->unlock();
- return status;
+ return status;
}}
/** Called when asyn clients call pasynGenericPointer->read().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] genericPointer Pointer to the object to read. */
asynStatus asynPortDriver::readGenericPointer(asynUser *pasynUser, void *genericPointer)
{
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s:readGenericPointer not implemented", driverName);
return asynError;
}
@@ -2732,21 +3177,21 @@ extern "C" {static asynStatus writeGenericPointer(void *drvPvt, asynUser *pasynU
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->writeGenericPointer(pasynUser, genericPointer);
pPvt->unlock();
- return status;
+ return status;
}}
/** Called when asyn clients call pasynGenericPointer->write().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
* \param[in] genericPointer Pointer to the object to write. */
asynStatus asynPortDriver::writeGenericPointer(asynUser *pasynUser, void *genericPointer)
{
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s:writeGenericPointer not implemented", driverName);
return asynError;
}
@@ -2800,23 +3245,23 @@ extern "C" {static asynStatus readOption(void *drvPvt, asynUser *pasynUser, cons
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->readOption(pasynUser, key, value, maxChars);
pPvt->unlock();
- return status;
+ return status;
}}
/** Called when asyn clients call pasynOption->read().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
- * \param[in] key Option key string.
+ * \param[in] key Option key string.
* \param[in] value Address of value string to be returned
* \param[in] maxChars Size of value string */
asynStatus asynPortDriver::readOption(asynUser *pasynUser, const char *key, char *value, int maxChars)
{
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s:readOption not implemented", driverName);
return asynError;
}
@@ -2825,52 +3270,52 @@ extern "C" {static asynStatus writeOption(void *drvPvt, asynUser *pasynUser, con
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->writeOption(pasynUser, key, value);
pPvt->unlock();
- return status;
+ return status;
}}
/** Called when asyn clients call pasynOption->write().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
- * \param[in] key Option key string.
+ * \param[in] key Option key string.
* \param[in] value Value string. */
asynStatus asynPortDriver::writeOption(asynUser *pasynUser, const char *key, const char *value)
{
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s:writeOption not implemented", driverName);
return asynError;
}
/* asynEnums interface methods */
-extern "C" {static asynStatus readEnum(void *drvPvt, asynUser *pasynUser, char *strings[], int values[], int severities[],
+extern "C" {static asynStatus readEnum(void *drvPvt, asynUser *pasynUser, char *strings[], int values[], int severities[],
size_t nElements, size_t *nIn)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->readEnum(pasynUser, strings, values, severities, nElements, nIn);
pPvt->unlock();
- return status;
+ return status;
}}
/** Called when asyn clients call pasynEnum->read().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
- * \param[in] strings Array of string pointers.
- * \param[in] values Array of values
- * \param[in] severities Array of severities
- * \param[in] nElements Size of value array
+ * \param[in] strings Array of string pointers.
+ * \param[in] values Array of values
+ * \param[in] severities Array of severities
+ * \param[in] nElements Size of value array
* \param[out] nIn Number of elements actually returned */
asynStatus asynPortDriver::readEnum(asynUser *pasynUser, char *strings[], int values[], int severities[], size_t nElements, size_t *nIn)
{
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s:readEnum not implemented", driverName);
return asynError;
}
@@ -2879,34 +3324,34 @@ extern "C" {static asynStatus writeEnum(void *drvPvt, asynUser *pasynUser, char
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->writeEnum(pasynUser, strings, values, severities, nElements);
pPvt->unlock();
- return status;
+ return status;
}}
/** Called when asyn clients call pasynEnum->write().
- * The base class implementation simply prints an error message.
+ * The base class implementation simply prints an error message.
* Derived classes may reimplement this function if required.
* \param[in] pasynUser pasynUser structure that encodes the reason and address.
- * \param[in] strings Array of string pointers.
- * \param[in] values Array of values
- * \param[in] severities Array of severities
+ * \param[in] strings Array of string pointers.
+ * \param[in] values Array of values
+ * \param[in] severities Array of severities
* \param[in] nElements Size of value array */
asynStatus asynPortDriver::writeEnum(asynUser *pasynUser, char *strings[], int values[], int severities[], size_t nElements)
{
- epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
+ epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s:writeEnum not implemented", driverName);
return asynError;
}
/** Called by driver to do the callbacks to registered clients on the asynEnum interface.
- * \param[in] strings Array of string pointers.
- * \param[in] values Array of values
- * \param[in] severities Array of severities
- * \param[in] nElements Size of value array
+ * \param[in] strings Array of string pointers.
+ * \param[in] values Array of values
+ * \param[in] severities Array of severities
+ * \param[in] nElements Size of value array
* \param[in] reason A client will be called if reason matches pasynUser->reason registered for that client.
* \param[in] address A client will be called if address matches the address registered for that client. */
asynStatus asynPortDriver::doCallbacksEnum(char *strings[], int values[], int severities[], size_t nElements, int reason, int address)
@@ -2934,22 +3379,22 @@ asynStatus asynPortDriver::doCallbacksEnum(char *strings[], int values[], int se
return asynSuccess;
}
-
+
/* asynDrvUser interface methods */
extern "C" {static asynStatus drvUserCreate(void *drvPvt, asynUser *pasynUser,
- const char *drvInfo,
+ const char *drvInfo,
const char **pptypeName, size_t *psize)
-{
+{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->drvUserCreate(pasynUser, drvInfo, pptypeName, psize);
pPvt->unlock();
- return status;
+ return status;
}}
-/** Called by asynManager to pass a pasynUser structure and drvInfo string to the driver;
+/** Called by asynManager to pass a pasynUser structure and drvInfo string to the driver;
* Assigns pasynUser->reason based on the value of the drvInfo string.
* This base class implementation looks up the drvInfo string in the parameter list.
* \param[in] pasynUser pasynUser structure that driver will modify
@@ -2957,39 +3402,39 @@ extern "C" {static asynStatus drvUserCreate(void *drvPvt, asynUser *pasynUser,
* \param[out] pptypeName Location in which driver can write information.
* \param[out] psize Location where driver can write information about size of pptypeName */
asynStatus asynPortDriver::drvUserCreate(asynUser *pasynUser,
- const char *drvInfo,
+ const char *drvInfo,
const char **pptypeName, size_t *psize)
{
static const char *functionName = "drvUserCreate";
asynStatus status;
int index;
int addr;
-
+
status = getAddress(pasynUser, &addr); if (status != asynSuccess) return status;
status = this->findParam(addr, drvInfo, &index);
if (status) {
asynPrint(pasynUser, ASYN_TRACE_ERROR,
- "%s:%s: addr=%d, cannot find parameter %s\n",
+ "%s:%s: addr=%d, cannot find parameter %s\n",
driverName, functionName, addr, drvInfo);
return status;
}
pasynUser->reason = index;
asynPrint(pasynUser, ASYN_TRACE_FLOW,
- "%s:%s: drvInfo=%s, index=%d\n",
+ "%s:%s: drvInfo=%s, index=%d\n",
driverName, functionName, drvInfo, index);
return asynSuccess;
}
-
+
extern "C" {static asynStatus drvUserGetType(void *drvPvt, asynUser *pasynUser,
const char **pptypeName, size_t *psize)
-{
+{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->drvUserGetType(pasynUser, pptypeName, psize);
pPvt->unlock();
- return status;
+ return status;
}}
/** Returns strings associated with driver-specific commands.
@@ -3014,14 +3459,14 @@ asynStatus asynPortDriver::drvUserGetType(asynUser *pasynUser,
}
extern "C" {static asynStatus drvUserDestroy(void *drvPvt, asynUser *pasynUser)
-{
+{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->drvUserDestroy(pasynUser);
pPvt->unlock();
- return status;
+ return status;
}}
/** Frees any resources allocated by drvUserCreate.
@@ -3039,13 +3484,13 @@ asynStatus asynPortDriver::drvUserDestroy(asynUser *pasynUser)
return asynSuccess;
}
-
+
/* asynCommon interface methods */
extern "C" {static void report(void *drvPvt, FILE *fp, int details)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
-
+
pPvt->lock();
pPvt->report(fp, details);
pPvt->unlock();
@@ -3071,10 +3516,10 @@ void asynPortDriver::report(FILE *fp, int details)
epicsTimeToStrftime(buff, sizeof(buff), "%Y/%m/%d %H:%M:%S.%03f", &timeStamp);
fprintf(fp, " Timestamp: %s\n", buff);
if (asynStdInterfaces.octet.pinterface) {
- fprintf(fp, " Input EOS[%d]: ", this->inputEosLenOctet);
+ fprintf(fp, " Input EOS[%d]: ", this->inputEosLenOctet);
epicsStrPrintEscaped(fp, this->inputEosOctet, this->inputEosLenOctet);
fprintf(fp, "\n");
- fprintf(fp, " Output EOS[%d]: ", this->outputEosLenOctet);
+ fprintf(fp, " Output EOS[%d]: ", this->outputEosLenOctet);
epicsStrPrintEscaped(fp, this->outputEosOctet, this->outputEosLenOctet);
fprintf(fp, "\n");
}
@@ -3083,6 +3528,7 @@ void asynPortDriver::report(FILE *fp, int details)
if (details >= 3) {
/* Report interrupt clients */
reportInterrupt (fp, pInterfaces->int32InterruptPvt, "int32");
+ reportInterrupt (fp, pInterfaces->int64InterruptPvt, "int64");
reportInterrupt (fp, pInterfaces->uInt32DigitalInterruptPvt,"uint32");
reportInterrupt (fp, pInterfaces->float64InterruptPvt, "float64");
reportInterrupt (fp, pInterfaces->octetInterruptPvt, "octet");
@@ -3098,7 +3544,7 @@ void asynPortDriver::report(FILE *fp, int details)
//* Time stamp support functions
/** Updates the timestamp for this port in pasynManager.
- * Drivers typically call this function when they receive new data and want
+ * Drivers typically call this function when they receive new data and want
* records with TSE=-2 to use this time as their timestamp. */
asynStatus asynPortDriver::updateTimeStamp()
{
@@ -3106,8 +3552,8 @@ asynStatus asynPortDriver::updateTimeStamp()
}
/** Updates the timestamp for this port in pasynManager, and returns this timestamp.
- * Drivers typically call this function when they receive new data and want
- * records with TSE=-2 to use this time as their timestamp.
+ * Drivers typically call this function when they receive new data and want
+ * records with TSE=-2 to use this time as their timestamp.
* \param[out] pTimeStamp A pointer to an epicsTimeStamp to receive the new timestamp. */
asynStatus asynPortDriver::updateTimeStamp(epicsTimeStamp *pTimeStamp)
{
@@ -3135,14 +3581,14 @@ extern "C" {static asynStatus connect(void *drvPvt, asynUser *pasynUser)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->connect(pasynUser);
pPvt->unlock();
- return status;
+ return status;
}}
-/** Connects driver to device;
+/** Connects driver to device;
* The base class implementation simply calls pasynManager->exceptionConnect if address is valid
* Derived classes can reimplement this function for real connection management.
* \param[in] pasynUser The pasynUser structure which contains information about the port and address */
@@ -3151,11 +3597,11 @@ asynStatus asynPortDriver::connect(asynUser *pasynUser)
int addr;
asynStatus status;
static const char *functionName = "connect";
-
+
status = getAddress(pasynUser, &addr); if (status != asynSuccess) return status;
pasynManager->exceptionConnect(pasynUser);
asynPrint(pasynUser, ASYN_TRACE_FLOW,
- "%s:%s:, pasynUser=%p\n",
+ "%s:%s:, pasynUser=%p\n",
driverName, functionName, pasynUser);
return asynSuccess;
}
@@ -3165,14 +3611,14 @@ extern "C" {static asynStatus disconnect(void *drvPvt, asynUser *pasynUser)
{
asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
asynStatus status;
-
+
pPvt->lock();
status = pPvt->disconnect(pasynUser);
pPvt->unlock();
- return status;
+ return status;
}}
-/** Disconnects driver from device;
+/** Disconnects driver from device;
* the base class implementation simply calls pasynManager->exceptionDisconnect.
* Derived classes can reimplement this function for real connection management.
* \param[in] pasynUser The pasynUser structure which contains information about the port and address */
@@ -3181,17 +3627,17 @@ asynStatus asynPortDriver::disconnect(asynUser *pasynUser)
int addr;
asynStatus status;
static const char *functionName = "disconnect";
-
+
status = getAddress(pasynUser, &addr); if (status != asynSuccess) return status;
pasynManager->exceptionDisconnect(pasynUser);
asynPrint(pasynUser, ASYN_TRACE_FLOW,
- "%s:%s:, pasynUser=%p\n",
+ "%s:%s:, pasynUser=%p\n",
driverName, functionName, pasynUser);
return asynSuccess;
}
-
+
/* Structures with function pointers for each of the asyn interfaces */
static asynCommon ifaceCommon = {
report,
@@ -3205,6 +3651,12 @@ static asynInt32 ifaceInt32 = {
getBounds
};
+static asynInt64 ifaceInt64 = {
+ writeInt64,
+ readInt64,
+ getBounds64
+};
+
static asynUInt32Digital ifaceUInt32Digital = {
writeUInt32Digital,
readUInt32Digital,
@@ -3245,6 +3697,11 @@ static asynInt32Array ifaceInt32Array = {
readInt32Array
};
+static asynInt64Array ifaceInt64Array = {
+ writeInt64Array,
+ readInt64Array
+};
+
static asynFloat32Array ifaceFloat32Array = {
writeFloat32Array,
readFloat32Array
@@ -3276,20 +3733,29 @@ static asynDrvUser ifaceDrvUser = {
drvUserDestroy
};
-
+asynPortDriver::asynPortDriver(asynParamSet* paramSet,
+ const char *portNameIn, int maxAddrIn, int interfaceMask, int interruptMask,
+ int asynFlags, int autoConnect, int priority, int stackSize):
+ paramSet(paramSet)
+{
+ initialize(portNameIn, maxAddrIn, interfaceMask, interruptMask, asynFlags,
+ autoConnect, priority, stackSize);
+ createParams();
+}
+
/** Constructor for the asynPortDriver class.
* \param[in] portNameIn The name of the asyn port driver to be created.
* \param[in] maxAddrIn The maximum number of asyn addr addresses this driver supports.
- Often it is 1 (which is the minimum), but some drivers, for example a
- 16-channel D/A or A/D would support values > 1.
+ Often it is 1 (which is the minimum), but some drivers, for example a
+ 16-channel D/A or A/D would support values > 1.
This controls the number of parameter tables that are created.
* \param[in] interfaceMask Bit mask defining the asyn interfaces that this driver supports.
The bit mask values are defined in asynPortDriver.h, e.g. asynInt32Mask.
* \param[in] interruptMask Bit mask definining the asyn interfaces that can generate interrupts (callbacks).
The bit mask values are defined in asynPortDriver.h, e.g. asynInt8ArrayMask.
* \param[in] asynFlags Flags when creating the asyn port driver; includes ASYN_CANBLOCK and ASYN_MULTIDEVICE.
- * \param[in] autoConnect The autoConnect flag for the asyn port driver.
+ * \param[in] autoConnect The autoConnect flag for the asyn port driver.
1 if the driver should autoconnect.
* \param[in] priority The thread priority for the asyn port driver thread if ASYN_CANBLOCK is set in asynFlags.
If it is 0 then the default value of epicsThreadPriorityMedium will be assigned by asynManager.
@@ -3335,7 +3801,7 @@ void asynPortDriver::initialize(const char *portNameIn, int maxAddrIn, int inter
/* Initialize some members to 0 */
pInterfaces = &this->asynStdInterfaces;
memset(pInterfaces, 0, sizeof(asynStdInterfaces));
-
+
this->portName = epicsStrDup(portNameIn);
if (maxAddrIn < 1) maxAddrIn = 1;
@@ -3357,7 +3823,7 @@ void asynPortDriver::initialize(const char *portNameIn, int maxAddrIn, int inter
printf("%s\n", msg.c_str());
throw std::runtime_error(msg);
}
-
+
inputEosOctet = epicsStrDup("");
inputEosLenOctet = 0;
outputEosOctet = epicsStrDup("");
@@ -3377,25 +3843,27 @@ void asynPortDriver::initialize(const char *portNameIn, int maxAddrIn, int inter
/* Create asynUser for debugging and for standardInterfacesBase */
this->pasynUserSelf = pasynManager->createAsynUser(0, 0);
-
+
/* The following asynPrint will be governed by the global trace mask since asynUser is not yet connected to port */
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
"%s:%s: creating port %s maxAddr=%d\n"
" interfaceMask=0x%X, interruptMask=0x%X\n"
" asynFlags=0x%X, autoConnect=%d, priority=%d, stackSize=%d\n",
driverName, functionName, this->portName, this->maxAddr, interfaceMask,
- interruptMask, asynFlags, autoConnect, priority, stackSize);
+ interruptMask, asynFlags, autoConnect, priority, stackSize);
/* Set addresses of asyn interfaces */
if (interfaceMask & asynCommonMask) pInterfaces->common.pinterface = (void *)&ifaceCommon;
if (interfaceMask & asynDrvUserMask) pInterfaces->drvUser.pinterface = (void *)&ifaceDrvUser;
if (interfaceMask & asynInt32Mask) pInterfaces->int32.pinterface = (void *)&ifaceInt32;
+ if (interfaceMask & asynInt64Mask) pInterfaces->int64.pinterface = (void *)&ifaceInt64;
if (interfaceMask & asynUInt32DigitalMask) pInterfaces->uInt32Digital.pinterface = (void *)&ifaceUInt32Digital;
if (interfaceMask & asynFloat64Mask) pInterfaces->float64.pinterface = (void *)&ifaceFloat64;
if (interfaceMask & asynOctetMask) pInterfaces->octet.pinterface = (void *)&ifaceOctet;
if (interfaceMask & asynInt8ArrayMask) pInterfaces->int8Array.pinterface = (void *)&ifaceInt8Array;
if (interfaceMask & asynInt16ArrayMask) pInterfaces->int16Array.pinterface = (void *)&ifaceInt16Array;
if (interfaceMask & asynInt32ArrayMask) pInterfaces->int32Array.pinterface = (void *)&ifaceInt32Array;
+ if (interfaceMask & asynInt64ArrayMask) pInterfaces->int64Array.pinterface = (void *)&ifaceInt64Array;
if (interfaceMask & asynFloat32ArrayMask) pInterfaces->float32Array.pinterface = (void *)&ifaceFloat32Array;
if (interfaceMask & asynFloat64ArrayMask) pInterfaces->float64Array.pinterface = (void *)&ifaceFloat64Array;
if (interfaceMask & asynGenericPointerMask) pInterfaces->genericPointer.pinterface= (void *)&ifaceGenericPointer;
@@ -3404,12 +3872,14 @@ void asynPortDriver::initialize(const char *portNameIn, int maxAddrIn, int inter
/* Define which interfaces can generate interrupts */
if (interruptMask & asynInt32Mask) pInterfaces->int32CanInterrupt = 1;
+ if (interruptMask & asynInt64Mask) pInterfaces->int64CanInterrupt = 1;
if (interruptMask & asynUInt32DigitalMask) pInterfaces->uInt32DigitalCanInterrupt = 1;
if (interruptMask & asynFloat64Mask) pInterfaces->float64CanInterrupt = 1;
if (interruptMask & asynOctetMask) pInterfaces->octetCanInterrupt = 1;
if (interruptMask & asynInt8ArrayMask) pInterfaces->int8ArrayCanInterrupt = 1;
if (interruptMask & asynInt16ArrayMask) pInterfaces->int16ArrayCanInterrupt = 1;
if (interruptMask & asynInt32ArrayMask) pInterfaces->int32ArrayCanInterrupt = 1;
+ if (interruptMask & asynInt64ArrayMask) pInterfaces->int64ArrayCanInterrupt = 1;
if (interruptMask & asynFloat32ArrayMask) pInterfaces->float32ArrayCanInterrupt = 1;
if (interruptMask & asynFloat64ArrayMask) pInterfaces->float64ArrayCanInterrupt = 1;
if (interruptMask & asynGenericPointerMask) pInterfaces->genericPointerCanInterrupt = 1;
@@ -3438,6 +3908,19 @@ void asynPortDriver::initialize(const char *portNameIn, int maxAddrIn, int inter
cbThread = new callbackThread(this);
}
+/** Create any parameters defined in the asynParamSet, if there are any */
+asynStatus asynPortDriver::createParams()
+{
+ asynStatus status;
+ std::vector paramDefinitions = paramSet->getParamDefinitions();
+ for (std::vector::iterator it = paramDefinitions.begin(); it != paramDefinitions.end(); ++it) {
+ status = createParam(it->name, it->type, it->index);
+ if (status) return asynError;
+ }
+
+ return asynSuccess;
+}
+
/** Destructor for asynPortDriver class; frees resources allocated when port driver is created. */
asynPortDriver::~asynPortDriver()
{
@@ -3460,7 +3943,7 @@ void* findAsynPortDriver(const char *portName)
asynUser *pasynUser;
asynInterface *pasynInterface;
asynStatus status;
-
+
pasynUser = pasynManager->createAsynUser(NULL, NULL);
status = pasynManager->connectDevice(pasynUser, portName, 0);
if (status) return NULL;
@@ -3470,5 +3953,5 @@ void* findAsynPortDriver(const char *portName)
pasynManager->freeAsynUser(pasynUser);
return pasynInterface->drvPvt;
}
-
+
diff --git a/asyn/asynPortDriver/asynPortDriver.h b/asyn/asynPortDriver/asynPortDriver.h
old mode 100755
new mode 100644
index 52bbdc0..7028ede
--- a/asyn/asynPortDriver/asynPortDriver.h
+++ b/asyn/asynPortDriver/asynPortDriver.h
@@ -9,12 +9,13 @@
#include
#include
+#include
#include
#include
class paramList;
-epicsShareFunc void* findAsynPortDriver(const char *portName);
+ASYN_API void* findAsynPortDriver(const char *portName);
typedef void (*userTimeStampFunction)(void *userPvt, epicsTimeStamp *pTimeStamp);
#ifdef __cplusplus
@@ -34,13 +35,18 @@ typedef void (*userTimeStampFunction)(void *userPvt, epicsTimeStamp *pTimeStamp)
#define asynFloat64ArrayMask 0x00000800
#define asynGenericPointerMask 0x00001000
#define asynEnumMask 0x00002000
+#define asynInt64Mask 0x00004000
+#define asynInt64ArrayMask 0x00008000
class callbackThread;
/** Base class for asyn port drivers; handles most of the bookkeeping for writing an asyn port driver
* with standard asyn interfaces and a parameter library. */
-class epicsShareClass asynPortDriver {
+class ASYN_API asynPortDriver {
public:
+ asynPortDriver(asynParamSet* paramSet,
+ const char *portName, int maxAddr, int interfaceMask, int interruptMask,
+ int asynFlags, int autoConnect, int priority, int stackSize);
asynPortDriver(const char *portName, int maxAddr, int interfaceMask, int interruptMask,
int asynFlags, int autoConnect, int priority, int stackSize);
asynPortDriver(const char *portName, int maxAddr, int paramTableSize, int interfaceMask, int interruptMask,
@@ -49,15 +55,18 @@ class epicsShareClass asynPortDriver {
virtual asynStatus lock();
virtual asynStatus unlock();
virtual asynStatus getAddress(asynUser *pasynUser, int *address);
- virtual asynStatus parseAsynUser(asynUser *pasynUser, int *reason, int *address, const char **paramName);
+ virtual asynStatus parseAsynUser(asynUser *pasynUser, int *reason, int *address, const char **paramName);
virtual asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
+ virtual asynStatus readInt64(asynUser *pasynUser, epicsInt64 *value);
+ virtual asynStatus writeInt64(asynUser *pasynUser, epicsInt64 value);
virtual asynStatus readUInt32Digital(asynUser *pasynUser, epicsUInt32 *value, epicsUInt32 mask);
virtual asynStatus writeUInt32Digital(asynUser *pasynUser, epicsUInt32 value, epicsUInt32 mask);
virtual asynStatus setInterruptUInt32Digital(asynUser *pasynUser, epicsUInt32 mask, interruptReason reason);
virtual asynStatus clearInterruptUInt32Digital(asynUser *pasynUser, epicsUInt32 mask);
virtual asynStatus getInterruptUInt32Digital(asynUser *pasynUser, epicsUInt32 *mask, interruptReason reason);
virtual asynStatus getBounds(asynUser *pasynUser, epicsInt32 *low, epicsInt32 *high);
+ virtual asynStatus getBounds64(asynUser *pasynUser, epicsInt64 *low, epicsInt64 *high);
virtual asynStatus readFloat64(asynUser *pasynUser, epicsFloat64 *value);
virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
virtual asynStatus readOctet(asynUser *pasynUser, char *value, size_t maxChars,
@@ -69,7 +78,7 @@ class epicsShareClass asynPortDriver {
virtual asynStatus getInputEosOctet(asynUser *pasynUser, char *eos, int eosSize, int *eosLen);
virtual asynStatus setOutputEosOctet(asynUser *pasynUser, const char *eos, int eosLen);
virtual asynStatus getOutputEosOctet(asynUser *pasynUser, char *eos, int eosSize, int *eosLen);
- virtual asynStatus readInt8Array(asynUser *pasynUser, epicsInt8 *value,
+ virtual asynStatus readInt8Array(asynUser *pasynUser, epicsInt8 *value,
size_t nElements, size_t *nIn);
virtual asynStatus writeInt8Array(asynUser *pasynUser, epicsInt8 *value,
size_t nElements);
@@ -87,6 +96,12 @@ class epicsShareClass asynPortDriver {
size_t nElements);
virtual asynStatus doCallbacksInt32Array(epicsInt32 *value,
size_t nElements, int reason, int addr);
+ virtual asynStatus readInt64Array(asynUser *pasynUser, epicsInt64 *value,
+ size_t nElements, size_t *nIn);
+ virtual asynStatus writeInt64Array(asynUser *pasynUser, epicsInt64 *value,
+ size_t nElements);
+ virtual asynStatus doCallbacksInt64Array(epicsInt64 *value,
+ size_t nElements, int reason, int addr);
virtual asynStatus readFloat32Array(asynUser *pasynUser, epicsFloat32 *value,
size_t nElements, size_t *nIn);
virtual asynStatus writeFloat32Array(asynUser *pasynUser, epicsFloat32 *value,
@@ -107,7 +122,7 @@ class epicsShareClass asynPortDriver {
virtual asynStatus readEnum(asynUser *pasynUser, char *strings[], int values[], int severities[], size_t nElements, size_t *nIn);
virtual asynStatus writeEnum(asynUser *pasynUser, char *strings[], int values[], int severities[], size_t nElements);
virtual asynStatus doCallbacksEnum(char *strings[], int values[], int severities[], size_t nElements, int reason, int addr);
- virtual asynStatus drvUserCreate(asynUser *pasynUser, const char *drvInfo,
+ virtual asynStatus drvUserCreate(asynUser *pasynUser, const char *drvInfo,
const char **pptypeName, size_t *psize);
virtual asynStatus drvUserGetType(asynUser *pasynUser,
const char **pptypeName, size_t *psize);
@@ -115,9 +130,10 @@ class epicsShareClass asynPortDriver {
virtual void report(FILE *fp, int details);
virtual asynStatus connect(asynUser *pasynUser);
virtual asynStatus disconnect(asynUser *pasynUser);
-
+
virtual asynStatus createParam( const char *name, asynParamType type, int *index);
virtual asynStatus createParam(int list, const char *name, asynParamType type, int *index);
+ virtual asynStatus createParams();
virtual asynStatus getNumParams( int *numParams);
virtual asynStatus getNumParams(int list, int *numParams);
virtual asynStatus findParam( const char *name, int *index);
@@ -142,6 +158,8 @@ class epicsShareClass asynPortDriver {
virtual void reportGetParamErrors(asynStatus status, int index, int list, const char *functionName);
virtual asynStatus setIntegerParam( int index, int value);
virtual asynStatus setIntegerParam(int list, int index, int value);
+ virtual asynStatus setInteger64Param( int index, epicsInt64 value);
+ virtual asynStatus setInteger64Param(int list, int index, epicsInt64 value);
virtual asynStatus setUIntDigitalParam( int index, epicsUInt32 value, epicsUInt32 valueMask);
virtual asynStatus setUIntDigitalParam(int list, int index, epicsUInt32 value, epicsUInt32 valueMask);
virtual asynStatus setUIntDigitalParam( int index, epicsUInt32 value, epicsUInt32 valueMask, epicsUInt32 interruptMask);
@@ -160,6 +178,8 @@ class epicsShareClass asynPortDriver {
virtual asynStatus setStringParam(int list, int index, const std::string& value);
virtual asynStatus getIntegerParam( int index, epicsInt32 * value);
virtual asynStatus getIntegerParam(int list, int index, epicsInt32 * value);
+ virtual asynStatus getInteger64Param( int index, epicsInt64 * value);
+ virtual asynStatus getInteger64Param(int list, int index, epicsInt64 * value);
virtual asynStatus getUIntDigitalParam( int index, epicsUInt32 *value, epicsUInt32 mask);
virtual asynStatus getUIntDigitalParam(int list, int index, epicsUInt32 *value, epicsUInt32 mask);
virtual asynStatus getDoubleParam( int index, double * value);
@@ -184,6 +204,7 @@ class epicsShareClass asynPortDriver {
void callbackTask();
protected:
+ asynParamSet* paramSet;
void initialize(const char *portNameIn, int maxAddrIn, int interfaceMask, int interruptMask, int asynFlags,
int autoConnect, int priority, int stackSize);
asynUser *pasynUserSelf; /**< asynUser connected to ourselves for asynTrace */
@@ -191,13 +212,14 @@ class epicsShareClass asynPortDriver {
private:
std::vector params;
+ paramList *getParamList(int list);
epicsMutexId mutexId;
char *inputEosOctet;
int inputEosLenOctet;
char *outputEosOctet;
int outputEosLenOctet;
callbackThread *cbThread;
- template
+ template
asynStatus doCallbacksArray(epicsType *value, size_t nElements,
int reason, int address, void *interruptPvt);
@@ -211,11 +233,24 @@ class callbackThread: public epicsThreadRunable {
~callbackThread();
void run();
private:
- epicsThread thread;
+ epicsThread *pThread;
asynPortDriver *pPortDriver;
epicsEvent shutdown;
+ epicsEvent doneEvent;
};
+/** Utility function that returns a pointer to an asynPortDriver derived class object from its name */
+template T* findDerivedAsynPortDriver(const char* portName)
+{
+ // findAsynPortDriver returns a void pointer that was cast from an asynPortDriver pointer
+ asynPortDriver* apd = (asynPortDriver*) findAsynPortDriver(portName);
+ if (!apd) return NULL;
+
+ // Downcast asynPortDriver pointer to T pointer - this requires pointer offsetting
+ T* pC = dynamic_cast(apd);
+ return pC;
+}
+
#endif /* cplusplus */
-
+
#endif
diff --git a/asyn/asynPortDriver/exceptions/ParamListInvalidIndex.cpp b/asyn/asynPortDriver/exceptions/ParamListInvalidIndex.cpp
index 7f1410d..87418e8 100644
--- a/asyn/asynPortDriver/exceptions/ParamListInvalidIndex.cpp
+++ b/asyn/asynPortDriver/exceptions/ParamListInvalidIndex.cpp
@@ -8,7 +8,7 @@
#include "ParamListInvalidIndex.h"
ParamListInvalidIndex::ParamListInvalidIndex(const std::string& description):
- logic_error(description){
+ std::logic_error(description){
}
diff --git a/asyn/asynPortDriver/exceptions/ParamListInvalidIndex.h b/asyn/asynPortDriver/exceptions/ParamListInvalidIndex.h
index 6d96c8e..546e3e2 100644
--- a/asyn/asynPortDriver/exceptions/ParamListInvalidIndex.h
+++ b/asyn/asynPortDriver/exceptions/ParamListInvalidIndex.h
@@ -10,10 +10,9 @@
#include
-using std::logic_error;
-class ParamListInvalidIndex: public logic_error {
+class ParamListInvalidIndex: public std::logic_error {
public:
- ParamListInvalidIndex(const std::string& description);
+ ParamListInvalidIndex(const std::string& description);
};
#endif /* PARAMLISTINVALIDINDEX_H_ */
diff --git a/asyn/asynPortDriver/exceptions/ParamListParamNotFound.cpp b/asyn/asynPortDriver/exceptions/ParamListParamNotFound.cpp
index d8a76fb..a063549 100644
--- a/asyn/asynPortDriver/exceptions/ParamListParamNotFound.cpp
+++ b/asyn/asynPortDriver/exceptions/ParamListParamNotFound.cpp
@@ -8,6 +8,6 @@
#include "ParamListParamNotFound.h"
ParamListParamNotFound::ParamListParamNotFound(const std::string& description):
- logic_error(description){
+ std::logic_error(description){
}
diff --git a/asyn/asynPortDriver/exceptions/ParamListParamNotFound.h b/asyn/asynPortDriver/exceptions/ParamListParamNotFound.h
index fe8079e..dd57ed3 100644
--- a/asyn/asynPortDriver/exceptions/ParamListParamNotFound.h
+++ b/asyn/asynPortDriver/exceptions/ParamListParamNotFound.h
@@ -10,10 +10,9 @@
#include
-using std::logic_error;
-class ParamListParamNotFound: public logic_error {
+class ParamListParamNotFound: public std::logic_error {
public:
- ParamListParamNotFound(const std::string& description);
+ ParamListParamNotFound(const std::string& description);
};
#endif /* PARAMLISTPARAMNOTFOUND_H_ */
diff --git a/asyn/asynPortDriver/exceptions/ParamValNotDefined.cpp b/asyn/asynPortDriver/exceptions/ParamValNotDefined.cpp
index 38b43e3..0c6f9fb 100644
--- a/asyn/asynPortDriver/exceptions/ParamValNotDefined.cpp
+++ b/asyn/asynPortDriver/exceptions/ParamValNotDefined.cpp
@@ -8,6 +8,6 @@
#include "ParamValNotDefined.h"
ParamValNotDefined::ParamValNotDefined(const std::string& description):
- logic_error(description){
+ std::logic_error(description){
}
diff --git a/asyn/asynPortDriver/exceptions/ParamValNotDefined.h b/asyn/asynPortDriver/exceptions/ParamValNotDefined.h
index 83e7cc9..5ac71e3 100644
--- a/asyn/asynPortDriver/exceptions/ParamValNotDefined.h
+++ b/asyn/asynPortDriver/exceptions/ParamValNotDefined.h
@@ -11,10 +11,9 @@
#include
#include
-using std::logic_error;
-class ParamValNotDefined: public logic_error {
+class ParamValNotDefined: public std::logic_error {
public:
- ParamValNotDefined(const std::string& description);
+ ParamValNotDefined(const std::string& description);
};
#endif /* PARAMVALNOTDEFINED_H_ */
diff --git a/asyn/asynPortDriver/exceptions/ParamValStringSizeRequestTooBig.cpp b/asyn/asynPortDriver/exceptions/ParamValStringSizeRequestTooBig.cpp
index a3219ef..dd4305c 100644
--- a/asyn/asynPortDriver/exceptions/ParamValStringSizeRequestTooBig.cpp
+++ b/asyn/asynPortDriver/exceptions/ParamValStringSizeRequestTooBig.cpp
@@ -8,6 +8,6 @@
#include "ParamValStringSizeRequestTooBig.h"
ParamValStringSizeRequestTooBig::ParamValStringSizeRequestTooBig(const std::string& description):
- logic_error(description){
+ std::logic_error(description){
}
diff --git a/asyn/asynPortDriver/exceptions/ParamValStringSizeRequestTooBig.h b/asyn/asynPortDriver/exceptions/ParamValStringSizeRequestTooBig.h
index fe0640b..7f706ff 100644
--- a/asyn/asynPortDriver/exceptions/ParamValStringSizeRequestTooBig.h
+++ b/asyn/asynPortDriver/exceptions/ParamValStringSizeRequestTooBig.h
@@ -10,10 +10,9 @@
#include
-using std::logic_error;
-class ParamValStringSizeRequestTooBig: public logic_error {
+class ParamValStringSizeRequestTooBig: public std::logic_error {
public:
- ParamValStringSizeRequestTooBig(const std::string& description);
+ ParamValStringSizeRequestTooBig(const std::string& description);
};
#endif /* PARAMVALSTRINGSIZEREQUESTTOOBIG_H_ */
diff --git a/asyn/asynPortDriver/exceptions/ParamValValueNotChanged.cpp b/asyn/asynPortDriver/exceptions/ParamValValueNotChanged.cpp
index 03e4f3c..9a7739f 100644
--- a/asyn/asynPortDriver/exceptions/ParamValValueNotChanged.cpp
+++ b/asyn/asynPortDriver/exceptions/ParamValValueNotChanged.cpp
@@ -8,6 +8,6 @@
#include "ParamValValueNotChanged.h"
ParamValValueNotChanged::ParamValValueNotChanged(const std::string& description):
-logic_error(description){
+std::logic_error(description){
}
diff --git a/asyn/asynPortDriver/exceptions/ParamValValueNotChanged.h b/asyn/asynPortDriver/exceptions/ParamValValueNotChanged.h
index b32dee5..15e86a2 100644
--- a/asyn/asynPortDriver/exceptions/ParamValValueNotChanged.h
+++ b/asyn/asynPortDriver/exceptions/ParamValValueNotChanged.h
@@ -10,10 +10,9 @@
#include
-using std::logic_error;
-class ParamValValueNotChanged: public logic_error {
+class ParamValValueNotChanged: public std::logic_error {
public:
- ParamValValueNotChanged(const std::string& description);
+ ParamValValueNotChanged(const std::string& description);
};
#endif /* PARAMVALVALUENOTCHANGED_H_ */
diff --git a/asyn/asynPortDriver/exceptions/ParamValWrongType.cpp b/asyn/asynPortDriver/exceptions/ParamValWrongType.cpp
index 047fe8b..424b10b 100644
--- a/asyn/asynPortDriver/exceptions/ParamValWrongType.cpp
+++ b/asyn/asynPortDriver/exceptions/ParamValWrongType.cpp
@@ -8,7 +8,7 @@
#include "ParamValWrongType.h"
ParamValWrongType::ParamValWrongType(const std::string& description):
- logic_error(description){
+ std::logic_error(description){
}
diff --git a/asyn/asynPortDriver/exceptions/ParamValWrongType.h b/asyn/asynPortDriver/exceptions/ParamValWrongType.h
index d79de25..5fdc0f8 100644
--- a/asyn/asynPortDriver/exceptions/ParamValWrongType.h
+++ b/asyn/asynPortDriver/exceptions/ParamValWrongType.h
@@ -10,10 +10,9 @@
#include
-using std::logic_error;
-class ParamValWrongType: public logic_error {
+class ParamValWrongType: public std::logic_error {
public:
- ParamValWrongType(const std::string& description);
+ ParamValWrongType(const std::string& description);
};
#endif /* PARAMVALWRONGTYPE_H_ */
diff --git a/asyn/asynPortDriver/paramErrors.h b/asyn/asynPortDriver/paramErrors.h
index dc16184..019ae2d 100644
--- a/asyn/asynPortDriver/paramErrors.h
+++ b/asyn/asynPortDriver/paramErrors.h
@@ -16,6 +16,7 @@
#define asynParamWrongType (asynStatus)(asynDisabled + 3)
#define asynParamBadIndex (asynStatus)(asynDisabled + 4)
#define asynParamUndefined (asynStatus)(asynDisabled + 5)
+#define asynParamInvalidList (asynStatus)(asynDisabled + 6)
#endif /* ASYNPORTDRIVERERRORSTATES_H_ */
diff --git a/asyn/asynPortDriver/paramVal.cpp b/asyn/asynPortDriver/paramVal.cpp
index 25312c9..aaa33d1 100644
--- a/asyn/asynPortDriver/paramVal.cpp
+++ b/asyn/asynPortDriver/paramVal.cpp
@@ -16,12 +16,14 @@
const char* paramVal::typeNames[] = {
"asynParamTypeUndefined",
"asynParamInt32",
+ "asynParamInt64",
"asynParamUInt32Digital",
"asynParamFloat64",
"asynParamOctet",
"asynParamInt8Array",
"asynParamInt16Array",
"asynParamInt32Array",
+ "asynParamInt64Array",
"asynParamFloat32Array",
"asynParamFloat64Array",
"asynParamGenericPointer"
@@ -151,6 +153,35 @@ epicsInt32 paramVal::getInteger()
return data.ival;
}
+/** Sets the value for a 64-bit integer.
+ * \param[in] value Value to set.
+ * \throws ParamValWrongType if type is not asynParamInt64
+ */
+void paramVal::setInteger64(epicsInt64 value)
+{
+ if (type != asynParamInt64)
+ throw ParamValWrongType("paramVal::setInteger64 can only handle asynParamInt64");
+ if (!isDefined() || (data.ival != value))
+ {
+ setDefined(true);
+ data.i64val = value;
+ setValueChanged();
+ }
+}
+
+/** Gets the value for a 64-bit integer in the parameter library.
+ * \throws ParamValWrongType if type is not asynParamInt64
+ * \throws paramValNotDefined if the value is not defined
+ */
+epicsInt64 paramVal::getInteger64()
+{
+ if (type != asynParamInt64)
+ throw ParamValWrongType("paramVal::getInteger64 can only handle asynParamInt64");
+ if (!isDefined())
+ throw ParamValNotDefined("paramVal::getInteger64 value not defined");
+ return data.i64val;
+}
+
/** Sets the value for a UInt32 in the parameter library.
* \param[in] value Value to set.
* \param[in] valueMask Mask to use when setting the value.
@@ -158,24 +189,38 @@ epicsInt32 paramVal::getInteger()
* \return Returns asynParamBadIndex if the index is not valid or asynParamWrongType if the parameter type is not asynParamUInt32Digital. */
void paramVal::setUInt32(epicsUInt32 value, epicsUInt32 valueMask, epicsUInt32 interruptMask)
{
- epicsUInt32 oldValue;
+ epicsUInt32 newValue;
if (type != asynParamUInt32Digital)
throw ParamValWrongType("paramVal::setUInt32 can only handle asynParamUInt32Digital");
- setDefined(true);
- oldValue = data.uival;
- /* Set any bits that are set in the value and the mask */
- data.uival |= (value & valueMask);
- /* Clear bits that are clear in the value and set in the mask */
- data.uival &= (value | ~valueMask);
- if (data.uival != oldValue) {
- /* Set the bits in the callback mask that have changed */
- uInt32CallbackMask |= (data.uival ^ oldValue);
- setValueChanged();
+
+ if (!isDefined())
+ {
+ /* Start from a known value for uival */
+ data.uival = 0;
+ setDefined(true);
+ /* Value has always changed if it became defined */
+ setValueChanged();
}
- if (interruptMask) {
- uInt32CallbackMask |= interruptMask;
- setValueChanged();
+
+ newValue = data.uival;
+ /* Clear bits covered by mask */
+ newValue &= ~valueMask;
+ /* Insert bits from value */
+ newValue |= (value & valueMask);
+
+ if (data.uival != newValue)
+ {
+ /* Set the bits in the callback mask that have changed */
+ uInt32CallbackMask |= (data.uival ^ newValue);
+ /* Update uival content */
+ data.uival = newValue;
+ setValueChanged();
+ }
+ if (interruptMask)
+ {
+ uInt32CallbackMask |= interruptMask;
+ setValueChanged();
}
}
@@ -258,6 +303,12 @@ void paramVal::report(int id, FILE *fp, int details)
else
fprintf(fp, "Parameter %d type=asynInt32, name=%s, value is undefined\n", id, getName());
break;
+ case asynParamInt64:
+ if (isDefined())
+ fprintf(fp, "Parameter %d type=asynInt64, name=%s, value=%lld, status=%d\n", id, getName(), getInteger64(), getStatus());
+ else
+ fprintf(fp, "Parameter %d type=asynInt64, name=%s, value is undefined\n", id, getName());
+ break;
case asynParamUInt32Digital:
if (isDefined())
fprintf(fp, "Parameter %d type=asynUInt32Digital, name=%s, value=0x%x, status=%d, risingMask=0x%x, fallingMask=0x%x, callbackMask=0x%x\n",
@@ -268,7 +319,7 @@ void paramVal::report(int id, FILE *fp, int details)
break;
case asynParamFloat64:
if (isDefined())
- fprintf(fp, "Parameter %d type=asynFloat64, name=%s, value=%f, status=%d\n", id, getName(), getDouble(), getStatus());
+ fprintf(fp, "Parameter %d type=asynFloat64, name=%s, value=%g, status=%d\n", id, getName(), getDouble(), getStatus());
else
fprintf(fp, "Parameter %d type=asynFloat64, name=%s, value is undefined\n", id, getName());
break;
@@ -296,6 +347,12 @@ void paramVal::report(int id, FILE *fp, int details)
else
fprintf(fp, "Parameter %d type=asynInt32Array, name=%s, value is undefined\n", id, getName());
break;
+ case asynParamInt64Array:
+ if (isDefined())
+ fprintf(fp, "Parameter %d type=asynInt64Array, name=%s, value=%p, status=%d\n", id, getName(), data.pi64, getStatus() );
+ else
+ fprintf(fp, "Parameter %d type=asynInt64Array, name=%s, value is undefined\n", id, getName());
+ break;
case asynParamFloat32Array:
if (isDefined())
fprintf(fp, "Parameter %d type=asynFloat32Array, name=%s, value=%p, status=%d\n", id, getName(), data.pf32, getStatus() );
diff --git a/asyn/asynPortDriver/paramVal.h b/asyn/asynPortDriver/paramVal.h
index 6ce1725..c7352d0 100644
--- a/asyn/asynPortDriver/paramVal.h
+++ b/asyn/asynPortDriver/paramVal.h
@@ -30,6 +30,8 @@ class paramVal {
bool nameEquals(const char* name);
void setInteger(epicsInt32 value);
epicsInt32 getInteger();
+ void setInteger64(epicsInt64 value);
+ epicsInt64 getInteger64();
void setUInt32(epicsUInt32 value, epicsUInt32 valueMask, epicsUInt32 interruptMask);
epicsUInt32 getUInt32(epicsUInt32 valueMask);
void setDouble(epicsFloat64 value);
@@ -56,11 +58,13 @@ class paramVal {
union
{
epicsInt32 ival;
+ epicsInt64 i64val;
epicsUInt32 uival;
epicsFloat64 dval;
epicsInt8 *pi8;
epicsInt16 *pi16;
epicsInt32 *pi32;
+ epicsInt64 *pi64;
epicsFloat32 *pf32;
epicsFloat64 *pf64;
void *pgp;
diff --git a/asyn/asynPortDriver/unittest/Makefile b/asyn/asynPortDriver/unittest/Makefile
index 8dde1dd..a8a257f 100644
--- a/asyn/asynPortDriver/unittest/Makefile
+++ b/asyn/asynPortDriver/unittest/Makefile
@@ -10,8 +10,17 @@ TOP=../../..
include $(TOP)/configure/CONFIG
+USR_CFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET -DUSE_TYPED_DRVET
+USR_CXXFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET -DUSE_TYPED_DRVET
+
PROD_LIBS += asyn
-PROD_LIBS += Com
+ifeq ($(EPICS_LIBCOM_ONLY),YES)
+ PROD_LIBS += Com
+ USR_CXXFLAGS += -DEPICS_LIBCOM_ONLY
+ USR_CFLAGS += -DEPICS_LIBCOM_ONLY
+else
+ PROD_LIBS += $(EPICS_BASE_IOC_LIBS)
+endif
#Tests for the parameters
#TESTPROD_HOST += ParamValTest
@@ -26,8 +35,27 @@ PROD_LIBS += Com
#tests for asynPortDriver
TESTPROD_HOST += asynPortDriverTest
asynPortDriverTest_SRCS += asynPortDriverTest.cpp
+testHarness_SRCS += asynPortDriverTest.cpp
TESTS += asynPortDriverTest
+
+# The testHarness runs all the test programs in a known working order.
+testHarness_SRCS += asynRunPortDriverTests.c
+
+asynPortDriverTestHarness_SRCS += $(testHarness_SRCS)
+asynPortDriverTestHarness_SRCS_RTEMS += rtemsTestHarness.c
+
+PROD_vxWorks = asynPortDriverTestHarness
+PROD_RTEMS += asynPortDriverTestHarness
+
+TESTSPEC_vxWorks = asynPortDriverTestHarness.munch; asynRunPortDriverTests
+TESTSPEC_RTEMS = asynPortDriverTestHarness.boot; asynRunPortDriverTests
+
+
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
+ifneq ($(filter $(T_A),$(CROSS_COMPILER_RUNTEST_ARCHS)),)
+TESTPROD = $(TESTPROD_HOST)
+TESTSCRIPTS += $(TESTS:%=%.t)
+endif
include $(TOP)/configure/RULES
diff --git a/asyn/asynPortDriver/unittest/asynPortDriverTest.cpp b/asyn/asynPortDriver/unittest/asynPortDriverTest.cpp
index 4744654..1b22000 100644
--- a/asyn/asynPortDriver/unittest/asynPortDriverTest.cpp
+++ b/asyn/asynPortDriver/unittest/asynPortDriverTest.cpp
@@ -16,9 +16,17 @@
#include
#include
-// fake out asynPortDriver callback dispatching
-extern "C" int interruptAccept;
-int interruptAccept=1;
+// Need interrupt accept from dbAccess.h unless asyn is built with EPICS_LIBCOM_ONLY
+#ifdef EPICS_LIBCOM_ONLY
+ static int interruptAccept;
+#else
+ #include
+#endif
+
+#ifdef __rtems__
+// no test data needed (when running individual CI tests)
+const void* epicsRtemsFSImage = 0;
+#endif
namespace {
@@ -81,6 +89,7 @@ void testA()
testOk1(portA->createParam(0, "int32", asynParamInt32, &idx2)==asynError);
+ testOk1(portA->createParam(0, "int64", asynParamInt64, &idx1)==asynSuccess);
testOk1(portA->createParam(0, "float64", asynParamFloat64, &idx1)==asynSuccess);
testOk1(portA->createParam(0, "uint32", asynParamUInt32Digital, &idx1)==asynSuccess);
testOk1(portA->createParam(0, "y", asynParamInt32, &idx1)==asynSuccess);
@@ -160,7 +169,7 @@ void testA()
MAIN(asynPortDriverTest)
{
- testPlan(53);
+ testPlan(54);
interruptAccept=1;
try {
testA();
diff --git a/asyn/asynPortDriver/unittest/asynRunPortDriverTests.c b/asyn/asynPortDriver/unittest/asynRunPortDriverTests.c
new file mode 100644
index 0000000..15d927c
--- /dev/null
+++ b/asyn/asynPortDriver/unittest/asynRunPortDriverTests.c
@@ -0,0 +1,31 @@
+/*************************************************************************\
+* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* Distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Run asynPortDriver tests as a batch.
+ *
+ * Do *not* include performance measurements here, they don't help to
+ * prove functionality (which is the point of this convenience routine).
+ */
+
+#include
+#include
+#include
+
+int asynPortDriverTest(void);
+
+void asynRunPortDriverTests(void)
+{
+ testHarness();
+
+ runTest(asynPortDriverTest);
+
+ /*
+ * Report now in case epicsExitTest dies
+ */
+ testHarnessDone();
+}
diff --git a/asyn/asynPortDriver/unittest/rtemsTestHarness.c b/asyn/asynPortDriver/unittest/rtemsTestHarness.c
new file mode 100644
index 0000000..47b68e3
--- /dev/null
+++ b/asyn/asynPortDriver/unittest/rtemsTestHarness.c
@@ -0,0 +1,19 @@
+/*************************************************************************\
+* Copyright (c) 2006 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* Distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+#include "epicsExit.h"
+#include "epicsGeneralTime.h"
+
+int
+main(int argc, char **argv)
+{
+ extern void asynRunPortDriverTests(void);
+ generalTimeReport(1);
+ asynRunPortDriverTests();
+ epicsExit(0);
+ return 0;
+}
diff --git a/asyn/asynRecord/asynRecord.c b/asyn/asynRecord/asynRecord.c
index a496460..f7d30b9 100644
--- a/asyn/asynRecord/asynRecord.c
+++ b/asyn/asynRecord/asynRecord.c
@@ -67,13 +67,14 @@ static char *drto_choices[NUM_DRTO_CHOICES] = {"Unknown", "N", "Y"};
#define OPT_SIZE 80 /* Size of buffer for setting and getting port options */
#define EOS_SIZE 10 /* Size of buffer for EOS */
#define ERR_SIZE 100 /* Size of buffer for error message */
+#define HOST_SIZE MAX_STRING_SIZE
#define QUEUE_TIMEOUT 10.0 /* Timeout for queueRequest */
-
+
/* Create RSET - Record Support Entry Table*/
#define report NULL
#define initialize NULL
-static long init_record(asynRecord * pasynRec, int pass);
-static long process(asynRecord * pasynRec);
+static long init_record(dbCommon * pasynRec, int pass);
+static long process(dbCommon * pasynRec);
static long special(struct dbAddr * paddr, int after);
#define get_value NULL
static long cvt_dbaddr(struct dbAddr * paddr);
@@ -81,7 +82,7 @@ static long get_array_info(struct dbAddr * paddr, long *no_elements,
long *offset);
static long put_array_info(struct dbAddr * paddr, long nNew);
#define get_units NULL
-static long get_precision(struct dbAddr * paddr, long *precision);
+static long get_precision(const struct dbAddr * paddr, long *precision);
#define get_enum_str NULL
#define get_enum_strs NULL
#define put_enum_str NULL
@@ -122,7 +123,7 @@ static void getEos(asynUser * pasynUser);
static void reportError(asynRecord * pasynRec, asynStatus status,
const char *pformat,...);
static void resetError(asynRecord * pasynRec);
-struct rset asynRSET = {
+rset asynRSET = {
RSETNUMBER,
report,
initialize,
@@ -142,7 +143,7 @@ struct rset asynRSET = {
get_control_double,
get_alarm_double};
epicsExportAddress(rset, asynRSET);
-
+
typedef struct oldValues { /* Used in monitor() and monitorStatus() */
epicsInt32 octetiv; /* asynOctet is valid */
epicsInt32 optioniv; /* asynOption is valid */
@@ -203,7 +204,7 @@ typedef struct oldValues { /* Used in monitor() and monitorStatus() */
epicsEnum16 auct; /* Autoconnect */
epicsEnum16 cnct; /* Connect/Disconnect */
epicsEnum16 enbl; /* Enable/Disable */
- char errs[ERR_SIZE + 1];/* Error string */
+ char errs[ERR_SIZE];/* Error string */
} oldValues;
#define REMEMBER_STATE(FIELD) pasynRecPvt->old.FIELD = pasynRec->FIELD
#define POST_IF_NEW(FIELD) \
@@ -215,7 +216,7 @@ typedef enum {
stateNoDevice, stateIdle, stateCancelIO, stateIO
} callbackState;
typedef enum {
- callbackConnect, callbackGetOption, callbackSetOption,
+ callbackConnect, callbackGetOption, callbackSetOption,
callbackGetEos, callbackSetEos
} callbackType;
typedef struct callbackMessage {
@@ -266,9 +267,10 @@ asynRecordDset asynRecordDevice = {
5,0,0,0,getIoIntInfo,0};
epicsExportAddress(dset, asynRecordDevice);
-
-static long init_record(asynRecord * pasynRec, int pass)
+
+static long init_record(dbCommon *pRec, int pass)
{
+ asynRecord *pasynRec = (asynRecord *)pRec;
asynRecPvt *pasynRecPvt;
asynUser *pasynUser;
asynStatus status;
@@ -297,7 +299,7 @@ static long init_record(asynRecord * pasynRec, int pass)
pasynRecPvt->outbuff = (char *) callocMustSucceed(
pasynRec->omax, sizeof(char), "asynRecord");
pasynRec->errs = (char *) callocMustSucceed(
- ERR_SIZE + 1, sizeof(char), "asynRecord");
+ ERR_SIZE, sizeof(char), "asynRecord");
pasynRec->udf = 0;
recGblResetAlarms(pasynRec); /* let initial state be no alarm */
strcpy(pasynRec->tfil, "Unknown");
@@ -316,9 +318,10 @@ static long init_record(asynRecord * pasynRec, int pass)
scanIoInit(&pasynRecPvt->ioScanPvt);
return (0);
}
-
-static long process(asynRecord * pasynRec)
+
+static long process(dbCommon *pRec)
{
+ asynRecord *pasynRec = (asynRecord *)pRec;
asynRecPvt *pasynRecPvt = pasynRec->dpvt;
callbackState state = pasynRecPvt->state;
asynStatus status;
@@ -335,7 +338,7 @@ static long process(asynRecord * pasynRec)
REMEMBER_STATE(nrrd);
resetError(pasynRec);
/* If we got value from interrupt no need to read */
- if(pasynRecPvt->gotValue) goto done;
+ if(pasynRecPvt->gotValue) goto done;
status = pasynManager->queueRequest(pasynRecPvt->pasynUser,
asynQueuePriorityLow, QUEUE_TIMEOUT);
if(status==asynSuccess) {
@@ -367,7 +370,7 @@ static long process(asynRecord * pasynRec)
pasynRecPvt->gotValue = 0;
return (0);
}
-
+
static long special(struct dbAddr * paddr, int after)
{
asynRecord *pasynRec = (asynRecord *) paddr->precord;
@@ -496,7 +499,7 @@ static long special(struct dbAddr * paddr, int after)
default:
break; /*handle other cases below*/
}
- if(fieldIndex == asynRecordPORT ||
+ if(fieldIndex == asynRecordPORT ||
fieldIndex == asynRecordADDR ||
fieldIndex == asynRecordDRVINFO) {
status = connectDevice(pasynRec);
@@ -513,7 +516,7 @@ static long special(struct dbAddr * paddr, int after)
}
return 0;
}
- if(fieldIndex == asynRecordPCNCT) {
+ if(fieldIndex == asynRecordPCNCT) {
if (pasynRec->pcnct) {
status = connectDevice(pasynRec);
} else {
@@ -523,12 +526,12 @@ static long special(struct dbAddr * paddr, int after)
}
return 0;
}
-
+
/* remaining cases must be handled by asynCallbackSpecial*/
pasynUserSpecial = pasynManager->duplicateAsynUser(pasynUser,
- asynCallbackSpecial,
+ asynCallbackSpecial,
queueTimeoutCallbackSpecial);
- pmsg = pasynUserSpecial->userData =
+ pmsg = pasynUserSpecial->userData =
(callbackMessage *)pasynManager->memMalloc(sizeof(*pmsg));
switch (fieldIndex) {
case asynRecordCNCT:
@@ -560,6 +563,11 @@ static long special(struct dbAddr * paddr, int after)
} else {
priority = asynQueuePriorityLow;
}
+ if (fieldIndex == asynRecordHOSTINFO) {
+ /* Enable changing host:port when not connected */
+ priority = asynQueuePriorityConnect;
+ pasynUserSpecial->reason = ASYN_REASON_QUEUE_EVEN_IF_NOT_CONNECTED;
+ }
status = pasynManager->queueRequest(pasynUserSpecial,
priority,QUEUE_TIMEOUT);
if(status!=asynSuccess) {
@@ -570,7 +578,7 @@ static long special(struct dbAddr * paddr, int after)
}
return 0;
}
-
+
static long getIoIntInfo(int cmd, dbCommon *pr, IOSCANPVT *iopvt)
{
asynRecord *pasynRec = (asynRecord *) pr;
@@ -796,7 +804,7 @@ static asynStatus cancelIOInterruptScan(asynRecord *pasynRec)
dbPutField(&pasynRecPvt->scanAddr,DBR_LONG,&passiveScan,1);
return(asynSuccess);
}
-
+
static void asynCallbackProcess(asynUser * pasynUser)
{
asynRecPvt *pasynRecPvt = pasynUser->userPvt;
@@ -865,8 +873,6 @@ static void asynCallbackSpecial(asynUser * pasynUser)
break;
}
- } else {
- monitorStatus(pasynRec);
}
} else {
if(isConnected) {
@@ -879,8 +885,6 @@ static void asynCallbackSpecial(asynUser * pasynUser)
break;
}
- } else {
- monitorStatus(pasynRec);
}
}
}
@@ -890,11 +894,12 @@ static void asynCallbackSpecial(asynUser * pasynUser)
"asynCallbackSpecial illegal type %d\n", callbackType);
status = asynError;
}
+ monitorStatus(pasynRec);
pasynManager->memFree(pmsg, sizeof(*pmsg));
pasynManager->freeAsynUser(pasynUser);
if (status == asynSuccess) pasynRecPvt->state = stateIdle;
}
-
+
static void exceptCallback(asynUser * pasynUser, asynException exception)
{
asynRecPvt *pasynRecPvt = pasynUser->userPvt;
@@ -931,7 +936,7 @@ static void queueTimeoutCallbackSpecial(asynUser * pasynUser)
pasynManager->memFree(pmsg, sizeof(*pmsg));
pasynManager->freeAsynUser(pasynUser);
}
-
+
static long cvt_dbaddr(struct dbAddr * paddr)
{
asynRecord *pasynRec = (asynRecord *) paddr->precord;
@@ -986,7 +991,7 @@ static long put_array_info(struct dbAddr * paddr, long nNew)
}
return (0);
}
-static long get_precision(struct dbAddr * paddr, long *precision)
+static long get_precision(const struct dbAddr * paddr, long *precision)
{
int fieldIndex = dbGetFieldIndex(paddr);
*precision = 0;
@@ -997,7 +1002,7 @@ static long get_precision(struct dbAddr * paddr, long *precision)
recGblGetPrec(paddr, precision);
return (0);
}
-
+
static void monitor(asynRecord * pasynRec)
{
/* Called when record processes for I/O operation */
@@ -1133,7 +1138,7 @@ static void monitorStatus(asynRecord * pasynRec)
POST_IF_NEW(ui32iv);
POST_IF_NEW(f64iv);
}
-
+
static asynStatus connectDevice(asynRecord * pasynRec)
{
asynInterface *pasynInterface;
@@ -1256,7 +1261,7 @@ static asynStatus connectDevice(asynRecord * pasynRec)
pasynRec->reason = 0;
/* If the DRVINFO field is not zero-length then print error */
if (strlen(pasynRec->drvinfo) > 0) {
- reportError(pasynRec, asynError,
+ reportError(pasynRec, asynError,
"asynDrvUser not supported but drvInfo not blank");
}
}
@@ -1269,12 +1274,13 @@ static asynStatus connectDevice(asynRecord * pasynRec)
pasynUserConnect = pasynManager->duplicateAsynUser(pasynUser,
asynCallbackSpecial, queueTimeoutCallbackSpecial);
pasynUserConnect->userData = pasynManager->memMalloc(sizeof(*pmsg));
+ pasynUserConnect->reason = ASYN_REASON_QUEUE_EVEN_IF_NOT_CONNECTED;
pmsg = (callbackMessage *)pasynUserConnect->userData;
pmsg->callbackType = callbackGetOption;
status = pasynManager->queueRequest(pasynUserConnect,
- asynQueuePriorityLow,QUEUE_TIMEOUT);
+ asynQueuePriorityConnect,QUEUE_TIMEOUT);
if(status!=asynSuccess) {
- reportError(pasynRec, asynError,
+ reportError(pasynRec, asynError,
"queueRequest failed\n");
pasynManager->memFree(pmsg, sizeof(*pmsg));
pasynManager->freeAsynUser(pasynUserConnect);
@@ -1290,13 +1296,13 @@ static asynStatus connectDevice(asynRecord * pasynRec)
status = pasynManager->queueRequest(pasynUserEos,
asynQueuePriorityLow,QUEUE_TIMEOUT);
if(status!=asynSuccess) {
- reportError(pasynRec, asynError,
+ reportError(pasynRec, asynError,
"queueRequest failed\n");
pasynManager->memFree(pmsg, sizeof(*pmsg));
pasynManager->freeAsynUser(pasynUserEos);
}
}
- pasynRec->pcnct = 1;
+ pasynRec->pcnct = 1;
status = asynSuccess;
goto done;
@@ -1310,10 +1316,10 @@ static asynStatus connectDevice(asynRecord * pasynRec)
done:
cancelIOInterruptScan(pasynRec);
- monitorStatus(pasynRec);
+ monitorStatus(pasynRec);
return(status);
}
-
+
static void performIO(asynUser * pasynUser)
{
asynRecPvt *pasynRecPvt = pasynUser->userPvt;
@@ -1354,7 +1360,7 @@ static void performIO(asynUser * pasynUser)
break;
}
}
-
+
static void performInt32IO(asynUser * pasynUser)
{
asynRecPvt *pasynRecPvt = pasynUser->userPvt;
@@ -1366,7 +1372,7 @@ static void performInt32IO(asynUser * pasynUser)
status = pasynRecPvt->pasynInt32->write(pasynRecPvt->asynInt32Pvt,
pasynUser, pasynRec->i32out);
asynPrint(pasynUser, ASYN_TRACEIO_DEVICE,
- "%s: status=%d, Int32 write data=%d\n",
+ "%s: status=%d, Int32 write data=%d\n",
pasynRec->name, status, pasynRec->i32out);
if(status != asynSuccess) {
reportError(pasynRec, status, "Int32 write error, %s",
@@ -1379,7 +1385,7 @@ static void performInt32IO(asynUser * pasynUser)
status = pasynRecPvt->pasynInt32->read(pasynRecPvt->asynInt32Pvt,
pasynUser, &pasynRec->i32inp);
asynPrint(pasynUser, ASYN_TRACEIO_DEVICE,
- "%s: status=%d, Int32 read data=%d\n",
+ "%s: status=%d, Int32 read data=%d\n",
pasynRec->name, status, pasynRec->i32inp);
if(status != asynSuccess) {
reportError(pasynRec, status, "Int32 read error, %s",
@@ -1402,7 +1408,7 @@ static void performUInt32DigitalIO(asynUser * pasynUser)
pasynUser, pasynRec->ui32out,
pasynRec->ui32mask);
asynPrint(pasynUser, ASYN_TRACEIO_DEVICE,
- "%s: status=%d, UInt32 write data=%d, mask=%d\n",
+ "%s: status=%d, UInt32 write data=%d, mask=%d\n",
pasynRec->name, status, pasynRec->ui32out, pasynRec->ui32mask);
if(status != asynSuccess) {
reportError(pasynRec, status, "UInt32 write error, %s",
@@ -1417,7 +1423,7 @@ static void performUInt32DigitalIO(asynUser * pasynUser)
pasynRec->ui32mask);
pasynRec->ui32inp = data;
asynPrint(pasynUser, ASYN_TRACEIO_DEVICE,
- "%s: status=%d, UInt32 read data=%d, mask=%d\n",
+ "%s: status=%d, UInt32 read data=%d, mask=%d\n",
pasynRec->name, status, pasynRec->i32inp, pasynRec->ui32mask);
if(status != asynSuccess) {
reportError(pasynRec, status, "UInt32 read error, %s",
@@ -1432,13 +1438,13 @@ static void performFloat64IO(asynUser * pasynUser)
asynRecPvt *pasynRecPvt = pasynUser->userPvt;
asynRecord *pasynRec = pasynRecPvt->prec;
asynStatus status;
-
+
if((pasynRec->tmod == asynTMOD_Write) ||
(pasynRec->tmod == asynTMOD_Write_Read)) {
status = pasynRecPvt->pasynFloat64->write(pasynRecPvt->asynFloat64Pvt,
pasynUser, pasynRec->f64out);
asynPrint(pasynUser, ASYN_TRACEIO_DEVICE,
- "%s: status=%d, Float64 write data=%f\n",
+ "%s: status=%d, Float64 write data=%f\n",
pasynRec->name, status, pasynRec->f64out);
if(status != asynSuccess) {
reportError(pasynRec, status, "Float64 write error, %s",
@@ -1451,7 +1457,7 @@ static void performFloat64IO(asynUser * pasynUser)
status = pasynRecPvt->pasynFloat64->read(pasynRecPvt->asynFloat64Pvt,
pasynUser, &pasynRec->f64inp);
asynPrint(pasynUser, ASYN_TRACEIO_DEVICE,
- "%s: status=%d, Float64 read data=%f\n",
+ "%s: status=%d, Float64 read data=%f\n",
pasynRec->name, status, pasynRec->f64inp);
if(status != asynSuccess) {
reportError(pasynRec, status, "Float64 read error, %s",
@@ -1505,7 +1511,7 @@ static void performOctetIO(asynUser * pasynUser)
}
/* Make sure nrrd is not more than inlen */
if(pasynRec->nrrd > (int)inlen) pasynRec->nrrd = (int)inlen;
- if(pasynRec->nrrd != 0)
+ if(pasynRec->nrrd != 0)
nread = pasynRec->nrrd;
else
nread = inlen;
@@ -1561,12 +1567,12 @@ static void performOctetIO(asynUser * pasynUser)
saveEosBuf,sizeof saveEosBuf,&saveEosLen);
/* getInputEos can return an error if the driver does not implement it */
if (status != asynSuccess) saveEosLen = 0;
- if (saveEosLen)
+ if (saveEosLen)
pasynRecPvt->pasynOctet->setInputEos(pasynRecPvt->asynOctetPvt,
pasynUser,NULL,0);
status = pasynRecPvt->pasynOctet->read(pasynRecPvt->asynOctetPvt,
pasynUser, inptr, nread, &nbytesTransfered,&eomReason);
- if (saveEosLen)
+ if (saveEosLen)
pasynRecPvt->pasynOctet->setInputEos(pasynRecPvt->asynOctetPvt,
pasynUser,saveEosBuf,saveEosLen);
} else {
@@ -1620,7 +1626,7 @@ static void performOctetIO(asynUser * pasynUser)
}
pasynRec->nord = (int)nbytesTransfered; /* Number of bytes read */
/* Copy to tinp with dbTranslateEscape */
- ntranslate = epicsStrSnPrintEscaped(pasynRec->tinp,
+ ntranslate = epicsStrSnPrintEscaped(pasynRec->tinp,
sizeof(pasynRec->tinp),
inptr, inlen);
asynPrint(pasynUser, ASYN_TRACEIO_DEVICE,
@@ -1628,7 +1634,7 @@ static void performOctetIO(asynUser * pasynUser)
pasynRec->name, (unsigned long)inlen, (unsigned long)nbytesTransfered, ntranslate);
}
}
-
+
static void gpibUniversalCmd(asynUser * pasynUser)
{
asynRecPvt *pasynRecPvt = pasynUser->userPvt;
@@ -1671,7 +1677,7 @@ static void gpibUniversalCmd(asynUser * pasynUser)
recGblSetSevr(pasynRec,WRITE_ALARM, MAJOR_ALARM);
}
}
-
+
static void gpibAddressedCmd(asynUser * pasynUser)
{
asynRecPvt *pasynRecPvt = pasynUser->userPvt;
@@ -1748,7 +1754,7 @@ static void gpibAddressedCmd(asynUser * pasynUser)
recGblSetSevr(pasynRec,WRITE_ALARM, MAJOR_ALARM);
}
}
-
+
static void setOption(asynUser * pasynUser)
{
asynRecPvt *pasynRecPvt = (asynRecPvt *) pasynUser->userPvt;
@@ -1830,6 +1836,7 @@ static void getOptions(asynUser * pasynUser)
asynRecPvt *pasynRecPvt = (asynRecPvt *) pasynUser->userPvt;
asynRecord *pasynRec = pasynRecPvt->prec;
char optbuff[OPT_SIZE];
+ char hostbuff[HOST_SIZE];
int i;
unsigned short monitor_mask = DBE_VALUE | DBE_LOG;
@@ -1852,7 +1859,7 @@ static void getOptions(asynUser * pasynUser)
REMEMBER_STATE(ixoff);
REMEMBER_STATE(ixany);
REMEMBER_STATE(drto);
- strncpy(pasynRecPvt->old.hostinfo, pasynRec->hostinfo, sizeof(pasynRec->hostinfo));
+ strncpy(pasynRecPvt->old.hostinfo, pasynRec->hostinfo, sizeof(pasynRecPvt->old.hostinfo));
/* Get port options */
pasynRecPvt->pasynOption->getOption(pasynRecPvt->asynOptionPvt, pasynUser,
"baud", optbuff, OPT_SIZE);
@@ -1916,8 +1923,8 @@ static void getOptions(asynUser * pasynUser)
if(strcmp(optbuff, drto_choices[i]) == 0)
pasynRec->drto = i;
pasynRecPvt->pasynOption->getOption(pasynRecPvt->asynOptionPvt, pasynUser,
- "hostinfo", optbuff, OPT_SIZE);
- strncpy(pasynRec->hostinfo, optbuff, sizeof(pasynRec->hostinfo));
+ "hostinfo", hostbuff, HOST_SIZE);
+ strncpy(pasynRec->hostinfo, hostbuff, sizeof(pasynRec->hostinfo));
POST_IF_NEW(baud);
POST_IF_NEW(lbaud);
POST_IF_NEW(prty);
@@ -1932,10 +1939,10 @@ static void getOptions(asynUser * pasynUser)
if (strncmp(pasynRec->hostinfo, pasynRecPvt->old.hostinfo, sizeof(pasynRec->hostinfo)) != 0) {
if(interruptAccept)
db_post_events(pasynRec, &pasynRec->hostinfo, monitor_mask);
- strncpy(pasynRecPvt->old.hostinfo, pasynRec->hostinfo, sizeof(pasynRec->hostinfo));
+ strncpy(pasynRecPvt->old.hostinfo, pasynRec->hostinfo, sizeof(pasynRecPvt->old.hostinfo));
}
}
-
+
static void setEos(asynUser * pasynUser)
{
@@ -1992,17 +1999,17 @@ static void getEos(asynUser * pasynUser)
/* If port does not have an asynOctet interface skip */
if (!pasynRec->octetiv) goto post;
- status = pasynRecPvt->pasynOctet->getInputEos(pasynRecPvt->asynOctetPvt,
+ status = pasynRecPvt->pasynOctet->getInputEos(pasynRecPvt->asynOctetPvt,
pasynUser, eosBuff, EOS_SIZE, &eosSize);
if ((status == asynSuccess) && (eosSize > 0)) {
- epicsStrSnPrintEscaped(inputEosTranslate,
+ epicsStrSnPrintEscaped(inputEosTranslate,
sizeof(inputEosTranslate),
eosBuff, eosSize);
}
- status = pasynRecPvt->pasynOctet->getOutputEos(pasynRecPvt->asynOctetPvt,
+ status = pasynRecPvt->pasynOctet->getOutputEos(pasynRecPvt->asynOctetPvt,
pasynUser, eosBuff, EOS_SIZE, &eosSize);
if ((status == asynSuccess) && (eosSize > 0)) {
- epicsStrSnPrintEscaped(outputEosTranslate,
+ epicsStrSnPrintEscaped(outputEosTranslate,
sizeof(outputEosTranslate),
eosBuff, eosSize);
}
@@ -2017,14 +2024,14 @@ static void getEos(asynUser * pasynUser)
}
}
-
+
static void reportError(asynRecord * pasynRec, asynStatus status,
const char *pformat,...)
{
asynRecPvt *pasynRecPvt = pasynRec->dpvt;
asynUser *pasynUser = pasynRecPvt->pasynUser;
unsigned short monitor_mask;
- char buffer[ERR_SIZE + 1];
+ char buffer[ERR_SIZE];
va_list pvar;
va_start(pvar, pformat);
epicsVsnprintf(buffer, ERR_SIZE, pformat, pvar);
@@ -2052,11 +2059,11 @@ static void resetError(asynRecord * pasynRec)
}
}
-
+
static const char * asynExceptionStrings[] = { ASYN_EXCEPTION_STRINGS };
const char * asynExceptionToString( asynException e )
{
- if ( e < 0 || e > asynExceptionTraceIOTruncateSize )
+ if ((size_t)e > asynExceptionTraceIOTruncateSize)
return "Invalid Exception Number!";
return asynExceptionStrings[e];
}
diff --git a/asyn/asynRecord/drvAsyn.c b/asyn/asynRecord/drvAsyn.c
index d14ccc9..90e1b6a 100644
--- a/asyn/asynRecord/drvAsyn.c
+++ b/asyn/asynRecord/drvAsyn.c
@@ -33,11 +33,8 @@
/* add support so that dbior generates asynDriver reports */
static long drvAsynReport(int level);
-struct {
- long number;
- DRVSUPFUN report;
- DRVSUPFUN init;
-} drvAsyn={
+
+drvet drvAsyn={
2,
drvAsynReport,
0
diff --git a/asyn/devEpics/asynCalc.dbd b/asyn/devEpics/asynCalc.dbd
new file mode 100644
index 0000000..27e30dc
--- /dev/null
+++ b/asyn/devEpics/asynCalc.dbd
@@ -0,0 +1,2 @@
+# support for EPICS calc module
+device(scalcout,INST_IO,asynScalcoutOctetWrite,"asynOctetWrite")
diff --git a/asyn/devEpics/asynEpicsUtils.c b/asyn/devEpics/asynEpicsUtils.c
index fd894a5..c24822f 100644
--- a/asyn/devEpics/asynEpicsUtils.c
+++ b/asyn/devEpics/asynEpicsUtils.c
@@ -22,26 +22,24 @@
#include
#include
-#define epicsExportSharedSymbols
-#include
#include "asynEpicsUtils.h"
-static asynStatus parseLink(asynUser *pasynUser, DBLINK *plink,
+static asynStatus parseLink(asynUser *pasynUser, DBLINK *plink,
char **port, int *addr, char **userParam);
-static asynStatus parseLinkMask(asynUser *pasynUser, DBLINK *plink,
+static asynStatus parseLinkMask(asynUser *pasynUser, DBLINK *plink,
char **port, int *addr, epicsUInt32 *mask,char **userParam);
static asynStatus parseLinkFree(asynUser *pasynUser,
char **port, char **userParam);
-static void asynStatusToEpicsAlarm(asynStatus status,
- epicsAlarmCondition defaultStat, epicsAlarmCondition *pStat,
+static void asynStatusToEpicsAlarm(asynStatus status,
+ epicsAlarmCondition defaultStat, epicsAlarmCondition *pStat,
epicsAlarmSeverity defaultSevr, epicsAlarmSeverity *pSevr);
static asynEpicsUtils utils = {
parseLink,parseLinkMask,parseLinkFree,asynStatusToEpicsAlarm
};
-epicsShareDef asynEpicsUtils *pasynEpicsUtils = &utils;
-
+asynEpicsUtils *pasynEpicsUtils = &utils;
+
/* parseLink syntax is:
VME_IO "C S @ userParams
INST_IO @asyn(wsws)userParams
@@ -54,7 +52,7 @@ static char *skipWhite(char *pstart,int commaOk){
return p;
}
-static asynStatus parseLink(asynUser *pasynUser, DBLINK *plink,
+static asynStatus parseLink(asynUser *pasynUser, DBLINK *plink,
char **port, int *addr, char **userParam)
{
struct vmeio *pvmeio;
@@ -86,10 +84,7 @@ static asynStatus parseLink(asynUser *pasynUser, DBLINK *plink,
if(*p) {
p = skipWhite(p,0);
if(*p) {
- len = strlen(p);
- *userParam = mallocMustSucceed(len+1,"asynEpicsUtils:parseLink");
- strncpy(*userParam,p,len);
- (*userParam)[len] = 0;
+ *userParam = epicsStrDup(p);
}
}
break;
@@ -139,10 +134,7 @@ static asynStatus parseLink(asynUser *pasynUser, DBLINK *plink,
if(*p) {
p = skipWhite(p,0);
if(userParam&& *p) {
- len = strlen(p);
- *userParam = mallocMustSucceed(len+1,"asynEpicsUtils:parseLink");
- strncpy(*userParam,p,len);
- (*userParam)[len] = 0;
+ *userParam = epicsStrDup(p);
}
}
break;
@@ -157,8 +149,8 @@ static asynStatus parseLink(asynUser *pasynUser, DBLINK *plink,
}
return(asynSuccess);
}
-
-static asynStatus parseLinkMask(asynUser *pasynUser, DBLINK *plink,
+
+static asynStatus parseLinkMask(asynUser *pasynUser, DBLINK *plink,
char **port, int *addr, epicsUInt32 *mask,char **userParam)
{
struct instio *pinstio;
@@ -221,10 +213,7 @@ static asynStatus parseLinkMask(asynUser *pasynUser, DBLINK *plink,
if(*p) {
p = skipWhite(p,0);
if(userParam&& *p) {
- len = strlen(p);
- *userParam = mallocMustSucceed(len+1,"asynEpicsUtils:parseLink");
- strncpy(*userParam,p,len);
- (*userParam)[len] = 0;
+ *userParam = epicsStrDup(p);
}
}
return(asynSuccess);
@@ -242,8 +231,8 @@ static asynStatus parseLinkFree(asynUser *pasynUser,
return(asynSuccess);
}
-static void asynStatusToEpicsAlarm(asynStatus status,
- epicsAlarmCondition defaultStat, epicsAlarmCondition *pStat,
+static void asynStatusToEpicsAlarm(asynStatus status,
+ epicsAlarmCondition defaultStat, epicsAlarmCondition *pStat,
epicsAlarmSeverity defaultSevr, epicsAlarmSeverity *pSevr)
{
switch (status) {
diff --git a/asyn/devEpics/asynEpicsUtils.h b/asyn/devEpics/asynEpicsUtils.h
index 192d4c6..0b7b97c 100644
--- a/asyn/devEpics/asynEpicsUtils.h
+++ b/asyn/devEpics/asynEpicsUtils.h
@@ -13,7 +13,6 @@
#define asynEpicsUtilsH
#include
-#include
#include
#include
#include "asynDriver.h"
@@ -23,17 +22,17 @@ extern "C" {
#endif /* __cplusplus */
typedef struct asynEpicsUtils {
- asynStatus (*parseLink)(asynUser *pasynUser, DBLINK *plink,
+ asynStatus (*parseLink)(asynUser *pasynUser, DBLINK *plink,
char **port, int *addr, char **userParam);
- asynStatus (*parseLinkMask)(asynUser *pasynUser, DBLINK *plink,
+ asynStatus (*parseLinkMask)(asynUser *pasynUser, DBLINK *plink,
char **port, int *addr, epicsUInt32 *mask,char **userParam);
- asynStatus (*parseLinkFree)(asynUser *pasynUser,
+ asynStatus (*parseLinkFree)(asynUser *pasynUser,
char **port, char **userParam);
- void (*asynStatusToEpicsAlarm)(asynStatus status,
- epicsAlarmCondition defaultStat, epicsAlarmCondition *pStat,
+ void (*asynStatusToEpicsAlarm)(asynStatus status,
+ epicsAlarmCondition defaultStat, epicsAlarmCondition *pStat,
epicsAlarmSeverity defaultSevr, epicsAlarmSeverity *pSevr);
} asynEpicsUtils;
-epicsShareExtern asynEpicsUtils *pasynEpicsUtils;
+ASYN_API extern asynEpicsUtils *pasynEpicsUtils;
#ifdef __cplusplus
}
diff --git a/asyn/devEpics/devAsynFloat32Array.c b/asyn/devEpics/devAsynFloat32Array.c
deleted file mode 100644
index 99869b3..0000000
--- a/asyn/devEpics/devAsynFloat32Array.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* devAsynFloat32Array.c */
-/***********************************************************************
-* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
-* National Laboratory, and the Regents of the University of
-* California, as Operator of Los Alamos National Laboratory, and
-* Berliner Elektronenspeicherring-Gesellschaft m.b.H. (BESSY).
-* asynDriver is distributed subject to a Software License Agreement
-* found in file LICENSE that is included with this distribution.
-***********************************************************************/
-/*
- Mark Rivers
- March 26, 2008
-*/
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include "asynDriver.h"
-#include "asynDrvUser.h"
-#include "asynFloat32Array.h"
-#include "asynEpicsUtils.h"
-
-#include "devAsynXXXArray.h"
-
-/* The code for this driver is generated by the macro in the include file with macro substitution */
-
-ASYN_XXX_ARRAY_FUNCS("devAsynFloat32Array", asynFloat32Array, asynFloat32ArrayType,
- interruptCallbackFloat32Array, epicsFloat32, asynFloat32ArrayWfIn, asynFloat32ArrayWfOut,
- menuFtypeFLOAT, menuFtypeFLOAT)
-
diff --git a/asyn/devEpics/devAsynFloat32Array.dbd b/asyn/devEpics/devAsynFloat32Array.dbd
deleted file mode 100644
index 45a0180..0000000
--- a/asyn/devEpics/devAsynFloat32Array.dbd
+++ /dev/null
@@ -1,2 +0,0 @@
-device(waveform,INST_IO,asynFloat32ArrayWfIn,"asynFloat32ArrayIn")
-device(waveform,INST_IO,asynFloat32ArrayWfOut,"asynFloat32ArrayOut")
diff --git a/asyn/devEpics/devAsynFloat64.c b/asyn/devEpics/devAsynFloat64.c
index 2333ac8..54ba154 100644
--- a/asyn/devEpics/devAsynFloat64.c
+++ b/asyn/devEpics/devAsynFloat64.c
@@ -12,7 +12,7 @@
14-OCT-2004
*/
-
+
#include
#include
#include
@@ -42,6 +42,7 @@
#include "asynFloat64SyncIO.h"
#include "asynEpicsUtils.h"
#include "asynFloat64.h"
+#include "devEpicsPvt.h"
#define INIT_OK 0
#define INIT_DO_NOT_CONVERT 2
@@ -74,6 +75,7 @@ typedef struct devPvt{
int ringSize;
int ringBufferOverflows;
ringBufferElement result;
+ asynStatus lastStatus;
epicsFloat64 sum;
interruptCallbackFloat64 interruptCallback;
int numAverage;
@@ -90,7 +92,7 @@ typedef struct devPvt{
int addr;
asynStatus previousQueueRequestStatus;
}devPvt;
-
+
static long initCommon(dbCommon *pr, DBLINK *plink,
userCallback processCallback,interruptCallbackFloat64 interruptCallback);
static long getIoIntInfo(int cmd, dbCommon *pr, IOSCANPVT *iopvt);
@@ -117,7 +119,7 @@ typedef struct analogDset { /* analog dset */
long number;
DEVSUPFUN dev_report;
DEVSUPFUN init;
- DEVSUPFUN init_record;
+ DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN processCommon;/*(0)=>(success ) */
DEVSUPFUN special_linconv;
@@ -133,7 +135,7 @@ analogDset asynAiFloat64Average = {
epicsExportAddress(dset, asynAiFloat64);
epicsExportAddress(dset, asynAoFloat64);
epicsExportAddress(dset, asynAiFloat64Average);
-
+
static long initCommon(dbCommon *pr, DBLINK *plink,
userCallback processCallback,interruptCallbackFloat64 interruptCallback)
{
@@ -143,7 +145,7 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
asynInterface *pasynInterface;
static const char *functionName="initCommon";
- pPvt = callocMustSucceed(1, sizeof(*pPvt), "%s::%s");
+ pPvt = callocMustSucceed(1, sizeof(*pPvt), "devAsynFloat64::initCommon");
pr->dpvt = pPvt;
pPvt->pr = pr;
/* Create asynUser */
@@ -209,20 +211,11 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
scanIoInit(&pPvt->ioScanPvt);
pPvt->interruptCallback = interruptCallback;
- /* If the info field "asyn:READBACK" is 1 and interruptCallback is not NULL
+ /* If the info field "asyn:READBACK" is 1 and interruptCallback is not NULL
* then register for callbacks on output records */
if (interruptCallback) {
int enableCallbacks=0;
- const char *callbackString;
- DBENTRY *pdbentry = dbAllocEntry(pdbbase);
- status = dbFindRecord(pdbentry, pr->name);
- if (status) {
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s error finding record\n",
- pr->name, driverName, functionName);
- goto bad;
- }
- callbackString = dbGetInfo(pdbentry, "asyn:READBACK");
+ const char *callbackString = asynDbGetInfo(pr, "asyn:READBACK");
if (callbackString) enableCallbacks = atoi(callbackString);
if (enableCallbacks) {
status = createRingBuffer(pr);
@@ -246,32 +239,22 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
pr->pact=1;
return INIT_ERROR;
}
-
+
static long createRingBuffer(dbCommon *pr)
{
devPvt *pPvt = (devPvt *)pr->dpvt;
- asynStatus status;
const char *sizeString;
- static const char *functionName="createRingBuffer";
-
+
if (!pPvt->ringBuffer) {
- DBENTRY *pdbentry = dbAllocEntry(pdbbase);
pPvt->ringSize = DEFAULT_RING_BUFFER_SIZE;
- status = dbFindRecord(pdbentry, pr->name);
- if (status) {
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s error finding record\n",
- pr->name, driverName, functionName);
- return -1;
- }
- sizeString = dbGetInfo(pdbentry, "asyn:FIFO");
+ sizeString = asynDbGetInfo(pr, "asyn:FIFO");
if (sizeString) pPvt->ringSize = atoi(sizeString);
- pPvt->ringBuffer = callocMustSucceed(pPvt->ringSize+1, sizeof *pPvt->ringBuffer, "%s::createRingBuffer");
+ pPvt->ringBuffer = callocMustSucceed(pPvt->ringSize+1, sizeof *pPvt->ringBuffer, "devAsynFloat64::createRingBuffer");
}
return asynSuccess;
}
-
+
static long getIoIntInfo(int cmd, dbCommon *pr, IOSCANPVT *iopvt)
{
devPvt *pPvt = (devPvt *)pr->dpvt;
@@ -331,12 +314,16 @@ static void processCallbackInput(asynUser *pasynUser)
pPvt->result.alarmSeverity = pPvt->pasynUser->alarmSeverity;
if (pPvt->result.status == asynSuccess) {
asynPrint(pasynUser, ASYN_TRACEIO_DEVICE,
- "%s %s::%s process value=%f\n",pr->name, driverName, functionName,pPvt->result.value);
+ "%s %s::%s process value=%f\n", pr->name, driverName, functionName,
+ pPvt->result.value);
} else {
- asynPrint(pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s process read error %s\n",
- pr->name, driverName, functionName,pasynUser->errorMessage);
+ if (pPvt->result.status != pPvt->lastStatus) {
+ asynPrint(pasynUser, ASYN_TRACE_ERROR,
+ "%s %s::%s process read error %s\n",
+ pr->name, driverName, functionName, pasynUser->errorMessage);
+ }
}
+ pPvt->lastStatus = pPvt->result.status;
if(pr->pact) callbackRequestProcessCallback(&pPvt->processCallback,pr->prio,pr);
}
@@ -352,15 +339,18 @@ static void processCallbackOutput(asynUser *pasynUser)
pPvt->result.alarmSeverity = pPvt->pasynUser->alarmSeverity;
if(pPvt->result.status == asynSuccess) {
asynPrint(pasynUser, ASYN_TRACEIO_DEVICE,
- "%s %s::%s process val %f\n",pr->name, driverName, functionName,pPvt->result.value);
+ "%s %s::%s process value %f\n", pr->name, driverName, functionName, pPvt->result.value);
} else {
- asynPrint(pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s pPvt->result.status=%d, process error %s\n",
- pr->name, driverName, functionName,pPvt->result.status, pasynUser->errorMessage);
+ if (pPvt->result.status != pPvt->lastStatus) {
+ asynPrint(pasynUser, ASYN_TRACE_ERROR,
+ "%s %s::%s process write error %s\n",
+ pr->name, driverName, functionName, pasynUser->errorMessage);
+ }
}
+ pPvt->lastStatus = pPvt->result.status;
if(pr->pact) callbackRequestProcessCallback(&pPvt->processCallback,pr->prio,pr);
}
-
+
static void interruptCallbackInput(void *drvPvt, asynUser *pasynUser,
epicsFloat64 value)
{
@@ -436,7 +426,7 @@ static void interruptCallbackOutput(void *drvPvt, asynUser *pasynUser,
* we must defer calling callbackRequest until end of record processing */
if (pPvt->asyncProcessingActive) {
pPvt->numDeferredOutputCallbacks++;
- } else {
+ } else {
callbackRequest(&pPvt->outputCallback);
}
}
@@ -445,7 +435,7 @@ static void interruptCallbackOutput(void *drvPvt, asynUser *pasynUser,
static void outputCallbackCallback(CALLBACK *pcb)
{
- devPvt *pPvt;
+ devPvt *pPvt;
static const char *functionName="outputCallbackCallback";
callbackGetUser(pPvt, pcb);
@@ -454,12 +444,14 @@ static void outputCallbackCallback(CALLBACK *pcb)
dbScanLock(pr);
epicsMutexLock(pPvt->devPvtLock);
pPvt->newOutputCallbackValue = 1;
+ /* We need to set udf=0 here so that it is already cleared when dbProcess is called */
+ pr->udf = 0;
dbProcess(pr);
if (pPvt->newOutputCallbackValue != 0) {
- /* We called dbProcess but the record did not process, perhaps because PACT was 1
+ /* We called dbProcess but the record did not process, perhaps because PACT was 1
* Need to remove ring buffer element */
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s warning dbProcess did not process record, PACT=%d\n",
+ asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
+ "%s %s::%s warning dbProcess did not process record, PACT=%d\n",
pr->name, driverName, functionName,pr->pact);
getCallbackValue(pPvt);
pPvt->newOutputCallbackValue = 0;
@@ -494,7 +486,7 @@ static void interruptCallbackAverage(void *drvPvt, asynUser *pasynUser,
* pai->sval is a double so it may not be completely safe to read without the lock? */
if ((pPvt->isIOIntrScan)) {
numToAverage = (int)(pai->sval + 0.5);
- if (numToAverage < 1) numToAverage = 1;
+ if (numToAverage < 1) numToAverage = 1;
if (pPvt->numAverage >= numToAverage) {
rp = &pPvt->ringBuffer[pPvt->ringHead];
rp->value = pPvt->sum/pPvt->numAverage;
@@ -517,14 +509,14 @@ static void interruptCallbackAverage(void *drvPvt, asynUser *pasynUser,
/* We only need to request the record to process if we added a new
* element to the ring buffer, not if we just replaced an element. */
scanIoRequest(pPvt->ioScanPvt);
- }
+ }
} /* End numAverage=SVAL, so time to compute average */
} /* End SCAN=I/O Intr */
- else {
+ else {
pPvt->result.status |= pasynUser->auxStatus;
pPvt->result.alarmStatus = pasynUser->alarmStatus;
pPvt->result.alarmSeverity = pasynUser->alarmSeverity;
- }
+ }
epicsMutexUnlock(pPvt->devPvtLock);
}
@@ -561,17 +553,17 @@ static void reportQueueRequestStatus(devPvt *pPvt, asynStatus status)
pPvt->previousQueueRequestStatus = status;
if (status == asynSuccess) {
asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s queueRequest status returned to normal\n",
+ "%s %s::%s queueRequest status returned to normal\n",
pPvt->pr->name, driverName, functionName);
} else {
asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s queueRequest error %s\n",
+ "%s %s::%s queueRequest error %s\n",
pPvt->pr->name, driverName, functionName,pPvt->pasynUser->errorMessage);
}
}
}
-
+
static long initAi(aiRecord *pai)
{
int status;
@@ -593,8 +585,8 @@ static long processAi(aiRecord *pr)
if(pPvt->canBlock) pr->pact = 0;
reportQueueRequestStatus(pPvt, status);
}
- pr->time = pPvt->result.time;
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pr->time = pPvt->result.time;
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
READ_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
@@ -616,7 +608,7 @@ static long processAi(aiRecord *pr)
}
}
-
+
static long initAo(aoRecord *pao)
{
devPvt *pPvt;
@@ -655,7 +647,6 @@ static long processAo(aoRecord *pr)
if (pr->aslo != 0.0) val64 *= pr->aslo;
val64 += pr->aoff;
pr->val = val64;
- pr->udf = 0;
}
} else if(pr->pact == 0) {
/* ASLO/AOFF conversion */
@@ -674,7 +665,7 @@ static long processAo(aoRecord *pr)
reportQueueRequestStatus(pPvt, status);
}
pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
- WRITE_ALARM, &pPvt->result.alarmStatus,
+ WRITE_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
if (pPvt->numDeferredOutputCallbacks > 0) {
@@ -692,7 +683,7 @@ static long processAo(aoRecord *pr)
return -1;
}
}
-
+
static long initAiAverage(aiRecord *pai)
{
int status;
@@ -725,8 +716,8 @@ static long processAiAverage(aiRecord *pai)
if (getCallbackValue(pPvt)) {
/* Record is I/O Intr scanned and the average has been put in the ring buffer */
dval = pPvt->result.value;
- pai->time = pPvt->result.time;
- } else {
+ pai->time = pPvt->result.time;
+ } else {
if (pPvt->numAverage == 0) {
recGblSetSevr(pai, UDF_ALARM, INVALID_ALARM);
pai->udf = 1;
@@ -738,7 +729,7 @@ static long processAiAverage(aiRecord *pai)
pPvt->sum = 0.;
}
epicsMutexUnlock(pPvt->devPvtLock);
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
READ_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
recGblSetSevr(pai, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
diff --git a/asyn/devEpics/devAsynFloat64Array.c b/asyn/devEpics/devAsynFloat64Array.c
deleted file mode 100644
index f865369..0000000
--- a/asyn/devEpics/devAsynFloat64Array.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* devAsynFloat64Array.c */
-/***********************************************************************
-* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
-* National Laboratory, and the Regents of the University of
-* California, as Operator of Los Alamos National Laboratory, and
-* Berliner Elektronenspeicherring-Gesellschaft m.b.H. (BESSY).
-* asynDriver is distributed subject to a Software License Agreement
-* found in file LICENSE that is included with this distribution.
-***********************************************************************/
-/*
- Mark Rivers
- March 26, 2008
-*/
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include "asynDriver.h"
-#include "asynDrvUser.h"
-#include "asynFloat64Array.h"
-#include "asynEpicsUtils.h"
-
-#include "devAsynXXXArray.h"
-
-/* The code for this driver is generated by the macro in the include file with macro substitution */
-
-ASYN_XXX_ARRAY_FUNCS("devAsynFloat64Array", asynFloat64Array, asynFloat64ArrayType,
- interruptCallbackFloat64Array, epicsFloat64, asynFloat64ArrayWfIn, asynFloat64ArrayWfOut,
- menuFtypeDOUBLE, menuFtypeDOUBLE)
-
diff --git a/asyn/devEpics/devAsynFloat64Array.dbd b/asyn/devEpics/devAsynFloat64Array.dbd
deleted file mode 100644
index 354ba9a..0000000
--- a/asyn/devEpics/devAsynFloat64Array.dbd
+++ /dev/null
@@ -1,2 +0,0 @@
-device(waveform,INST_IO,asynFloat64ArrayWfIn,"asynFloat64ArrayIn")
-device(waveform,INST_IO,asynFloat64ArrayWfOut,"asynFloat64ArrayOut")
diff --git a/asyn/devEpics/devAsynInt16Array.dbd b/asyn/devEpics/devAsynInt16Array.dbd
deleted file mode 100644
index 4955b6c..0000000
--- a/asyn/devEpics/devAsynInt16Array.dbd
+++ /dev/null
@@ -1,2 +0,0 @@
-device(waveform,INST_IO,asynInt16ArrayWfIn,"asynInt16ArrayIn")
-device(waveform,INST_IO,asynInt16ArrayWfOut,"asynInt16ArrayOut")
diff --git a/asyn/devEpics/devAsynInt32.c b/asyn/devEpics/devAsynInt32.c
index 8642948..d2dc420 100644
--- a/asyn/devEpics/devAsynInt32.c
+++ b/asyn/devEpics/devAsynInt32.c
@@ -54,6 +54,7 @@
#include "asynEnum.h"
#include "asynEnumSyncIO.h"
#include "asynEpicsUtils.h"
+#include "devEpicsPvt.h"
#define INIT_OK 0
#define INIT_DO_NOT_CONVERT 2
@@ -92,6 +93,7 @@ typedef struct devPvt{
int ringSize;
int ringBufferOverflows;
ringBufferElement result;
+ asynStatus lastStatus;
interruptCallbackInt32 interruptCallback;
double sum;
int numAverage;
@@ -114,9 +116,9 @@ typedef struct devPvt{
int enumSeverities[MAX_ENUM_STATES];
asynStatus previousQueueRequestStatus;
}devPvt;
-
-static void setEnums(char *outStrings, int *outVals, epicsEnum16 *outSeverities,
- char *inStrings[], int *inVals, int *inSeverities,
+
+static void setEnums(char *outStrings, int *outVals, epicsEnum16 *outSeverities,
+ char *inStrings[], int *inVals, int *inSeverities,
size_t numIn, size_t numOut);
static long getIoIntInfo(int cmd, dbCommon *pr, IOSCANPVT *iopvt);
static long createRingBuffer(dbCommon *pr);
@@ -190,7 +192,7 @@ epicsExportAddress(dset, asynBiInt32);
epicsExportAddress(dset, asynBoInt32);
epicsExportAddress(dset, asynMbbiInt32);
epicsExportAddress(dset, asynMbboInt32);
-
+
static long initCommon(dbCommon *pr, DBLINK *plink,
userCallback processCallback,interruptCallbackInt32 interruptCallback, interruptCallbackEnum callbackEnum,
int maxEnums, char *pFirstString, int *pFirstValue, epicsEnum16 *pFirstSeverity)
@@ -211,14 +213,14 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
pasynUser->userPvt = pPvt;
pPvt->pasynUser = pasynUser;
pPvt->devPvtLock = epicsMutexCreate();
-
+
/* Parse the link to get addr and port */
/* We accept 2 different link syntax (@asyn(...) and @asynMask(...)
* If parseLink returns an error then try parseLinkMask. */
- status = pasynEpicsUtils->parseLink(pasynUser, plink,
+ status = pasynEpicsUtils->parseLink(pasynUser, plink,
&pPvt->portName, &pPvt->addr, &pPvt->userParam);
if (status != asynSuccess) {
- status = pasynEpicsUtils->parseLinkMask(pasynUser, plink,
+ status = pasynEpicsUtils->parseLinkMask(pasynUser, plink,
&pPvt->portName, &pPvt->addr, &mask, &pPvt->userParam);
}
if (status != asynSuccess) {
@@ -226,7 +228,7 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
pr->name, driverName, functionName, pasynUser->errorMessage);
goto bad;
}
-
+
/* Parse nbits if it was specified */
nbits = (int)mask;
if (nbits) {
@@ -244,7 +246,7 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
pPvt->deviceHigh = pPvt->mask;
}
}
-
+
/* Connect to device */
status = pasynManager->connectDevice(pasynUser, pPvt->portName, pPvt->addr);
if (status != asynSuccess) {
@@ -285,7 +287,7 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
scanIoInit(&pPvt->ioScanPvt);
pPvt->interruptCallback = interruptCallback;
/* Initialize synchronous interface */
- status = pasynInt32SyncIO->connect(pPvt->portName, pPvt->addr,
+ status = pasynInt32SyncIO->connect(pPvt->portName, pPvt->addr,
&pPvt->pasynUserSync, pPvt->userParam);
if (status != asynSuccess) {
printf("%s %s::%s Int32SyncIO->connect failed %s\n",
@@ -298,7 +300,7 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
size_t numRead;
asynEnum *pasynEnum = pasynInterface->pinterface;
void *registrarPvt;
- status = pasynEnumSyncIO->connect(pPvt->portName, pPvt->addr,
+ status = pasynEnumSyncIO->connect(pPvt->portName, pPvt->addr,
&pPvt->pasynUserEnumSync, pPvt->userParam);
if (status != asynSuccess) {
printf("%s %s::%s EnumSyncIO->connect failed %s\n",
@@ -306,10 +308,10 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
goto bad;
}
status = pasynEnumSyncIO->read(pPvt->pasynUserEnumSync,
- pPvt->enumStrings, pPvt->enumValues, pPvt->enumSeverities, maxEnums,
+ pPvt->enumStrings, pPvt->enumValues, pPvt->enumSeverities, maxEnums,
&numRead, pPvt->pasynUser->timeout);
if (status == asynSuccess) {
- setEnums(pFirstString, pFirstValue, pFirstSeverity,
+ setEnums(pFirstString, pFirstValue, pFirstSeverity,
pPvt->enumStrings, pPvt->enumValues, pPvt->enumSeverities, numRead, maxEnums);
}
status = pasynEnum->registerInterruptUser(
@@ -320,20 +322,11 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
pr->name, driverName, functionName,pPvt->pasynUser->errorMessage);
}
}
- /* If the info field "asyn:READBACK" is 1 and interruptCallback is not NULL
+ /* If the info field "asyn:READBACK" is 1 and interruptCallback is not NULL
* then register for callbacks on output records */
if (interruptCallback) {
int enableCallbacks=0;
- const char *callbackString;
- DBENTRY *pdbentry = dbAllocEntry(pdbbase);
- status = dbFindRecord(pdbentry, pr->name);
- if (status) {
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s error finding record\n",
- pr->name, driverName, functionName);
- goto bad;
- }
- callbackString = dbGetInfo(pdbentry, "asyn:READBACK");
+ const char *callbackString = asynDbGetInfo(pr, "asyn:READBACK");
if (callbackString) enableCallbacks = atoi(callbackString);
if (enableCallbacks) {
status = createRingBuffer(pr);
@@ -357,25 +350,15 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
pr->pact=1;
return INIT_ERROR;
}
-
+
static long createRingBuffer(dbCommon *pr)
{
devPvt *pPvt = (devPvt *)pr->dpvt;
- asynStatus status;
const char *sizeString;
- static const char *functionName="createRingBuffer";
-
+
if (!pPvt->ringBuffer) {
- DBENTRY *pdbentry = dbAllocEntry(pdbbase);
pPvt->ringSize = DEFAULT_RING_BUFFER_SIZE;
- status = dbFindRecord(pdbentry, pr->name);
- if (status) {
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s error finding record\n",
- pr->name, driverName, functionName);
- return -1;
- }
- sizeString = dbGetInfo(pdbentry, "asyn:FIFO");
+ sizeString = asynDbGetInfo(pr, "asyn:FIFO");
if (sizeString) pPvt->ringSize = atoi(sizeString);
pPvt->ringBuffer = callocMustSucceed(pPvt->ringSize+1, sizeof *pPvt->ringBuffer, "devAsynInt32::createRingBuffer");
}
@@ -429,18 +412,23 @@ static long getIoIntInfo(int cmd, dbCommon *pr, IOSCANPVT *iopvt)
return 0;
}
-static void setEnums(char *outStrings, int *outVals, epicsEnum16 *outSeverities, char *inStrings[], int *inVals, int *inSeverities,
+static void setEnums(char *outStrings, int *outVals, epicsEnum16 *outSeverities, char *inStrings[], int *inVals, int *inSeverities,
size_t numIn, size_t numOut)
{
size_t i;
-
+
for (i=0; i MAX_ENUM_STRING_SIZE-1) len = MAX_ENUM_STRING_SIZE-1;
+ memcpy(&outStrings[i*MAX_ENUM_STRING_SIZE], inStrings[i], len);
+ outStrings[i*MAX_ENUM_STRING_SIZE + len] = '\0';
+ }
if (outVals) outVals[i] = inVals[i];
if (outSeverities) outSeverities[i] = inSeverities[i];
}
@@ -483,7 +471,7 @@ static long convertAo(aoRecord *precord, int pass)
}
return 0;
}
-
+
static void processCallbackInput(asynUser *pasynUser)
{
devPvt *pPvt = (devPvt *)pasynUser->userPvt;
@@ -500,12 +488,16 @@ static void processCallbackInput(asynUser *pasynUser)
}
if (pPvt->result.status == asynSuccess) {
asynPrint(pasynUser, ASYN_TRACEIO_DEVICE,
- "%s %s::%s process value=%d\n",pr->name, driverName, functionName,pPvt->result.value);
+ "%s %s::%s process value=%d\n", pr->name, driverName, functionName,
+ pPvt->result.value);
} else {
- asynPrint(pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s process read error %s\n",
- pr->name, driverName, functionName, pasynUser->errorMessage);
+ if (pPvt->result.status != pPvt->lastStatus) {
+ asynPrint(pasynUser, ASYN_TRACE_ERROR,
+ "%s %s::%s process read error %s\n",
+ pr->name, driverName, functionName, pasynUser->errorMessage);
+ }
}
+ pPvt->lastStatus = pPvt->result.status;
if(pr->pact) callbackRequestProcessCallback(&pPvt->processCallback,pr->prio,pr);
}
@@ -519,18 +511,22 @@ static void processCallbackOutput(asynUser *pasynUser)
pPvt->result.time = pPvt->pasynUser->timestamp;
pPvt->result.alarmStatus = pPvt->pasynUser->alarmStatus;
pPvt->result.alarmSeverity = pPvt->pasynUser->alarmSeverity;
- if(pPvt->result.status == asynSuccess) {
+ if (pPvt->result.status == asynSuccess) {
asynPrint(pasynUser, ASYN_TRACEIO_DEVICE,
- "%s %s::%s process value %d\n",pr->name, driverName, functionName,pPvt->result.value);
+ "%s %s::%s process value %d\n", pr->name, driverName, functionName,
+ pPvt->result.value);
} else {
- asynPrint(pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s process error %s\n",
- pr->name, driverName, functionName, pasynUser->errorMessage);
+ if (pPvt->result.status != pPvt->lastStatus) {
+ asynPrint(pasynUser, ASYN_TRACE_ERROR,
+ "%s %s::%s process write error %s\n",
+ pr->name, driverName, functionName, pasynUser->errorMessage);
+ }
}
+ pPvt->lastStatus = pPvt->result.status;
if(pr->pact) callbackRequestProcessCallback(&pPvt->processCallback,pr->prio,pr);
}
-static void interruptCallbackInput(void *drvPvt, asynUser *pasynUser,
+static void interruptCallbackInput(void *drvPvt, asynUser *pasynUser,
epicsInt32 value)
{
devPvt *pPvt = (devPvt *)drvPvt;
@@ -580,7 +576,7 @@ static void interruptCallbackInput(void *drvPvt, asynUser *pasynUser,
}
epicsMutexUnlock(pPvt->devPvtLock);
}
-
+
static void interruptCallbackOutput(void *drvPvt, asynUser *pasynUser,
epicsInt32 value)
{
@@ -613,7 +609,7 @@ static void interruptCallbackOutput(void *drvPvt, asynUser *pasynUser,
* we must defer calling callbackRequest until end of record processing */
if (pPvt->asyncProcessingActive) {
pPvt->numDeferredOutputCallbacks++;
- } else {
+ } else {
callbackRequest(&pPvt->outputCallback);
}
}
@@ -624,19 +620,21 @@ static void outputCallbackCallback(CALLBACK *pcb)
{
static const char *functionName="outputCallbackCallback";
- devPvt *pPvt;
+ devPvt *pPvt;
callbackGetUser(pPvt, pcb);
{
dbCommon *pr = pPvt->pr;
dbScanLock(pr);
epicsMutexLock(pPvt->devPvtLock);
pPvt->newOutputCallbackValue = 1;
+ /* We need to set udf=0 here so that it is already cleared when dbProcess is called */
+ pr->udf = 0;
dbProcess(pr);
if (pPvt->newOutputCallbackValue != 0) {
- /* We called dbProcess but the record did not process, perhaps because PACT was 1
+ /* We called dbProcess but the record did not process, perhaps because PACT was 1
* Need to remove ring buffer element */
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s warning dbProcess did not process record, PACT=%d\n",
+ asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
+ "%s %s::%s warning dbProcess did not process record, PACT=%d\n",
pr->name, driverName, functionName,pr->pact);
getCallbackValue(pPvt);
pPvt->newOutputCallbackValue = 0;
@@ -664,7 +662,7 @@ static void interruptCallbackAverage(void *drvPvt, asynUser *pasynUser,
pai->name, driverName, functionName, value);
if (!interruptAccept) return;
epicsMutexLock(pPvt->devPvtLock);
- pPvt->numAverage++;
+ pPvt->numAverage++;
pPvt->sum += (double)value;
/* We use the SVAL field to hold the number of values to average when SCAN=I/O Intr
* We should be calling dbScanLock when accessing pPvt->isIOIntrScan and pai->sval but that leads to deadlocks
@@ -674,7 +672,7 @@ static void interruptCallbackAverage(void *drvPvt, asynUser *pasynUser,
* pai->sval is a double so it may not be completely safe to read without the lock? */
if ((pPvt->isIOIntrScan)) {
numToAverage = (int)(pai->sval + 0.5);
- if (numToAverage < 1) numToAverage = 1;
+ if (numToAverage < 1) numToAverage = 1;
if (pPvt->numAverage >= numToAverage) {
double dval;
rp = &pPvt->ringBuffer[pPvt->ringHead];
@@ -700,10 +698,10 @@ static void interruptCallbackAverage(void *drvPvt, asynUser *pasynUser,
/* We only need to request the record to process if we added a new
* element to the ring buffer, not if we just replaced an element. */
scanIoRequest(pPvt->ioScanPvt);
- }
+ }
} /* End numAverage=SVAL, so time to compute average */
} /* End SCAN=I/O Intr */
- else {
+ else {
pPvt->result.status |= pasynUser->auxStatus;
pPvt->result.alarmStatus = pasynUser->alarmStatus;
pPvt->result.alarmSeverity = pasynUser->alarmSeverity;
@@ -719,7 +717,7 @@ static void interruptCallbackEnumMbbi(void *drvPvt, asynUser *pasynUser,
if (!interruptAccept) return;
dbScanLock((dbCommon*)pr);
- setEnums((char*)&pr->zrst, (int*)&pr->zrvl, &pr->zrsv,
+ setEnums((char*)&pr->zrst, (int*)&pr->zrvl, &pr->zrsv,
strings, values, severities, nElements, MAX_ENUM_STATES);
db_post_events(pr, &pr->val, DBE_PROPERTY);
dbScanUnlock((dbCommon*)pr);
@@ -733,7 +731,7 @@ static void interruptCallbackEnumMbbo(void *drvPvt, asynUser *pasynUser,
if (!interruptAccept) return;
dbScanLock((dbCommon*)pr);
- setEnums((char*)&pr->zrst, (int*)&pr->zrvl, &pr->zrsv,
+ setEnums((char*)&pr->zrst, (int*)&pr->zrvl, &pr->zrsv,
strings, values, severities, nElements, MAX_ENUM_STATES);
db_post_events(pr, &pr->val, DBE_PROPERTY);
dbScanUnlock((dbCommon*)pr);
@@ -747,7 +745,7 @@ static void interruptCallbackEnumBi(void *drvPvt, asynUser *pasynUser,
if (!interruptAccept) return;
dbScanLock((dbCommon*)pr);
- setEnums((char*)&pr->znam, NULL, &pr->zsv,
+ setEnums((char*)&pr->znam, NULL, &pr->zsv,
strings, NULL, severities, nElements, 2);
db_post_events(pr, &pr->val, DBE_PROPERTY);
dbScanUnlock((dbCommon*)pr);
@@ -761,7 +759,7 @@ static void interruptCallbackEnumBo(void *drvPvt, asynUser *pasynUser,
if (!interruptAccept) return;
dbScanLock((dbCommon*)pr);
- setEnums((char*)&pr->znam, NULL, &pr->zsv,
+ setEnums((char*)&pr->znam, NULL, &pr->zsv,
strings, NULL, severities, nElements, 2);
db_post_events(pr, &pr->val, DBE_PROPERTY);
dbScanUnlock((dbCommon*)pr);
@@ -800,17 +798,17 @@ static void reportQueueRequestStatus(devPvt *pPvt, asynStatus status)
pPvt->previousQueueRequestStatus = status;
if (status == asynSuccess) {
asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s queueRequest status returned to normal\n",
+ "%s %s::%s queueRequest status returned to normal\n",
pPvt->pr->name, driverName, functionName);
} else {
asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s queueRequest error %s\n",
+ "%s %s::%s queueRequest error %s\n",
pPvt->pr->name, driverName, functionName,pPvt->pasynUser->errorMessage);
}
}
}
-
+
static long initAi(aiRecord *pr)
{
devPvt *pPvt;
@@ -842,13 +840,13 @@ static long processAi(aiRecord *pr)
if(pPvt->canBlock) pr->pact = 0;
reportQueueRequestStatus(pPvt, status);
}
- pr->time = pPvt->result.time;
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pr->time = pPvt->result.time;
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
READ_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
(void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
if (pPvt->result.status == asynSuccess) {
- pr->rval = pPvt->result.value;
+ pr->rval = pPvt->result.value;
pr->udf = 0;
return 0;
}
@@ -856,7 +854,7 @@ static long processAi(aiRecord *pr)
return -1;
}
}
-
+
static long initAiAverage(aiRecord *pr)
{
devPvt *pPvt;
@@ -864,7 +862,7 @@ static long initAiAverage(aiRecord *pr)
static const char *functionName="initAiAverage";
status = initCommon((dbCommon *)pr, &pr->inp,
- NULL, interruptCallbackAverage, NULL,
+ NULL, interruptCallbackAverage, NULL,
0, NULL, NULL, NULL);
if (status != INIT_OK) return status;
pPvt = pr->dpvt;
@@ -897,8 +895,8 @@ static long processAiAverage(aiRecord *pr)
if (getCallbackValue(pPvt)) {
/* Record is I/O Intr scanned and the average has been put in the ring buffer */
rval = pPvt->result.value;
- pr->time = pPvt->result.time;
- } else {
+ pr->time = pPvt->result.time;
+ } else {
if (pPvt->numAverage == 0) {
(void)recGblSetSevr(pr, UDF_ALARM, INVALID_ALARM);
pr->udf = 1;
@@ -914,7 +912,7 @@ static long processAiAverage(aiRecord *pr)
epicsMutexUnlock(pPvt->devPvtLock);
asynPrint(pPvt->pasynUser, ASYN_TRACEIO_DEVICE,
"%s %s::%s rval=%d, status=%d\n",pr->name, driverName, functionName, pr->rval, pPvt->result.status);
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
READ_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
(void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
@@ -928,13 +926,13 @@ static long processAiAverage(aiRecord *pr)
return -1;
}
}
-
+
static long initAo(aoRecord *pao)
{
devPvt *pPvt;
int status;
epicsInt32 value;
-
+
status = initCommon((dbCommon *)pao,&pao->out,
processCallbackOutput,interruptCallbackOutput, NULL,
0, NULL, NULL, NULL);
@@ -967,13 +965,12 @@ static long processAo(aoRecord *pr)
asynStatus status;
double value;
static const char *functionName="processAo";
-
+
epicsMutexLock(pPvt->devPvtLock);
if (pPvt->newOutputCallbackValue && getCallbackValue(pPvt)) {
/* We got a callback from the driver */
if (pPvt->result.status == asynSuccess) {
pr->rval = pPvt->result.value;
- pr->udf = 0;
value = (double)pr->rval + (double)pr->roff;
if(pr->aslo!=0.0) value *= pr->aslo;
value += pr->aoff;
@@ -1009,7 +1006,7 @@ static long processAo(aoRecord *pr)
if(pPvt->canBlock) pr->pact = 0;
reportQueueRequestStatus(pPvt, status);
}
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
WRITE_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
(void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
@@ -1028,7 +1025,7 @@ static long processAo(aoRecord *pr)
return -1;
}
}
-
+
static long initLi(longinRecord *pr)
{
int status;
@@ -1053,7 +1050,7 @@ static long processLi(longinRecord *pr)
reportQueueRequestStatus(pPvt, status);
}
pr->time = pPvt->result.time;
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
READ_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
(void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
@@ -1067,7 +1064,7 @@ static long processLi(longinRecord *pr)
return -1;
}
}
-
+
static long initLo(longoutRecord *pr)
{
devPvt *pPvt;
@@ -1098,8 +1095,7 @@ static long processLo(longoutRecord *pr)
if (pPvt->newOutputCallbackValue && getCallbackValue(pPvt)) {
/* We got a callback from the driver */
if (pPvt->result.status == asynSuccess) {
- pr->val = pPvt->result.value;
- pr->udf = 0;
+ pr->val = pPvt->result.value;
}
} else if(pr->pact == 0) {
pPvt->result.value = pr->val;
@@ -1114,7 +1110,7 @@ static long processLo(longoutRecord *pr)
epicsMutexLock(pPvt->devPvtLock);
reportQueueRequestStatus(pPvt, status);
}
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
WRITE_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
(void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
@@ -1134,7 +1130,7 @@ static long processLo(longoutRecord *pr)
}
}
-
+
static long initBi(biRecord *pr)
{
int status;
@@ -1158,7 +1154,7 @@ static long processBi(biRecord *pr)
reportQueueRequestStatus(pPvt, status);
}
pr->time = pPvt->result.time;
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
READ_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
(void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
@@ -1172,7 +1168,7 @@ static long processBi(biRecord *pr)
return -1;
}
}
-
+
static long initBo(boRecord *pr)
{
devPvt *pPvt;
@@ -1205,7 +1201,6 @@ static long processBo(boRecord *pr)
if (pPvt->result.status == asynSuccess) {
pr->rval = pPvt->result.value;
pr->val = (pr->rval) ? 1 : 0;
- pr->udf = 0;
}
} else if(pr->pact == 0) {
pPvt->result.value = pr->rval;
@@ -1220,7 +1215,7 @@ static long processBo(boRecord *pr)
epicsMutexLock(pPvt->devPvtLock);
reportQueueRequestStatus(pPvt, status);
}
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
WRITE_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
(void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
@@ -1239,7 +1234,7 @@ static long processBo(boRecord *pr)
}
}
-
+
static long initMbbi(mbbiRecord *pr)
{
int status;
@@ -1266,7 +1261,7 @@ static long processMbbi(mbbiRecord *pr)
reportQueueRequestStatus(pPvt, status);
}
pr->time = pPvt->result.time;
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
READ_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
(void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
@@ -1280,7 +1275,7 @@ static long processMbbi(mbbiRecord *pr)
return -1;
}
}
-
+
static long initMbbo(mbboRecord *pr)
{
devPvt *pPvt;
@@ -1348,7 +1343,7 @@ static long processMbbo(mbboRecord *pr)
epicsMutexLock(pPvt->devPvtLock);
reportQueueRequestStatus(pPvt, status);
}
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
WRITE_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
(void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
diff --git a/asyn/devEpics/devAsynInt32Array.dbd b/asyn/devEpics/devAsynInt32Array.dbd
deleted file mode 100644
index dc8bc2e..0000000
--- a/asyn/devEpics/devAsynInt32Array.dbd
+++ /dev/null
@@ -1,2 +0,0 @@
-device(waveform,INST_IO,asynInt32ArrayWfIn,"asynInt32ArrayIn")
-device(waveform,INST_IO,asynInt32ArrayWfOut,"asynInt32ArrayOut")
diff --git a/asyn/devEpics/devAsynInt64.c b/asyn/devEpics/devAsynInt64.c
new file mode 100644
index 0000000..49e0c7e
--- /dev/null
+++ b/asyn/devEpics/devAsynInt64.c
@@ -0,0 +1,1040 @@
+/* devAsynInt64.c */
+/***********************************************************************
+* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
+* National Laboratory, and the Regents of the University of
+* California, as Operator of Los Alamos National Laboratory, and
+* Berliner Elektronenspeicherring-Gesellschaft m.b.H. (BESSY).
+* asynDriver is distributed subject to a Software License Agreement
+* found in file LICENSE that is included with this distribution.
+***********************************************************************/
+/*
+ Authors: Mark Rivers and Marty Kraimer
+ 05-Sept-2004
+*/
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include "epicsMath.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef HAVE_DEVINT64
+#include
+#include
+#endif
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include "asynDriver.h"
+#include "asynDrvUser.h"
+#include "asynInt64.h"
+#include "asynInt64SyncIO.h"
+#include "asynEpicsUtils.h"
+#include "devEpicsPvt.h"
+
+#define INIT_OK 0
+#define INIT_DO_NOT_CONVERT 2
+#define INIT_ERROR -1
+
+#define DEFAULT_RING_BUFFER_SIZE 10
+
+static const char *driverName = "devAsynInt64";
+
+typedef struct ringBufferElement {
+ epicsInt64 value;
+ epicsTimeStamp time;
+ asynStatus status;
+ epicsAlarmCondition alarmStatus;
+ epicsAlarmSeverity alarmSeverity;
+} ringBufferElement;
+
+typedef struct devPvt{
+ dbCommon *pr;
+ asynUser *pasynUser;
+ asynUser *pasynUserSync;
+ asynInt64 *pint64;
+ void *int64Pvt;
+ void *registrarPvt;
+ int canBlock;
+ epicsInt64 deviceLow;
+ epicsInt64 deviceHigh;
+ epicsMutexId devPvtLock;
+ ringBufferElement *ringBuffer;
+ int ringHead;
+ int ringTail;
+ int ringSize;
+ int ringBufferOverflows;
+ ringBufferElement result;
+ asynStatus lastStatus;
+ interruptCallbackInt64 interruptCallback;
+ double sum;
+ int numAverage;
+ int isAiAverage;
+ int isIOIntrScan;
+ int asyncProcessingActive;
+ int bipolar;
+ epicsInt32 mask;
+ epicsInt32 signBit;
+ CALLBACK processCallback;
+ CALLBACK outputCallback;
+ int newOutputCallbackValue;
+ int numDeferredOutputCallbacks;
+ IOSCANPVT ioScanPvt;
+ char *portName;
+ char *userParam;
+ int addr;
+ asynStatus previousQueueRequestStatus;
+}devPvt;
+
+static long getIoIntInfo(int cmd, dbCommon *pr, IOSCANPVT *iopvt);
+static long createRingBuffer(dbCommon *pr);
+static long convertAi(aiRecord *pai, int pass);
+static long convertAo(aoRecord *pao, int pass);
+static void processCallbackInput(asynUser *pasynUser);
+static void processCallbackOutput(asynUser *pasynUser);
+static void outputCallbackCallback(CALLBACK *pcb);
+static int getCallbackValue(devPvt *pPvt);
+static void interruptCallbackInput(void *drvPvt, asynUser *pasynUser,
+ epicsInt64 value);
+static void interruptCallbackOutput(void *drvPvt, asynUser *pasynUser,
+ epicsInt64 value);
+static void interruptCallbackAverage(void *drvPvt, asynUser *pasynUser,
+ epicsInt64 value);
+
+typedef struct analogDset { /* analog dset */
+ long number;
+ DEVSUPFUN dev_report;
+ DEVSUPFUN init;
+ DEVSUPFUN init_record;
+ DEVSUPFUN get_ioint_info;
+ DEVSUPFUN processCommon;/*(0)=>(success ) */
+ DEVSUPFUN special_linconv;
+} analogDset;
+
+#ifdef HAVE_DEVINT64
+static long initLLi(int64inRecord *pli);
+static long initLLo(int64outRecord *plo);
+static long processLLi(int64inRecord *pr);
+static long processLLo(int64outRecord *pr);
+
+analogDset asynInt64In = {
+ 5,0,0,initLLi, getIoIntInfo, processLLi };
+analogDset asynInt64Out = {
+ 5,0,0,initLLo, getIoIntInfo, processLLo };
+epicsExportAddress(dset, asynInt64In);
+epicsExportAddress(dset, asynInt64Out);
+#endif
+
+static long initAi(aiRecord *pai);
+static long initAiAverage(aiRecord *pai);
+static long initAo(aoRecord *pao);
+static long initLi(longinRecord *pli);
+static long initLo(longoutRecord *plo);
+
+static long processAi(aiRecord *pr);
+static long processAiAverage(aiRecord *pr);
+static long processAo(aoRecord *pr);
+static long processLi(longinRecord *pr);
+static long processLo(longoutRecord *pr);
+
+
+analogDset asynAiInt64 = {
+ 6,0,0,initAi, getIoIntInfo, processAi, convertAi };
+analogDset asynAiInt64Average = {
+ 6,0,0,initAiAverage,getIoIntInfo, processAiAverage , convertAi };
+analogDset asynAoInt64 = {
+ 6,0,0,initAo, getIoIntInfo, processAo , convertAo };
+analogDset asynLiInt64 = {
+ 5,0,0,initLi, getIoIntInfo, processLi };
+analogDset asynLoInt64 = {
+ 5,0,0,initLo, getIoIntInfo, processLo };
+epicsExportAddress(dset, asynAiInt64);
+epicsExportAddress(dset, asynAiInt64Average);
+epicsExportAddress(dset, asynAoInt64);
+epicsExportAddress(dset, asynLiInt64);
+epicsExportAddress(dset, asynLoInt64);
+
+static long initCommon(dbCommon *pr, DBLINK *plink,
+ userCallback processCallback,interruptCallbackInt64 interruptCallback)
+{
+ devPvt *pPvt;
+ asynStatus status;
+ asynUser *pasynUser;
+ asynInterface *pasynInterface;
+ static const char *functionName="initCommon";
+
+ pPvt = callocMustSucceed(1, sizeof(*pPvt), "devAsynInt64::initCommon");
+ pr->dpvt = pPvt;
+ pPvt->pr = pr;
+ /* Create asynUser */
+ pasynUser = pasynManager->createAsynUser(processCallback, 0);
+ pasynUser->userPvt = pPvt;
+ pPvt->pasynUser = pasynUser;
+ pPvt->devPvtLock = epicsMutexCreate();
+
+ /* Parse the link to get addr and port */
+ status = pasynEpicsUtils->parseLink(pasynUser, plink,
+ &pPvt->portName, &pPvt->addr, &pPvt->userParam);
+ if (status != asynSuccess) {
+ printf("%s %s::%s %s\n",
+ pr->name, driverName, functionName, pasynUser->errorMessage);
+ goto bad;
+ }
+
+ /* Connect to device */
+ status = pasynManager->connectDevice(pasynUser, pPvt->portName, pPvt->addr);
+ if (status != asynSuccess) {
+ printf("%s %s::%s connectDevice failed %s\n",
+ pr->name, driverName, functionName, pasynUser->errorMessage);
+ goto bad;
+ }
+ status = pasynManager->canBlock(pPvt->pasynUser, &pPvt->canBlock);
+ if (status != asynSuccess) {
+ printf("%s %s::%s canBlock failed %s\n",
+ pr->name, driverName, functionName, pasynUser->errorMessage);
+ goto bad;
+ }
+ /*call drvUserCreate*/
+ pasynInterface = pasynManager->findInterface(pasynUser,asynDrvUserType,1);
+ if(pasynInterface && pPvt->userParam) {
+ asynDrvUser *pasynDrvUser;
+ void *drvPvt;
+
+ pasynDrvUser = (asynDrvUser *)pasynInterface->pinterface;
+ drvPvt = pasynInterface->drvPvt;
+ status = pasynDrvUser->create(drvPvt,pasynUser,pPvt->userParam,0,0);
+ if(status!=asynSuccess) {
+ printf("%s %s::%s drvUserCreate %s\n",
+ pr->name, driverName, functionName, pasynUser->errorMessage);
+ goto bad;
+ }
+ }
+ /* Get interface asynInt64 */
+ pasynInterface = pasynManager->findInterface(pasynUser, asynInt64Type, 1);
+ if (!pasynInterface) {
+ printf("%s %s::%s findInterface asynInt64Type %s\n",
+ pr->name, driverName, functionName,pasynUser->errorMessage);
+ goto bad;
+ }
+ pPvt->pint64 = pasynInterface->pinterface;
+ pPvt->int64Pvt = pasynInterface->drvPvt;
+ scanIoInit(&pPvt->ioScanPvt);
+ pPvt->interruptCallback = interruptCallback;
+ /* Initialize synchronous interface */
+ status = pasynInt64SyncIO->connect(pPvt->portName, pPvt->addr,
+ &pPvt->pasynUserSync, pPvt->userParam);
+ if (status != asynSuccess) {
+ printf("%s %s::%s Int64SyncIO->connect failed %s\n",
+ pr->name, driverName, functionName, pPvt->pasynUserSync->errorMessage);
+ goto bad;
+ }
+ /* If the info field "asyn:READBACK" is 1 and interruptCallback is not NULL
+ * then register for callbacks on output records */
+ if (interruptCallback) {
+ int enableCallbacks=0;
+ const char *callbackString = asynDbGetInfo(pr, "asyn:READBACK");
+ if (callbackString) enableCallbacks = atoi(callbackString);
+ if (enableCallbacks) {
+ status = createRingBuffer(pr);
+ if (status!=asynSuccess) goto bad;
+ status = pPvt->pint64->registerInterruptUser(
+ pPvt->int64Pvt,pPvt->pasynUser,
+ pPvt->interruptCallback,pPvt,&pPvt->registrarPvt);
+ if (status!=asynSuccess) {
+ printf("%s %s::%s error calling registerInterruptUser %s\n",
+ pr->name, driverName, functionName,pPvt->pasynUser->errorMessage);
+ }
+ /* Initialize the interrupt callback */
+ callbackSetCallback(outputCallbackCallback, &pPvt->outputCallback);
+ callbackSetPriority(pr->prio, &pPvt->outputCallback);
+ callbackSetUser(pPvt, &pPvt->outputCallback);
+ }
+ }
+ return INIT_OK;
+bad:
+ recGblSetSevr(pr,LINK_ALARM,INVALID_ALARM);
+ pr->pact=1;
+ return INIT_ERROR;
+}
+
+static long createRingBuffer(dbCommon *pr)
+{
+ devPvt *pPvt = (devPvt *)pr->dpvt;
+ const char *sizeString;
+
+ if (!pPvt->ringBuffer) {
+ pPvt->ringSize = DEFAULT_RING_BUFFER_SIZE;
+ sizeString = asynDbGetInfo(pr, "asyn:FIFO");
+ if (sizeString) pPvt->ringSize = atoi(sizeString);
+ pPvt->ringBuffer = callocMustSucceed(pPvt->ringSize+1, sizeof *pPvt->ringBuffer, "devAsynInt64::createRingBuffer");
+ }
+ return asynSuccess;
+}
+
+static long getIoIntInfo(int cmd, dbCommon *pr, IOSCANPVT *iopvt)
+{
+ devPvt *pPvt = (devPvt *)pr->dpvt;
+ asynStatus status;
+ static const char *functionName="getIoIntInfo";
+
+ /* If initCommon failed then pPvt->pint64 is NULL, return error */
+ if (!pPvt->pint64) return -1;
+
+ if (cmd == 0) {
+ /* Add to scan list. Register interrupts */
+ asynPrint(pPvt->pasynUser, ASYN_TRACE_FLOW,
+ "%s %s::%s registering interrupt\n",
+ pr->name, driverName, functionName);
+ status = createRingBuffer(pr);
+ status = pPvt->pint64->registerInterruptUser(
+ pPvt->int64Pvt,pPvt->pasynUser,
+ pPvt->interruptCallback,pPvt,&pPvt->registrarPvt);
+ if(status!=asynSuccess) {
+ printf("%s %s::%s registerInterruptUser %s\n",
+ pr->name, driverName, functionName,pPvt->pasynUser->errorMessage);
+ }
+ } else {
+ asynPrint(pPvt->pasynUser, ASYN_TRACE_FLOW,
+ "%s %s::%s canceling interrupt\n",
+ pr->name, driverName, functionName);
+ status = pPvt->pint64->cancelInterruptUser(pPvt->int64Pvt,
+ pPvt->pasynUser,pPvt->registrarPvt);
+ if(status!=asynSuccess) {
+ printf("%s %s::%s cancelInterruptUser %s\n",
+ pr->name, driverName, functionName,pPvt->pasynUser->errorMessage);
+ }
+ }
+ *iopvt = pPvt->ioScanPvt;
+ return 0;
+}
+
+static long convertAi(aiRecord *precord, int pass)
+{
+ devPvt *pPvt = (devPvt *)precord->dpvt;
+ double eguf,egul,deviceHigh,deviceLow;
+
+ if (pass==0) return 0;
+ /* set linear conversion slope */
+ if(pPvt->deviceHigh!=pPvt->deviceLow) {
+ eguf = precord->eguf;
+ egul = precord->egul;
+ deviceHigh = (double)pPvt->deviceHigh;
+ deviceLow = (double)pPvt->deviceLow;
+ precord->eslo = (eguf - egul)/(deviceHigh - deviceLow);
+ precord->eoff = (deviceHigh*egul - deviceLow*eguf)/
+ (deviceHigh - deviceLow);
+ }
+ return 0;
+}
+
+static long convertAo(aoRecord *precord, int pass)
+{
+ devPvt *pPvt = (devPvt *)precord->dpvt;
+ double eguf,egul,deviceHigh,deviceLow;
+
+ if (pass==0) return 0;
+ /* set linear conversion slope */
+ if(pPvt->deviceHigh!=pPvt->deviceLow) {
+ eguf = precord->eguf;
+ egul = precord->egul;
+ deviceHigh = (double)pPvt->deviceHigh;
+ deviceLow = (double)pPvt->deviceLow;
+ precord->eslo = (eguf - egul)/(deviceHigh - deviceLow);
+ precord->eoff = (deviceHigh*egul - deviceLow*eguf)/
+ (deviceHigh - deviceLow);
+ }
+ return 0;
+}
+
+static void processCallbackInput(asynUser *pasynUser)
+{
+ devPvt *pPvt = (devPvt *)pasynUser->userPvt;
+ dbCommon *pr = (dbCommon *)pPvt->pr;
+ static const char *functionName="processCallbackInput";
+
+ pPvt->result.status = pPvt->pint64->read(pPvt->int64Pvt, pPvt->pasynUser, &pPvt->result.value);
+ pPvt->result.time = pPvt->pasynUser->timestamp;
+ pPvt->result.alarmStatus = pPvt->pasynUser->alarmStatus;
+ pPvt->result.alarmSeverity = pPvt->pasynUser->alarmSeverity;
+ if (pPvt->result.status == asynSuccess) {
+ asynPrint(pasynUser, ASYN_TRACEIO_DEVICE,
+ "%s %s::%s process value=%lld\n",pr->name, driverName, functionName,pPvt->result.value);
+ } else {
+ if (pPvt->result.status != pPvt->lastStatus) {
+ asynPrint(pasynUser, ASYN_TRACE_ERROR,
+ "%s %s::%s process read error %s\n",
+ pr->name, driverName, functionName, pasynUser->errorMessage);
+ }
+ }
+ pPvt->lastStatus = pPvt->result.status;
+ if(pr->pact) callbackRequestProcessCallback(&pPvt->processCallback,pr->prio,pr);
+}
+
+static void processCallbackOutput(asynUser *pasynUser)
+{
+ devPvt *pPvt = (devPvt *)pasynUser->userPvt;
+ dbCommon *pr = pPvt->pr;
+ static const char *functionName="processCallbackOutput";
+
+ pPvt->result.status = pPvt->pint64->write(pPvt->int64Pvt, pPvt->pasynUser,pPvt->result.value);
+ pPvt->result.time = pPvt->pasynUser->timestamp;
+ pPvt->result.alarmStatus = pPvt->pasynUser->alarmStatus;
+ pPvt->result.alarmSeverity = pPvt->pasynUser->alarmSeverity;
+ if(pPvt->result.status == asynSuccess) {
+ asynPrint(pasynUser, ASYN_TRACEIO_DEVICE,
+ "%s %s::%s process value %lld\n",pr->name, driverName, functionName,pPvt->result.value);
+ } else {
+ if (pPvt->result.status != pPvt->lastStatus) {
+ asynPrint(pasynUser, ASYN_TRACE_ERROR,
+ "%s %s::%s process error %s\n",
+ pr->name, driverName, functionName, pasynUser->errorMessage);
+ }
+ }
+ pPvt->lastStatus = pPvt->result.status;
+ if(pr->pact) callbackRequestProcessCallback(&pPvt->processCallback,pr->prio,pr);
+}
+
+static void interruptCallbackInput(void *drvPvt, asynUser *pasynUser,
+ epicsInt64 value)
+{
+ devPvt *pPvt = (devPvt *)drvPvt;
+ dbCommon *pr = pPvt->pr;
+ ringBufferElement *rp;
+ static const char *functionName="interruptCallbackInput";
+
+ asynPrint(pPvt->pasynUser, ASYN_TRACEIO_DEVICE,
+ "%s %s::%s new value=%lld\n",
+ pr->name, driverName, functionName, value);
+ /* There is a problem. A driver could be calling us with a value after
+ * this record has registered for callbacks but before EPICS has set interruptAccept,
+ * which means that scanIoRequest will return immediately.
+ * This is very bad, because if we have pushed a value into the ring buffer
+ * it won't get popped off because the record won't process. The values
+ * read the next time the record processes would then be stale.
+ * We previously worked around this problem by waiting here for interruptAccept.
+ * But that does not work if the callback is coming from the thread that is executing
+ * iocInit, which can happen with synchronous drivers (ASYN_CANBLOCK=0) that do callbacks
+ * when a value is written to them, which can happen in initRecord for an output record.
+ * Instead we just return. There will then be nothing in the ring buffer, so the first
+ * read will do a read from the driver, which should be OK. */
+ if (!interruptAccept) return;
+ epicsMutexLock(pPvt->devPvtLock);
+ rp = &pPvt->ringBuffer[pPvt->ringHead];
+ rp->value = value;
+ rp->time = pasynUser->timestamp;
+ rp->status = pasynUser->auxStatus;
+ rp->alarmStatus = pasynUser->alarmStatus;
+ rp->alarmSeverity = pasynUser->alarmSeverity;
+ pPvt->ringHead = (pPvt->ringHead==pPvt->ringSize) ? 0 : pPvt->ringHead+1;
+ if (pPvt->ringHead == pPvt->ringTail) {
+ /* There was no room in the ring buffer. In the past we just threw away
+ * the new value. However, it is better to remove the oldest value from the
+ * ring buffer and add the new one. That way the final value the record receives
+ * is guaranteed to be the most recent value */
+ pPvt->ringTail = (pPvt->ringTail==pPvt->ringSize) ? 0 : pPvt->ringTail+1;
+ pPvt->ringBufferOverflows++;
+ } else {
+ /* We only need to request the record to process if we added a new
+ * element to the ring buffer, not if we just replaced an element. */
+ scanIoRequest(pPvt->ioScanPvt);
+ }
+ epicsMutexUnlock(pPvt->devPvtLock);
+}
+
+static void interruptCallbackOutput(void *drvPvt, asynUser *pasynUser,
+ epicsInt64 value)
+{
+ devPvt *pPvt = (devPvt *)drvPvt;
+ dbCommon *pr = pPvt->pr;
+ ringBufferElement *rp;
+ static const char *functionName="interruptCallbackOutput";
+
+ asynPrint(pPvt->pasynUser, ASYN_TRACEIO_DEVICE,
+ "%s %s::%s new value=%lld\n",
+ pr->name, driverName, functionName, value);
+ if (!interruptAccept) return;
+ epicsMutexLock(pPvt->devPvtLock);
+ rp = &pPvt->ringBuffer[pPvt->ringHead];
+ rp->value = value;
+ rp->time = pasynUser->timestamp;
+ rp->status = pasynUser->auxStatus;
+ rp->alarmStatus = pasynUser->alarmStatus;
+ rp->alarmSeverity = pasynUser->alarmSeverity;
+ pPvt->ringHead = (pPvt->ringHead==pPvt->ringSize) ? 0 : pPvt->ringHead+1;
+ if (pPvt->ringHead == pPvt->ringTail) {
+ pPvt->ringTail = (pPvt->ringTail==pPvt->ringSize) ? 0 : pPvt->ringTail+1;
+ pPvt->ringBufferOverflows++;
+ } else {
+ /* If this callback was received during asynchronous record processing
+ * we must defer calling callbackRequest until end of record processing */
+ if (pPvt->asyncProcessingActive) {
+ pPvt->numDeferredOutputCallbacks++;
+ } else {
+ callbackRequest(&pPvt->outputCallback);
+ }
+ }
+ epicsMutexUnlock(pPvt->devPvtLock);
+}
+
+static void interruptCallbackAverage(void *drvPvt, asynUser *pasynUser,
+ epicsInt64 value)
+{
+ devPvt *pPvt = (devPvt *)drvPvt;
+ aiRecord *pai = (aiRecord *)pPvt->pr;
+ ringBufferElement *rp;
+ int numToAverage;
+ static const char *functionName="interruptCallbackAverage";
+
+ if (pPvt->mask) {
+ value &= pPvt->mask;
+ if (pPvt->bipolar && (value & pPvt->signBit)) value |= ~pPvt->mask;
+ }
+ asynPrint(pPvt->pasynUser, ASYN_TRACEIO_DEVICE,
+ "%s %s::%s new value=%lld\n",
+ pai->name, driverName, functionName, value);
+ if (!interruptAccept) return;
+ epicsMutexLock(pPvt->devPvtLock);
+ pPvt->numAverage++;
+ pPvt->sum += (double)value;
+ /* We use the SVAL field to hold the number of values to average when SCAN=I/O Intr
+ * We should be calling dbScanLock when accessing pPvt->isIOIntrScan and pai->sval but that leads to deadlocks
+ * because we have the asynPortDriver lock in the driver, and we would be taking the scan lock
+ * after the asynPortDriver lock, which is the opposite of normal record processing.
+ * pPvt->isIOIntrScan is an int, so should be OK to read because write to it is atomic?
+ * pai->sval is a double so it may not be completely safe to read without the lock? */
+ if ((pPvt->isIOIntrScan)) {
+ numToAverage = (int)(pai->sval + 0.5);
+ if (numToAverage < 1) numToAverage = 1;
+ if (pPvt->numAverage >= numToAverage) {
+ double dval;
+ rp = &pPvt->ringBuffer[pPvt->ringHead];
+ dval = pPvt->sum/pPvt->numAverage;
+ dval += (pPvt->sum>0.0) ? 0.5 : -0.5;
+ rp->value = (epicsInt32)dval;
+ pPvt->numAverage = 0;
+ pPvt->sum = 0.;
+ rp->time = pasynUser->timestamp;
+ rp->status = pasynUser->auxStatus;
+ rp->alarmStatus = pasynUser->alarmStatus;
+ rp->alarmSeverity = pasynUser->alarmSeverity;
+ pPvt->ringHead = (pPvt->ringHead==pPvt->ringSize) ? 0 : pPvt->ringHead+1;
+ if (pPvt->ringHead == pPvt->ringTail) {
+ /* There was no room in the ring buffer. In the past we just threw away
+ * the new value. However, it is better to remove the oldest value from the
+ * ring buffer and add the new one. That way the final value the record receives
+ * is guaranteed to be the most recent value */
+ pPvt->ringTail = (pPvt->ringTail==pPvt->ringSize) ? 0 : pPvt->ringTail+1;
+ pPvt->ringBufferOverflows++;
+ } /* End ring buffer full */
+ else {
+ /* We only need to request the record to process if we added a new
+ * element to the ring buffer, not if we just replaced an element. */
+ scanIoRequest(pPvt->ioScanPvt);
+ }
+ } /* End numAverage=SVAL, so time to compute average */
+ } /* End SCAN=I/O Intr */
+ else {
+ pPvt->result.status |= pasynUser->auxStatus;
+ pPvt->result.alarmStatus = pasynUser->alarmStatus;
+ pPvt->result.alarmSeverity = pasynUser->alarmSeverity;
+ }
+ epicsMutexUnlock(pPvt->devPvtLock);
+}
+
+static void outputCallbackCallback(CALLBACK *pcb)
+{
+ static const char *functionName="outputCallbackCallback";
+
+ devPvt *pPvt;
+ callbackGetUser(pPvt, pcb);
+ {
+ dbCommon *pr = pPvt->pr;
+ dbScanLock(pr);
+ epicsMutexLock(pPvt->devPvtLock);
+ pPvt->newOutputCallbackValue = 1;
+ /* We need to set udf=0 here so that it is already cleared when dbProcess is called */
+ pr->udf = 0;
+ dbProcess(pr);
+ if (pPvt->newOutputCallbackValue != 0) {
+ /* We called dbProcess but the record did not process, perhaps because PACT was 1
+ * Need to remove ring buffer element */
+ asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
+ "%s %s::%s warning dbProcess did not process record, PACT=%d\n",
+ pr->name, driverName, functionName,pr->pact);
+ getCallbackValue(pPvt);
+ pPvt->newOutputCallbackValue = 0;
+ }
+ epicsMutexUnlock(pPvt->devPvtLock);
+ dbScanUnlock(pr);
+ }
+}
+
+static int getCallbackValue(devPvt *pPvt)
+{
+ int ret = 0;
+ static const char *functionName="getCallbackValue";
+
+ epicsMutexLock(pPvt->devPvtLock);
+ if (pPvt->ringTail != pPvt->ringHead) {
+ if (pPvt->ringBufferOverflows > 0) {
+ asynPrint(pPvt->pasynUser, ASYN_TRACE_WARNING,
+ "%s %s::%s warning, %d ring buffer overflows\n",
+ pPvt->pr->name, driverName, functionName, pPvt->ringBufferOverflows);
+ pPvt->ringBufferOverflows = 0;
+ }
+ pPvt->result = pPvt->ringBuffer[pPvt->ringTail];
+ pPvt->ringTail = (pPvt->ringTail==pPvt->ringSize) ? 0 : pPvt->ringTail+1;
+ asynPrint(pPvt->pasynUser, ASYN_TRACEIO_DEVICE,
+ "%s %s::%s from ringBuffer value=%lld\n",
+ pPvt->pr->name, driverName, functionName,pPvt->result.value);
+ ret = 1;
+ }
+ epicsMutexUnlock(pPvt->devPvtLock);
+ return ret;
+}
+
+static void reportQueueRequestStatus(devPvt *pPvt, asynStatus status)
+{
+ static const char *functionName="reportQueueRequestStatus";
+
+ if (status != asynSuccess) pPvt->result.status = status;
+ if (pPvt->previousQueueRequestStatus != status) {
+ pPvt->previousQueueRequestStatus = status;
+ if (status == asynSuccess) {
+ asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
+ "%s %s::%s queueRequest status returned to normal\n",
+ pPvt->pr->name, driverName, functionName);
+ } else {
+ asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
+ "%s %s::%s queueRequest error %s\n",
+ pPvt->pr->name, driverName, functionName,pPvt->pasynUser->errorMessage);
+ }
+ }
+}
+
+#ifdef HAVE_DEVINT64
+static long initLLi(int64inRecord *pr)
+{
+ int status;
+
+ status = initCommon((dbCommon *)pr,&pr->inp,
+ processCallbackInput,interruptCallbackInput);
+
+ return status;
+}
+
+static long processLLi(int64inRecord *pr)
+{
+ devPvt *pPvt = (devPvt *)pr->dpvt;
+ int status;
+
+ if(!getCallbackValue(pPvt) && !pr->pact) {
+ if(pPvt->canBlock) pr->pact = 1;
+ status = pasynManager->queueRequest(pPvt->pasynUser, 0, 0);
+ if((status==asynSuccess) && pPvt->canBlock) return 0;
+ if(pPvt->canBlock) pr->pact = 0;
+ reportQueueRequestStatus(pPvt, status);
+ }
+ pr->time = pPvt->result.time;
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ READ_ALARM, &pPvt->result.alarmStatus,
+ INVALID_ALARM, &pPvt->result.alarmSeverity);
+ (void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
+ if(pPvt->result.status==asynSuccess) {
+ pr->val = pPvt->result.value;
+ pr->udf=0;
+ return 0;
+ }
+ else {
+ pPvt->result.status = asynSuccess;
+ return -1;
+ }
+}
+
+static long initLLo(int64outRecord *pr)
+{
+ devPvt *pPvt;
+ int status;
+ epicsInt64 value;
+
+ status = initCommon((dbCommon *)pr,&pr->out,
+ processCallbackOutput,interruptCallbackOutput);
+ if (status != INIT_OK) return status;
+ pPvt = pr->dpvt;
+ /* Read the current value from the device */
+ status = pasynInt64SyncIO->read(pPvt->pasynUserSync,
+ &value, pPvt->pasynUser->timeout);
+ if (status == asynSuccess) {
+ pr->val = value;
+ pr->udf = 0;
+ }
+ return INIT_OK;
+}
+
+static long processLLo(int64outRecord *pr)
+{
+ devPvt *pPvt = (devPvt *)pr->dpvt;
+ int status;
+
+ epicsMutexLock(pPvt->devPvtLock);
+ if (pPvt->newOutputCallbackValue && getCallbackValue(pPvt)) {
+ /* We got a callback from the driver */
+ if (pPvt->result.status == asynSuccess) {
+ pr->val = pPvt->result.value;
+ }
+ } else if(pr->pact == 0) {
+ pPvt->result.value = pr->val;
+ if(pPvt->canBlock) {
+ pr->pact = 1;
+ pPvt->asyncProcessingActive = 1;
+ }
+ epicsMutexUnlock(pPvt->devPvtLock);
+ status = pasynManager->queueRequest(pPvt->pasynUser, 0, 0);
+ if((status==asynSuccess) && pPvt->canBlock) return 0;
+ if(pPvt->canBlock) pr->pact = 0;
+ epicsMutexLock(pPvt->devPvtLock);
+ reportQueueRequestStatus(pPvt, status);
+ }
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ WRITE_ALARM, &pPvt->result.alarmStatus,
+ INVALID_ALARM, &pPvt->result.alarmSeverity);
+ (void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
+ if (pPvt->numDeferredOutputCallbacks > 0) {
+ callbackRequest(&pPvt->outputCallback);
+ pPvt->numDeferredOutputCallbacks--;
+ }
+ pPvt->newOutputCallbackValue = 0;
+ pPvt->asyncProcessingActive = 0;
+ epicsMutexUnlock(pPvt->devPvtLock);
+ if(pPvt->result.status == asynSuccess) {
+ return 0;
+ }
+ else {
+ pPvt->result.status = asynSuccess;
+ return -1;
+ }
+}
+#endif /* HAVE_DEVINT64 */
+
+static long initAi(aiRecord *pr)
+{
+ devPvt *pPvt;
+ int status;
+
+ status = initCommon((dbCommon *)pr,&pr->inp,
+ processCallbackInput,interruptCallbackInput);
+ if(status != INIT_OK) return status;
+ pPvt = pr->dpvt;
+ /* Don't call getBounds if we already have non-zero values from
+ * parseLinkMask */
+ if ((pPvt->deviceLow == 0) && (pPvt->deviceHigh == 0)) {
+ pasynInt64SyncIO->getBounds(pPvt->pasynUserSync,
+ &pPvt->deviceLow, &pPvt->deviceHigh);
+ }
+ convertAi(pr, 1);
+ return INIT_OK;
+}
+static long processAi(aiRecord *pr)
+{
+ devPvt *pPvt = (devPvt *)pr->dpvt;
+ int status;
+
+ if(!getCallbackValue(pPvt) && !pr->pact) {
+ if(pPvt->canBlock) pr->pact = 1;
+ status = pasynManager->queueRequest(pPvt->pasynUser, 0, 0);
+ if((status==asynSuccess) && pPvt->canBlock) return 0;
+ if(pPvt->canBlock) pr->pact = 0;
+ reportQueueRequestStatus(pPvt, status);
+ }
+ pr->time = pPvt->result.time;
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ READ_ALARM, &pPvt->result.alarmStatus,
+ INVALID_ALARM, &pPvt->result.alarmSeverity);
+ (void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
+ if (pPvt->result.status == asynSuccess) {
+ pr->val = (epicsFloat64)pPvt->result.value;
+ pr->udf = 0;
+ return 2;
+ }
+ else {
+ return -1;
+ }
+}
+
+static long initAiAverage(aiRecord *pr)
+{
+ devPvt *pPvt;
+ int status;
+ static const char *functionName="initAiAverage";
+
+ status = initCommon((dbCommon *)pr, &pr->inp,
+ NULL, interruptCallbackAverage);
+ if (status != INIT_OK) return status;
+ pPvt = pr->dpvt;
+ pPvt->isAiAverage = 1;
+ status = pPvt->pint64->registerInterruptUser(
+ pPvt->int64Pvt,pPvt->pasynUser,
+ interruptCallbackAverage,pPvt,&pPvt->registrarPvt);
+ if(status!=asynSuccess) {
+ printf("%s %s::%s registerInterruptUser %s\n",
+ pr->name, driverName, functionName,pPvt->pasynUser->errorMessage);
+ }
+ /* Don't call getBounds if we already have non-zero values from
+ * parseLinkMask */
+ if ((pPvt->deviceLow == 0) && (pPvt->deviceHigh == 0)) {
+ pasynInt64SyncIO->getBounds(pPvt->pasynUserSync,
+ &pPvt->deviceLow, &pPvt->deviceHigh);
+ }
+ convertAi(pr, 1);
+ return INIT_OK;
+}
+
+static long processAiAverage(aiRecord *pr)
+{
+ devPvt *pPvt = (devPvt *)pr->dpvt;
+ double val;
+ static const char *functionName="processAiAverage";
+
+ epicsMutexLock(pPvt->devPvtLock);
+
+ if (getCallbackValue(pPvt)) {
+ /* Record is I/O Intr scanned and the average has been put in the ring buffer */
+ val = (double)pPvt->result.value;
+ pr->time = pPvt->result.time;
+ } else {
+ if (pPvt->numAverage == 0) {
+ (void)recGblSetSevr(pr, UDF_ALARM, INVALID_ALARM);
+ pr->udf = 1;
+ epicsMutexUnlock(pPvt->devPvtLock);
+ return -2;
+ }
+ val = pPvt->sum/pPvt->numAverage;
+ pPvt->numAverage = 0;
+ pPvt->sum = 0.;
+ }
+ epicsMutexUnlock(pPvt->devPvtLock);
+ asynPrint(pPvt->pasynUser, ASYN_TRACEIO_DEVICE,
+ "%s %s::%s val=%f, status=%d\n",pr->name, driverName, functionName, val, pPvt->result.status);
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ READ_ALARM, &pPvt->result.alarmStatus,
+ INVALID_ALARM, &pPvt->result.alarmSeverity);
+ (void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
+ if (pPvt->result.status == asynSuccess) {
+ pr->val = val;
+ pr->udf = 0;
+ return 2;
+ }
+ else {
+ pPvt->result.status = asynSuccess;
+ return -1;
+ }
+}
+
+static long initAo(aoRecord *pao)
+{
+ devPvt *pPvt;
+ int status;
+ epicsInt64 value;
+
+ status = initCommon((dbCommon *)pao,&pao->out,
+ processCallbackOutput,interruptCallbackOutput);
+ if (status != INIT_OK) return status;
+ pPvt = pao->dpvt;
+ /* Don't call getBounds if we already have non-zero values from
+ * parseLinkMask */
+ if ((pPvt->deviceLow == 0) && (pPvt->deviceHigh == 0)) {
+ pasynInt64SyncIO->getBounds(pPvt->pasynUserSync,
+ &pPvt->deviceLow, &pPvt->deviceHigh);
+ }
+ convertAo(pao, 1);
+ /* Read the current value from the device */
+ status = pasynInt64SyncIO->read(pPvt->pasynUserSync,
+ &value, pPvt->pasynUser->timeout);
+ if (pPvt->mask) {
+ value &= pPvt->mask;
+ if (pPvt->bipolar && (value & pPvt->signBit)) value |= ~pPvt->mask;
+ }
+ if (status == asynSuccess) {
+ pao->val = (epicsFloat64)value;
+ return INIT_DO_NOT_CONVERT;
+ }
+ return INIT_DO_NOT_CONVERT; /* Do not convert */
+}
+
+static long processAo(aoRecord *pr)
+{
+ devPvt *pPvt = (devPvt *)pr->dpvt;
+ asynStatus status;
+ double value;
+ /* static const char *functionName="processAo"; */
+
+ epicsMutexLock(pPvt->devPvtLock);
+ if (pPvt->newOutputCallbackValue && getCallbackValue(pPvt)) {
+ /* We got a callback from the driver */
+ if (pPvt->result.status == asynSuccess) {
+ value = (double)pPvt->result.value;
+ if (pr->linr == menuConvertNO_CONVERSION){
+ ; /*do nothing*/
+ } else if ((pr->linr == menuConvertLINEAR) ||
+ (pr->linr == menuConvertSLOPE)) {
+ value = value*pr->eslo + pr->eoff;
+ }
+ pr->val = value;
+ pr->udf = isnan(value);
+ }
+ } else if(pr->pact == 0) {
+ pPvt->result.value = (epicsInt64)pr->val;
+ if(pPvt->canBlock) {
+ pr->pact = 1;
+ pPvt->asyncProcessingActive = 1;
+ }
+ epicsMutexUnlock(pPvt->devPvtLock);
+ status = pasynManager->queueRequest(pPvt->pasynUser, 0, 0);
+ if((status==asynSuccess) && pPvt->canBlock) return 0;
+ epicsMutexLock(pPvt->devPvtLock);
+ if(pPvt->canBlock) pr->pact = 0;
+ reportQueueRequestStatus(pPvt, status);
+ }
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ WRITE_ALARM, &pPvt->result.alarmStatus,
+ INVALID_ALARM, &pPvt->result.alarmSeverity);
+ (void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
+ if (pPvt->numDeferredOutputCallbacks > 0) {
+ callbackRequest(&pPvt->outputCallback);
+ pPvt->numDeferredOutputCallbacks--;
+ }
+ pPvt->newOutputCallbackValue = 0;
+ pPvt->asyncProcessingActive = 0;
+ epicsMutexUnlock(pPvt->devPvtLock);
+ if(pPvt->result.status == asynSuccess) {
+ return 0;
+ }
+ else {
+ pPvt->result.status = asynSuccess;
+ return -1;
+ }
+}
+
+static long initLi(longinRecord *pr)
+{
+ int status;
+
+ status = initCommon((dbCommon *)pr,&pr->inp,
+ processCallbackInput,interruptCallbackInput);
+
+ return status;
+}
+
+static long processLi(longinRecord *pr)
+{
+ devPvt *pPvt = (devPvt *)pr->dpvt;
+ int status;
+
+ if(!getCallbackValue(pPvt) && !pr->pact) {
+ if(pPvt->canBlock) pr->pact = 1;
+ status = pasynManager->queueRequest(pPvt->pasynUser, 0, 0);
+ if((status==asynSuccess) && pPvt->canBlock) return 0;
+ if(pPvt->canBlock) pr->pact = 0;
+ reportQueueRequestStatus(pPvt, status);
+ }
+ pr->time = pPvt->result.time;
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ READ_ALARM, &pPvt->result.alarmStatus,
+ INVALID_ALARM, &pPvt->result.alarmSeverity);
+ (void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
+ if(pPvt->result.status==asynSuccess) {
+ pr->val = (epicsInt32)pPvt->result.value;
+ pr->udf=0;
+ return 0;
+ }
+ else {
+ pPvt->result.status = asynSuccess;
+ return -1;
+ }
+}
+
+static long initLo(longoutRecord *pr)
+{
+ devPvt *pPvt;
+ int status;
+ epicsInt64 value;
+
+ status = initCommon((dbCommon *)pr,&pr->out,
+ processCallbackOutput,interruptCallbackOutput);
+ if (status != INIT_OK) return status;
+ pPvt = pr->dpvt;
+ /* Read the current value from the device */
+ status = pasynInt64SyncIO->read(pPvt->pasynUserSync,
+ &value, pPvt->pasynUser->timeout);
+ if (status == asynSuccess) {
+ pr->val = (epicsInt32)value;
+ pr->udf = 0;
+ }
+ return INIT_OK;
+}
+
+static long processLo(longoutRecord *pr)
+{
+ devPvt *pPvt = (devPvt *)pr->dpvt;
+ int status;
+
+ epicsMutexLock(pPvt->devPvtLock);
+ if (pPvt->newOutputCallbackValue && getCallbackValue(pPvt)) {
+ /* We got a callback from the driver */
+ if (pPvt->result.status == asynSuccess) {
+ pr->val = (epicsInt32)pPvt->result.value;
+ }
+ } else if(pr->pact == 0) {
+ pPvt->result.value = pr->val;
+ if(pPvt->canBlock) {
+ pr->pact = 1;
+ pPvt->asyncProcessingActive = 1;
+ }
+ epicsMutexUnlock(pPvt->devPvtLock);
+ status = pasynManager->queueRequest(pPvt->pasynUser, 0, 0);
+ if((status==asynSuccess) && pPvt->canBlock) return 0;
+ if(pPvt->canBlock) pr->pact = 0;
+ epicsMutexLock(pPvt->devPvtLock);
+ reportQueueRequestStatus(pPvt, status);
+ }
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ WRITE_ALARM, &pPvt->result.alarmStatus,
+ INVALID_ALARM, &pPvt->result.alarmSeverity);
+ (void)recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
+ if (pPvt->numDeferredOutputCallbacks > 0) {
+ callbackRequest(&pPvt->outputCallback);
+ pPvt->numDeferredOutputCallbacks--;
+ }
+ pPvt->newOutputCallbackValue = 0;
+ pPvt->asyncProcessingActive = 0;
+ epicsMutexUnlock(pPvt->devPvtLock);
+ if(pPvt->result.status == asynSuccess) {
+ return 0;
+ }
+ else {
+ pPvt->result.status = asynSuccess;
+ return -1;
+ }
+}
diff --git a/asyn/devEpics/devAsynInt64.dbd b/asyn/devEpics/devAsynInt64.dbd
new file mode 100644
index 0000000..88291f4
--- /dev/null
+++ b/asyn/devEpics/devAsynInt64.dbd
@@ -0,0 +1,2 @@
+device(int64in,INST_IO,asynInt64In,"asynInt64")
+device(int64out,INST_IO,asynInt64Out,"asynInt64")
diff --git a/asyn/devEpics/devAsynInt32Array.c b/asyn/devEpics/devAsynInt64Array.c
similarity index 80%
rename from asyn/devEpics/devAsynInt32Array.c
rename to asyn/devEpics/devAsynInt64Array.c
index 09c0ee8..76b342b 100644
--- a/asyn/devEpics/devAsynInt32Array.c
+++ b/asyn/devEpics/devAsynInt64Array.c
@@ -1,4 +1,4 @@
-/* devAsynInt32Array.c */
+/* devAsynInt64Array.c */
/***********************************************************************
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory, and the Regents of the University of
@@ -36,14 +36,14 @@
#include
#include "asynDriver.h"
#include "asynDrvUser.h"
-#include "asynInt32Array.h"
+#include "asynInt64Array.h"
#include "asynEpicsUtils.h"
#include "devAsynXXXArray.h"
/* The code for this driver is generated by the macro in the include file with macro substitution */
-ASYN_XXX_ARRAY_FUNCS("devAsynInt32Array", asynInt32Array, asynInt32ArrayType,
- interruptCallbackInt32Array, epicsInt32, asynInt32ArrayWfIn, asynInt32ArrayWfOut,
- menuFtypeLONG, menuFtypeULONG)
+ASYN_XXX_ARRAY_FUNCS("devAsynInt64Array", asynInt64Array, asynInt64ArrayType,
+ interruptCallbackInt64Array, epicsInt64, asynInt64ArrayWfIn, asynInt64ArrayWfOut,
+ menuFtypeINT64, menuFtypeUINT64)
diff --git a/asyn/devEpics/devAsynInt64Array.dbd b/asyn/devEpics/devAsynInt64Array.dbd
new file mode 100644
index 0000000..ed1ee87
--- /dev/null
+++ b/asyn/devEpics/devAsynInt64Array.dbd
@@ -0,0 +1,4 @@
+device(waveform, INST_IO, asynInt64ArrayWfIn, "asynInt64ArrayIn")
+device(waveform, INST_IO, asynInt64ArrayWfOut, "asynInt64ArrayOut")
+device(aai, INST_IO, asynInt64ArrayAai, "asynInt64ArrayIn")
+device(aao, INST_IO, asynInt64ArrayAao, "asynInt64ArrayOut")
diff --git a/asyn/devEpics/devAsynInt64Misc.dbd b/asyn/devEpics/devAsynInt64Misc.dbd
new file mode 100644
index 0000000..f018911
--- /dev/null
+++ b/asyn/devEpics/devAsynInt64Misc.dbd
@@ -0,0 +1,4 @@
+device(longin,INST_IO,asynLiInt64,"asynInt64")
+device(longout,INST_IO,asynLoInt64,"asynInt64")
+device(ai,INST_IO,asynAiInt64,"asynInt64")
+device(ao,INST_IO,asynAoInt64,"asynInt64")
diff --git a/asyn/devEpics/devAsynInt16Array.c b/asyn/devEpics/devAsynInt64TimeSeries.c
similarity index 75%
rename from asyn/devEpics/devAsynInt16Array.c
rename to asyn/devEpics/devAsynInt64TimeSeries.c
index 40053b6..a459e4c 100644
--- a/asyn/devEpics/devAsynInt16Array.c
+++ b/asyn/devEpics/devAsynInt64TimeSeries.c
@@ -1,4 +1,4 @@
-/* devAsynInt16Array.c */
+/* devAsynInt64Array.c */
/***********************************************************************
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory, and the Regents of the University of
@@ -9,19 +9,19 @@
***********************************************************************/
/*
Mark Rivers
- March 26, 2008
+ February 8, 2012
*/
#include
#include
#include
+#include
#include
#include
#include
#include
#include
-#include
#include
#include
#include
@@ -32,17 +32,18 @@
#include
#include
#include
+#include
#include
#include "asynDriver.h"
#include "asynDrvUser.h"
-#include "asynInt16Array.h"
#include "asynEpicsUtils.h"
-#include "devAsynXXXArray.h"
+#include "asynInt64.h"
+#include "devAsynXXXTimeSeries.h"
/* The code for this driver is generated by the macro in the include file with macro substitution */
-ASYN_XXX_ARRAY_FUNCS("devAsynInt16Array", asynInt16Array, asynInt16ArrayType,
- interruptCallbackInt16Array, epicsInt16, asynInt16ArrayWfIn, asynInt16ArrayWfOut,
- menuFtypeSHORT, menuFtypeUSHORT)
+ASYN_XXX_TIME_SERIES_FUNCS("devAsynInt64TimeSeries", asynInt64, asynInt64Type,
+ interruptCallbackInt64, epicsInt64, asynInt64TimeSeries,
+ menuFtypeINT64, menuFtypeUINT64)
diff --git a/asyn/devEpics/devAsynInt64TimeSeries.dbd b/asyn/devEpics/devAsynInt64TimeSeries.dbd
new file mode 100644
index 0000000..3784a7f
--- /dev/null
+++ b/asyn/devEpics/devAsynInt64TimeSeries.dbd
@@ -0,0 +1 @@
+device(waveform,INST_IO,asynInt64TimeSeries,"asynInt64TimeSeries")
diff --git a/asyn/devEpics/devAsynInt8Array.c b/asyn/devEpics/devAsynInt8Array.c
deleted file mode 100644
index e60c2a4..0000000
--- a/asyn/devEpics/devAsynInt8Array.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* devAsynInt8Array.c */
-/***********************************************************************
-* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
-* National Laboratory, and the Regents of the University of
-* California, as Operator of Los Alamos National Laboratory, and
-* Berliner Elektronenspeicherring-Gesellschaft m.b.H. (BESSY).
-* asynDriver is distributed subject to a Software License Agreement
-* found in file LICENSE that is included with this distribution.
-***********************************************************************/
-/*
- Mark Rivers
- March 26, 2008
-*/
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include "asynDriver.h"
-#include "asynDrvUser.h"
-#include "asynInt8Array.h"
-#include "asynEpicsUtils.h"
-
-#include "devAsynXXXArray.h"
-
-/* The code for this driver is generated by the macro in the include file with macro substitution */
-
-ASYN_XXX_ARRAY_FUNCS("devAsynInt8Array", asynInt8Array, asynInt8ArrayType,
- interruptCallbackInt8Array, epicsInt8, asynInt8ArrayWfIn, asynInt8ArrayWfOut,
- menuFtypeCHAR, menuFtypeUCHAR)
-
diff --git a/asyn/devEpics/devAsynInt8Array.dbd b/asyn/devEpics/devAsynInt8Array.dbd
deleted file mode 100644
index 956027c..0000000
--- a/asyn/devEpics/devAsynInt8Array.dbd
+++ /dev/null
@@ -1,2 +0,0 @@
-device(waveform,INST_IO,asynInt8ArrayWfIn,"asynInt8ArrayIn")
-device(waveform,INST_IO,asynInt8ArrayWfOut,"asynInt8ArrayOut")
diff --git a/asyn/devEpics/devAsynOctet.c b/asyn/devEpics/devAsynOctet.c
index 74b5d6e..d25fb81 100644
--- a/asyn/devEpics/devAsynOctet.c
+++ b/asyn/devEpics/devAsynOctet.c
@@ -11,7 +11,7 @@
Author: Marty Kraimer
02SEP2004
- This file provides device support for stringin, stringout, and waveform.
+ This file provides device support for stringin, stringout, lsi, lso, printf, scalcout and waveform.
NOTE: waveform must be a array of chars
asynSiOctetCmdResponse,asynWfOctetCmdResponse:
INP has a command string.
@@ -26,7 +26,7 @@
INP contains which is passed to asynDrvUser.create
VAL is sent
*/
-
+
#include
#include
#include
@@ -48,6 +48,14 @@
#include
#include
#include
+#ifdef HAVE_LSREC
+#include
+#include
+#include
+#endif /* HAVE_LSREC */
+#ifdef HAVE_CALCMOD
+#include "sCalcoutRecord.h"
+#endif /* HAVE_CALCMOD */
#include
#include
#include
@@ -58,6 +66,7 @@
#include "asynOctet.h"
#include "asynOctetSyncIO.h"
#include "asynEpicsUtils.h"
+#include "devEpicsPvt.h"
#define INIT_OK 0
#define INIT_ERROR -1
@@ -86,6 +95,7 @@ typedef struct devPvt {
char *userParam;
int isOutput;
int isWaveform;
+ epicsUInt32 *pLen; /* pointer to string length field to update, nord for waveform, len for lsi/lso/printf */
/* Following are for CmdResponse */
char *buffer;
size_t bufSize;
@@ -115,9 +125,10 @@ typedef struct devPvt {
interruptCallbackOctet interruptCallback;
asynStatus previousQueueRequestStatus;
} devPvt;
-
-static long initCommon(dbCommon *precord, DBLINK *plink, userCallback callback,
- int isOutput, int isWaveform, int useDrvUser, char *pValue, size_t valSize);
+
+static long initCommon(dbCommon *precord, DBLINK *plink, userCallback callback,
+ int isOutput, int isWaveform, int useDrvUser, char *pValue,
+ epicsUInt32* pLen, size_t valSize);
static long createRingBuffer(dbCommon *pr, int minRingSize);
static long getIoIntInfo(int cmd, dbCommon *pr, IOSCANPVT *iopvt);
static void outputCallbackCallback(CALLBACK *pcb);
@@ -126,7 +137,7 @@ static void interruptCallback(void *drvPvt, asynUser *pasynUser,
static int initDrvUser(devPvt *pPvt);
static int initCmdBuffer(devPvt *pPvt);
static int initDbAddr(devPvt *pPvt);
-static asynStatus writeIt(asynUser *pasynUser, const char *message,
+static asynStatus writeIt(asynUser *pasynUser, const char *message,
size_t nbytes);
static asynStatus readIt(asynUser *pasynUser, char *message,
size_t maxBytes, size_t *nBytesRead);
@@ -153,6 +164,25 @@ static void callbackWfWrite(asynUser *pasynUser);
static long initWfWriteBinary(waveformRecord *pwf);
static void callbackWfWriteBinary(asynUser *pasynUser);
+#ifdef HAVE_LSREC
+static long initLsiCmdResponse(lsiRecord *plsi);
+static void callbackLsiCmdResponse(asynUser *pasynUser);
+static long initLsiWriteRead(lsiRecord *plsi);
+static void callbackLsiWriteRead(asynUser *pasynUser);
+static long initLsiRead(lsiRecord *plsi);
+static void callbackLsiRead(asynUser *pasynUser);
+static long initLsoWrite(lsoRecord *plso);
+static void callbackLsoWrite(asynUser *pasynUser);
+
+static long initPfWrite(printfRecord *ppf);
+static void callbackPfWrite(asynUser *pasynUser);
+#endif /* HAVE_LSREC */
+
+#ifdef HAVE_CALCMOD
+static long initScalcoutWrite(scalcoutRecord *pscalcout);
+static void callbackScalcoutWrite(asynUser *pasynUser);
+#endif /* HAVE_CALCMOD */
+
typedef struct commonDset {
long number;
DEVSUPFUN dev_report;
@@ -180,6 +210,22 @@ commonDset asynWfOctetWrite = {
5, 0, 0, initWfWrite, 0, processCommon};
commonDset asynWfOctetWriteBinary = {
5, 0, 0, initWfWriteBinary, 0, processCommon};
+#ifdef HAVE_LSREC
+commonDset asynLsiOctetCmdResponse = {
+ 5, 0, 0, initLsiCmdResponse, 0, processCommon};
+commonDset asynLsiOctetWriteRead = {
+ 5, 0, 0, initLsiWriteRead, 0, processCommon};
+commonDset asynLsiOctetRead = {
+ 5, 0, 0, initLsiRead, getIoIntInfo, processCommon};
+commonDset asynLsoOctetWrite = {
+ 5, 0, 0, initLsoWrite, 0, processCommon};
+commonDset asynPfOctetWrite = {
+ 5, 0, 0, initPfWrite, 0, processCommon};
+#endif /* HAVE_LSREC */
+#ifdef HAVE_CALCMOD
+commonDset asynScalcoutOctetWrite = {
+ 5, 0, 0, initScalcoutWrite, 0, processCommon};
+#endif /* HAVE_CALCMOD */
epicsExportAddress(dset, asynSiOctetCmdResponse);
epicsExportAddress(dset, asynSiOctetWriteRead);
@@ -190,9 +236,20 @@ epicsExportAddress(dset, asynWfOctetWriteRead);
epicsExportAddress(dset, asynWfOctetRead);
epicsExportAddress(dset, asynWfOctetWrite);
epicsExportAddress(dset, asynWfOctetWriteBinary);
-
-static long initCommon(dbCommon *precord, DBLINK *plink, userCallback callback,
- int isOutput, int isWaveform, int useDrvUser, char *pValue, size_t valSize)
+#ifdef HAVE_LSREC
+epicsExportAddress(dset, asynLsiOctetCmdResponse);
+epicsExportAddress(dset, asynLsiOctetWriteRead);
+epicsExportAddress(dset, asynLsiOctetRead);
+epicsExportAddress(dset, asynLsoOctetWrite);
+epicsExportAddress(dset, asynPfOctetWrite);
+#endif /* HAVE_LSREC */
+#ifdef HAVE_CALCMOD
+epicsExportAddress(dset, asynScalcoutOctetWrite);
+#endif /* HAVE_CALCMOD */
+
+static long initCommon(dbCommon *precord, DBLINK *plink, userCallback callback,
+ int isOutput, int isWaveform, int useDrvUser, char *pValue,
+ epicsUInt32 *pLen, size_t valSize)
{
devPvt *pPvt;
asynStatus status;
@@ -201,7 +258,6 @@ static long initCommon(dbCommon *precord, DBLINK *plink, userCallback callback,
commonDset *pdset = (commonDset *)precord->dset;
asynOctet *poctet;
char *buffer;
- waveformRecord *pwf = (waveformRecord *)precord;
static const char *functionName="initCommon";
pPvt = callocMustSucceed(1,sizeof(*pPvt),"devAsynOctet::initCommon");
@@ -210,13 +266,14 @@ static long initCommon(dbCommon *precord, DBLINK *plink, userCallback callback,
pPvt->isOutput = isOutput;
pPvt->isWaveform = isWaveform;
pPvt->pValue = pValue;
+ pPvt->pLen = pLen;
pPvt->valSize = valSize;
pPvt->interruptCallback = interruptCallback;
/* Create asynUser */
pasynUser = pasynManager->createAsynUser(callback, 0);
pasynUser->userPvt = pPvt;
pPvt->pasynUser = pasynUser;
- status = pasynEpicsUtils->parseLink(pasynUser, plink,
+ status = pasynEpicsUtils->parseLink(pasynUser, plink,
&pPvt->portName, &pPvt->addr,&pPvt->userParam);
if (status != asynSuccess) {
printf("%s %s::%s error in link %s\n",
@@ -251,40 +308,33 @@ static long initCommon(dbCommon *precord, DBLINK *plink, userCallback callback,
}
if (pPvt->isWaveform) {
+ waveformRecord *pwf = (waveformRecord *)precord;
if(pwf->ftvl!=menuFtypeCHAR && pwf->ftvl!=menuFtypeUCHAR) {
printf("%s FTVL Must be CHAR or UCHAR\n",pwf->name);
pwf->pact = 1;
goto bad;
- }
- if(pwf->nelm<=0) {
- printf("%s NELM must be > 0\n",pwf->name);
- pwf->pact = 1;
- goto bad;
}
}
+ if(valSize <= 0) {
+ printf("%s record size must be > 0\n",precord->name);
+ precord->pact = 1;
+ goto bad;
+ }
- /* If this is an output record
+ /* If this is an output record
* - If the info field "asyn:INITIAL_READBACK" is 1 then try to read the initial value from the driver
- * - If the info field "asyn:READBACK" is 1 then register for callbacks
+ * - If the info field "asyn:READBACK" is 1 then register for callbacks
*/
if (pPvt->isOutput) {
int enableReadbacks = 0;
const char *readbackString;
int enableInitialReadback = 0;
const char *initialReadbackString;
- DBENTRY *pdbentry = dbAllocEntry(pdbbase);
size_t nBytesRead;
int eomReason;
asynUser *pasynUserSync;
- status = dbFindRecord(pdbentry, precord->name);
- if (status) {
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s error finding record\n",
- precord->name, driverName, functionName);
- goto bad;
- }
- readbackString = dbGetInfo(pdbentry, "asyn:READBACK");
+ readbackString = asynDbGetInfo(precord, "asyn:READBACK");
if (readbackString) enableReadbacks = atoi(readbackString);
if (enableReadbacks) {
/* If enableReabacks is set we will get a deadlock if not using ring buffer.
@@ -304,11 +354,11 @@ static long initCommon(dbCommon *precord, DBLINK *plink, userCallback callback,
callbackSetUser(pPvt, &pPvt->outputCallback);
}
- initialReadbackString = dbGetInfo(pdbentry, "asyn:INITIAL_READBACK");
+ initialReadbackString = asynDbGetInfo(precord, "asyn:INITIAL_READBACK");
if (initialReadbackString) enableInitialReadback = atoi(initialReadbackString);
if (enableInitialReadback) {
/* Initialize synchronous interface */
- status = pasynOctetSyncIO->connect(pPvt->portName, pPvt->addr,
+ status = pasynOctetSyncIO->connect(pPvt->portName, pPvt->addr,
&pasynUserSync, pPvt->userParam);
if (status != asynSuccess) {
printf("%s %s::%s octetSyncIO->connect failed %s\n",
@@ -323,13 +373,16 @@ static long initCommon(dbCommon *precord, DBLINK *plink, userCallback callback,
if (nBytesRead == valSize) nBytesRead--;
buffer[nBytesRead] = 0;
strcpy(pValue, buffer);
- if (pPvt->isWaveform) pwf->nord = nBytesRead;
+ if (pPvt->pLen != NULL)
+ {
+ *(pPvt->pLen) = (epicsUInt32)(pPvt->isWaveform ? nBytesRead : nBytesRead + 1); /* lsi, lso and printf count \0 in length */
+ }
}
free(buffer);
pasynOctetSyncIO->disconnect(pasynUserSync);
}
}
-
+
return(INIT_OK);
bad:
@@ -338,32 +391,22 @@ static long initCommon(dbCommon *precord, DBLINK *plink, userCallback callback,
return(INIT_ERROR);
}
-
+
static long createRingBuffer(dbCommon *pr, int minRingSize)
{
devPvt *pPvt = (devPvt *)pr->dpvt;
- asynStatus status;
int i;
const char *sizeString;
- static const char *functionName="createRingBuffer";
-
+
if (!pPvt->ringBuffer) {
- DBENTRY *pdbentry = dbAllocEntry(pdbbase);
- status = dbFindRecord(pdbentry, pr->name);
- if (status) {
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s error finding record\n",
- pr->name, driverName, functionName);
- return -1;
- }
pPvt->ringSize = minRingSize;
- sizeString = dbGetInfo(pdbentry, "asyn:FIFO");
+ sizeString = asynDbGetInfo(pr, "asyn:FIFO");
if (sizeString) pPvt->ringSize = atoi(sizeString);
if (pPvt->ringSize > 0) {
- pPvt->ringBuffer = callocMustSucceed(pPvt->ringSize+1, sizeof *pPvt->ringBuffer,
+ pPvt->ringBuffer = callocMustSucceed(pPvt->ringSize+1, sizeof *pPvt->ringBuffer,
"devAsynOctet::createRingBuffer");
/* Allocate array for each ring buffer element */
- for (i=0; iringSize; i++) {
+ for (i=0; iringSize+1; i++) {
pPvt->ringBuffer[i].pValue = callocMustSucceed(pPvt->valSize, 1,
"devAsynOctet::createRingBuffer creating ring element array");
}
@@ -372,7 +415,7 @@ static long createRingBuffer(dbCommon *pr, int minRingSize)
return asynSuccess;
}
-
+
static long getIoIntInfo(int cmd, dbCommon *pr, IOSCANPVT *iopvt)
{
devPvt *pPvt = (devPvt *)pr->dpvt;
@@ -423,8 +466,8 @@ static int getRingBufferValue(devPvt *pPvt)
pPvt->precord->name, driverName, functionName, pPvt->ringBufferOverflows);
pPvt->ringBufferOverflows = 0;
}
- pPvt->result = pPvt->ringBuffer[pPvt->ringTail];
- pPvt->ringTail = (pPvt->ringTail==pPvt->ringSize-1) ? 0 : pPvt->ringTail+1;
+ pPvt->result = pPvt->ringBuffer[pPvt->ringTail];
+ pPvt->ringTail = (pPvt->ringTail==pPvt->ringSize) ? 0 : pPvt->ringTail+1;
ret = 1;
}
epicsMutexUnlock(pPvt->devPvtLock);
@@ -445,7 +488,7 @@ static void interruptCallback(void *drvPvt, asynUser *pasynUser,
pr->name, driverName, functionName, pPvt->ringSize, (int)len);
if (len >= pPvt->valSize) len = pPvt->valSize-1;
if (pPvt->ringSize == 0) {
- /* Not using a ring buffer */
+ /* Not using a ring buffer */
if (pasynUser->auxStatus == asynSuccess) {
/* Note: calling dbScanLock here may to lead to deadlocks when asyn:READBACK is set for output records
* and the driver is non-blocking.
@@ -470,7 +513,7 @@ static void interruptCallback(void *drvPvt, asynUser *pasynUser,
* we must defer calling callbackRequest until end of record processing */
if (pPvt->asyncProcessingActive) {
pPvt->numDeferredOutputCallbacks++;
- } else {
+ } else {
callbackRequest(&pPvt->outputCallback);
}
} else {
@@ -489,18 +532,18 @@ static void interruptCallback(void *drvPvt, asynUser *pasynUser,
}
rp = &pPvt->ringBuffer[pPvt->ringHead];
rp->len = len;
- memcpy(rp->pValue, value, len);
+ memcpy(rp->pValue, value, len);
rp->pValue[len] = 0;
rp->time = pasynUser->timestamp;
rp->status = pasynUser->auxStatus;
rp->alarmStatus = pasynUser->alarmStatus;
rp->alarmSeverity = pasynUser->alarmSeverity;
- pPvt->ringHead = (pPvt->ringHead==pPvt->ringSize-1) ? 0 : pPvt->ringHead+1;
+ pPvt->ringHead = (pPvt->ringHead==pPvt->ringSize) ? 0 : pPvt->ringHead+1;
if (pPvt->ringHead == pPvt->ringTail) {
/* There was no room in the ring buffer. Remove the oldest value from the
* ring buffer and add the new one so the final value the record receives
* is guaranteed to be the most recent value */
- pPvt->ringTail = (pPvt->ringTail==pPvt->ringSize-1) ? 0 : pPvt->ringTail+1;
+ pPvt->ringTail = (pPvt->ringTail==pPvt->ringSize) ? 0 : pPvt->ringTail+1;
pPvt->ringBufferOverflows++;
} else {
/* We only need to request the record to process if we added a new
@@ -510,7 +553,7 @@ static void interruptCallback(void *drvPvt, asynUser *pasynUser,
* we must defer calling callbackRequest until end of record processing */
if (pPvt->asyncProcessingActive) {
pPvt->numDeferredOutputCallbacks++;
- } else {
+ } else {
callbackRequest(&pPvt->outputCallback);
}
} else {
@@ -523,7 +566,7 @@ static void interruptCallback(void *drvPvt, asynUser *pasynUser,
static void outputCallbackCallback(CALLBACK *pcb)
{
- devPvt *pPvt;
+ devPvt *pPvt;
static const char *functionName="outputCallbackCallback";
callbackGetUser(pPvt, pcb);
@@ -532,12 +575,14 @@ static void outputCallbackCallback(CALLBACK *pcb)
dbScanLock(pr);
epicsMutexLock(pPvt->devPvtLock);
pPvt->newOutputCallbackValue = 1;
+ /* We need to set udf=0 here so that it is already cleared when dbProcess is called */
+ pr->udf = 0;
dbProcess(pr);
if (pPvt->newOutputCallbackValue != 0) {
- /* We called dbProcess but the record did not process, perhaps because PACT was 1
+ /* We called dbProcess but the record did not process, perhaps because PACT was 1
* Need to remove ring buffer element */
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s warning dbProcess did not process record, PACT=%d\n",
+ asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
+ "%s %s::%s warning dbProcess did not process record, PACT=%d\n",
pr->name, driverName, functionName, pr->pact);
if (pPvt->ringSize > 0) {
getRingBufferValue(pPvt);
@@ -548,7 +593,7 @@ static void outputCallbackCallback(CALLBACK *pcb)
dbScanUnlock(pr);
}
}
-
+
static int initDrvUser(devPvt *pPvt)
{
asynUser *pasynUser = pPvt->pasynUser;
@@ -613,7 +658,7 @@ static int initDbAddr(devPvt *pPvt)
}
return INIT_OK;
}
-
+
static asynStatus writeIt(asynUser *pasynUser,const char *message,size_t nbytes)
{
devPvt *pPvt = (devPvt *)pasynUser->userPvt;
@@ -670,7 +715,7 @@ static asynStatus readIt(asynUser *pasynUser,char *message,
"%s %s::%s eomReason %d\n",precord->name, driverName, functionName, eomReason);
return pPvt->result.status;
}
-
+
static void reportQueueRequestStatus(devPvt *pPvt, asynStatus status)
{
static const char *functionName="reportQueueRequestStatus";
@@ -679,11 +724,11 @@ static void reportQueueRequestStatus(devPvt *pPvt, asynStatus status)
pPvt->previousQueueRequestStatus = status;
if (status == asynSuccess) {
asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s queueRequest status returned to normal\n",
+ "%s %s::%s queueRequest status returned to normal\n",
pPvt->precord->name, driverName, functionName);
} else {
asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s queueRequest error %s\n",
+ "%s %s::%s queueRequest error %s\n",
pPvt->precord->name, driverName, functionName,pPvt->pasynUser->errorMessage);
}
}
@@ -691,11 +736,10 @@ static void reportQueueRequestStatus(devPvt *pPvt, asynStatus status)
static long processCommon(dbCommon *precord)
{
devPvt *pPvt = (devPvt *)precord->dpvt;
- waveformRecord *pwf = (waveformRecord *)precord;
int gotCallbackData;
asynStatus status;
static const char *functionName="processCommon";
-
+
epicsMutexLock(pPvt->devPvtLock);
if (pPvt->isOutput) {
if (pPvt->ringSize == 0) {
@@ -729,7 +773,9 @@ static long processCommon(dbCommon *precord)
if (pPvt->ringSize == 0) {
/* Data has already been copied to the record in interruptCallback */
pPvt->gotValue--;
- if (pPvt->isWaveform && (pPvt->result.status == asynSuccess)) pwf->nord = pPvt->nord;
+ if ((pPvt->pLen != NULL) && (pPvt->result.status == asynSuccess)) {
+ (*pPvt->pLen) = (pPvt->isWaveform ? pPvt->nord : pPvt->nord + 1); /* lsi, lso and printf count \0 in length */
+ }
if (pPvt->gotValue) {
asynPrint(pPvt->pasynUser, ASYN_TRACE_WARNING,
"%s %s::%s warning: multiple interrupt callbacks between processing\n",
@@ -743,19 +789,21 @@ static long processCommon(dbCommon *precord)
epicsMutexLock(pPvt->devPvtLock);
if (rp->status == asynSuccess) {
memcpy(pPvt->pValue, rp->pValue, rp->len);
- if (pPvt->isWaveform) pwf->nord = rp->len;
+ if (pPvt->pLen != NULL) {
+ (*pPvt->pLen) = (epicsUInt32)(pPvt->isWaveform ? rp->len : rp->len + 1); /* lsi, lso and printf count \0 in length */
+ }
}
precord->time = rp->time;
epicsMutexUnlock(pPvt->devPvtLock);
}
- len = strlen(pPvt->pValue);
+ len = (int)strlen(pPvt->pValue);
asynPrintIO(pPvt->pasynUser, ASYN_TRACEIO_DEVICE,
pPvt->pValue, len,
"%s %s::%s len=%d, data:",
precord->name, driverName, functionName, len);
}
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
pPvt->isOutput ? WRITE_ALARM : READ_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
(void)recGblSetSevr(precord, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
@@ -781,14 +829,14 @@ static void finish(dbCommon *pr)
if(pr->pact) callbackRequestProcessCallback(&pPvt->processCallback,pr->prio,pr);
}
-
+
static long initSiCmdResponse(stringinRecord *psi)
{
devPvt *pPvt;
int status;
- status = initCommon((dbCommon *)psi, &psi->inp, callbackSiCmdResponse,
- 0, 0, 0, psi->val, sizeof(psi->val));
+ status = initCommon((dbCommon *)psi, &psi->inp, callbackSiCmdResponse,
+ 0, 0, 0, psi->val, NULL, sizeof(psi->val));
if(status!=INIT_OK) return status;
pPvt = (devPvt *)psi->dpvt;
return initCmdBuffer(pPvt);
@@ -821,7 +869,7 @@ static long initSiWriteRead(stringinRecord *psi)
devPvt *pPvt;
status = initCommon((dbCommon *)psi, &psi->inp, callbackSiWriteRead,
- 0, 0, 0, psi->val, sizeof(psi->val));
+ 0, 0, 0, psi->val, NULL, sizeof(psi->val));
if(status!=INIT_OK) return status;
pPvt = (devPvt *)psi->dpvt;
return initDbAddr(pPvt);
@@ -860,11 +908,11 @@ static void callbackSiWriteRead(asynUser *pasynUser)
}
finish((dbCommon *)psi);
}
-
+
static long initSiRead(stringinRecord *psi)
{
- return initCommon((dbCommon *)psi, &psi->inp, callbackSiRead,
- 0, 0, 1, psi->val, sizeof(psi->val));
+ return initCommon((dbCommon *)psi, &psi->inp, callbackSiRead,
+ 0, 0, 1, psi->val, NULL, sizeof(psi->val));
}
static void callbackSiRead(asynUser *pasynUser)
@@ -888,7 +936,7 @@ static void callbackSiRead(asynUser *pasynUser)
static long initSoWrite(stringoutRecord *pso)
{
return initCommon((dbCommon *)pso, &pso->out, callbackSoWrite,
- 1, 0, 1, pso->val, sizeof(pso->val));
+ 1, 0, 1, pso->val, NULL, sizeof(pso->val));
}
/* implementation of strnlen() as i'm not sure it is available everywhere */
@@ -910,13 +958,13 @@ static void callbackSoWrite(asynUser *pasynUser)
writeIt(pasynUser, pso->val, my_strnlen(pso->val, sizeof(pso->val)));
finish((dbCommon *)pso);
}
-
+
static long initWfCmdResponse(waveformRecord *pwf)
{
int status;
status = initCommon((dbCommon *)pwf, &pwf->inp, callbackWfCmdResponse,
- 0, 1, 0, pwf->bptr, pwf->nelm);
+ 0, 1, 0, pwf->bptr, &(pwf->nord), pwf->nelm);
if (status != INIT_OK) return status;
return initCmdBuffer((devPvt *)pwf->dpvt);
}
@@ -934,8 +982,10 @@ static void callbackWfCmdResponse(asynUser *pasynUser)
status = readIt(pasynUser,pwf->bptr,(size_t)pwf->nelm,&nBytesRead);
pwf->time = pasynUser->timestamp;
if(status==asynSuccess) {
+ if (nBytesRead == pwf->nelm) nBytesRead--;
+ pbuf[nBytesRead] = 0;
+ pwf->udf = 0;
pwf->nord = (epicsUInt32)nBytesRead;
- if (nBytesRead < pwf->nelm) pbuf[nBytesRead] = 0;
}
}
finish((dbCommon *)pwf);
@@ -946,7 +996,7 @@ static long initWfWriteRead(waveformRecord *pwf)
int status;
status = initCommon((dbCommon *)pwf, &pwf->inp, callbackWfWriteRead,
- 0, 1, 0, pwf->bptr, pwf->nelm);
+ 0, 1, 0, pwf->bptr, &(pwf->nord), pwf->nelm);
if (status != INIT_OK) return status;
return initDbAddr((devPvt *)pwf->dpvt);
}
@@ -978,17 +1028,19 @@ static void callbackWfWriteRead(asynUser *pasynUser)
status = readIt(pasynUser,pwf->bptr, (size_t)pwf->nelm, &nBytesRead);
pwf->time = pasynUser->timestamp;
if(status==asynSuccess) {
+ if (nBytesRead == pwf->nelm) nBytesRead--;
+ pbuf[nBytesRead] = 0;
+ pwf->udf = 0;
pwf->nord = (epicsUInt32)nBytesRead;
- if (nBytesRead < pwf->nelm) pbuf[nBytesRead] = 0;
}
}
finish((dbCommon *)pwf);
}
-
+
static long initWfRead(waveformRecord *pwf)
{
return initCommon((dbCommon *)pwf, &pwf->inp, callbackWfRead,
- 0, 1, 1, pwf->bptr, pwf->nelm);
+ 0, 1, 1, pwf->bptr, &(pwf->nord), pwf->nelm);
}
static void callbackWfRead(asynUser *pasynUser)
@@ -1002,8 +1054,10 @@ static void callbackWfRead(asynUser *pasynUser)
status = readIt(pasynUser, pwf->bptr, pwf->nelm, &nBytesRead);
pwf->time = pasynUser->timestamp;
if(status==asynSuccess) {
+ if (nBytesRead == pwf->nelm) nBytesRead--;
+ pbuf[nBytesRead] = 0;
+ pwf->udf = 0;
pwf->nord = (epicsUInt32)nBytesRead;
- if (nBytesRead < pwf->nelm) pbuf[nBytesRead] = 0;
}
finish((dbCommon *)pwf);
}
@@ -1011,7 +1065,7 @@ static void callbackWfRead(asynUser *pasynUser)
static long initWfWrite(waveformRecord *pwf)
{
return initCommon((dbCommon *)pwf, &pwf->inp, callbackWfWrite,
- 1, 1, 1, pwf->bptr, pwf->nelm);
+ 1, 1, 1, pwf->bptr, &(pwf->nord), pwf->nelm);
}
static void callbackWfWrite(asynUser *pasynUser)
@@ -1026,7 +1080,7 @@ static void callbackWfWrite(asynUser *pasynUser)
static long initWfWriteBinary(waveformRecord *pwf)
{
return initCommon((dbCommon *)pwf, &pwf->inp, callbackWfWriteBinary,
- 1, 1, 1, pwf->bptr, pwf->nelm);
+ 1, 1, 1, pwf->bptr, &(pwf->nord), pwf->nelm);
}
static void callbackWfWriteBinary(asynUser *pasynUser)
@@ -1037,3 +1091,169 @@ static void callbackWfWriteBinary(asynUser *pasynUser)
writeIt(pasynUser, pwf->bptr, pwf->nord);
finish((dbCommon *)pwf);
}
+
+#ifdef HAVE_LSREC
+
+static long initLsiCmdResponse(lsiRecord *plsi)
+{
+ devPvt *pPvt;
+ int status;
+
+ status = initCommon((dbCommon *)plsi, &plsi->inp, callbackLsiCmdResponse,
+ 0, 0, 0, plsi->val, &(plsi->len), plsi->sizv);
+ if(status!=INIT_OK) return status;
+ pPvt = (devPvt *)plsi->dpvt;
+ return initCmdBuffer(pPvt);
+}
+
+static void callbackLsiCmdResponse(asynUser *pasynUser)
+{
+ devPvt *pPvt = (devPvt *)pasynUser->userPvt;
+ lsiRecord *plsi = (lsiRecord *)pPvt->precord;
+ asynStatus status;
+ size_t len = plsi->sizv;
+ size_t nBytesRead;
+
+ status = writeIt(pasynUser,pPvt->buffer,pPvt->bufLen);
+ if(status==asynSuccess) {
+ status = readIt(pasynUser,plsi->val,len,&nBytesRead);
+ plsi->time = pasynUser->timestamp;
+ if(status==asynSuccess) {
+ plsi->udf = 0;
+ if(nBytesRead==len) nBytesRead--;
+ plsi->val[nBytesRead] = 0;
+ plsi->len = (epicsUInt32)nBytesRead + 1;
+ }
+ }
+ finish((dbCommon *)plsi);
+}
+
+static long initLsiWriteRead(lsiRecord *plsi)
+{
+ int status;
+ devPvt *pPvt;
+
+ status = initCommon((dbCommon *)plsi, &plsi->inp, callbackLsiWriteRead,
+ 0, 0, 0, plsi->val, &(plsi->len), plsi->sizv);
+ if(status!=INIT_OK) return status;
+ pPvt = (devPvt *)plsi->dpvt;
+ return initDbAddr(pPvt);
+}
+
+static void callbackLsiWriteRead(asynUser *pasynUser)
+{
+ devPvt *pPvt = (devPvt *)pasynUser->userPvt;
+ lsiRecord *plsi = (lsiRecord *)pPvt->precord;
+ asynStatus status;
+ size_t nBytesRead;
+ long dbStatus;
+ char raw[MAX_STRING_SIZE+1];
+ char translate[MAX_STRING_SIZE+1];
+ size_t len = plsi->sizv;
+
+ dbStatus = dbGet(&pPvt->dbAddr,DBR_STRING,raw,0,0,0);
+ raw[MAX_STRING_SIZE] = 0;
+ if(dbStatus) {
+ asynPrint(pasynUser,ASYN_TRACE_ERROR,
+ "%s dbGet failed\n",plsi->name);
+ recGblSetSevr(plsi,READ_ALARM,INVALID_ALARM);
+ finish((dbCommon *)plsi);
+ return;
+ }
+ dbTranslateEscape(translate,raw);
+ status = writeIt(pasynUser,translate,strlen(translate));
+ if(status==asynSuccess) {
+ status = readIt(pasynUser,plsi->val,len,&nBytesRead);
+ plsi->time = pasynUser->timestamp;
+ if(status==asynSuccess) {
+ plsi->udf = 0;
+ if(nBytesRead==len) nBytesRead--;
+ plsi->val[nBytesRead] = 0;
+ plsi->len = (epicsUInt32)nBytesRead + 1;
+ }
+ }
+ finish((dbCommon *)plsi);
+}
+
+static long initLsiRead(lsiRecord *plsi)
+{
+ return initCommon((dbCommon *)plsi, &plsi->inp, callbackLsiRead,
+ 0, 0, 1, plsi->val, &(plsi->len), plsi->sizv);
+}
+
+static void callbackLsiRead(asynUser *pasynUser)
+{
+ devPvt *pPvt = (devPvt *)pasynUser->userPvt;
+ lsiRecord *plsi = (lsiRecord *)pPvt->precord;
+ size_t nBytesRead;
+ asynStatus status;
+ size_t len = plsi->sizv;
+
+ status = readIt(pasynUser,plsi->val,len,&nBytesRead);
+ plsi->time = pasynUser->timestamp;
+ if (status==asynSuccess) {
+ plsi->udf = 0;
+ if (nBytesRead==len) nBytesRead--;
+ plsi->val[nBytesRead] = 0;
+ plsi->len = (epicsUInt32)nBytesRead + 1;
+ }
+ finish((dbCommon *)plsi);
+}
+
+static long initLsoWrite(lsoRecord *plso)
+{
+ return initCommon((dbCommon *)plso, &plso->out, callbackLsoWrite,
+ 1, 0, 1, plso->val, &(plso->len), plso->sizv);
+}
+
+static void callbackLsoWrite(asynUser *pasynUser)
+{
+ devPvt *pPvt = (devPvt *)pasynUser->userPvt;
+ lsoRecord *plso = (lsoRecord *)pPvt->precord;
+
+ writeIt(pasynUser, plso->val, my_strnlen(plso->val, plso->len));
+ finish((dbCommon *)plso);
+}
+
+static long initPfWrite(printfRecord *ppf)
+{
+ return initCommon((dbCommon *)ppf, &ppf->out, callbackPfWrite,
+ 1, 0, 1, ppf->val, &(ppf->len), ppf->sizv);
+}
+
+static void callbackPfWrite(asynUser *pasynUser)
+{
+ devPvt *pPvt = (devPvt *)pasynUser->userPvt;
+ printfRecord *ppf = (printfRecord *)pPvt->precord;
+
+ writeIt(pasynUser, ppf->val, my_strnlen(ppf->val, ppf->len));
+ finish((dbCommon *)ppf);
+}
+
+#endif /* HAVE_LSREC */
+
+#ifdef HAVE_CALCMOD
+static long initScalcoutWrite(scalcoutRecord *pscalcout)
+{
+ long ret;
+ pscalcout->osv[0] = 0;
+ ret = initCommon((dbCommon *)pscalcout, &pscalcout->out, callbackScalcoutWrite,
+ 1, 0, 1, pscalcout->osv, NULL, sizeof(pscalcout->osv));
+ /* update sval and val if an inital readback from the device */
+ if (ret == INIT_OK && my_strnlen(pscalcout->osv, sizeof(pscalcout->osv)) > 0) {
+ strncpy(pscalcout->sval, pscalcout->osv, sizeof(pscalcout->sval));
+ pscalcout->sval[sizeof(pscalcout->sval) - 1] = 0;
+ pscalcout->val = atof(pscalcout->sval);
+ }
+ return ret;
+}
+
+static void callbackScalcoutWrite(asynUser *pasynUser)
+{
+ devPvt *pPvt = (devPvt *)pasynUser->userPvt;
+ scalcoutRecord *pscalcout = (scalcoutRecord *)pPvt->precord;
+
+ writeIt(pasynUser, pscalcout->osv, my_strnlen(pscalcout->osv, sizeof(pscalcout->osv)));
+ finish((dbCommon *)pscalcout);
+}
+#endif /* HAVE_CALCMOD */
diff --git a/asyn/devEpics/devAsynOctetLs.dbd b/asyn/devEpics/devAsynOctetLs.dbd
new file mode 100644
index 0000000..5e0ed15
--- /dev/null
+++ b/asyn/devEpics/devAsynOctetLs.dbd
@@ -0,0 +1,5 @@
+device(lsi,INST_IO,asynLsiOctetCmdResponse,"asynOctetCmdResponse")
+device(lsi,INST_IO,asynLsiOctetWriteRead,"asynOctetWriteRead")
+device(lsi,INST_IO,asynLsiOctetRead,"asynOctetRead")
+device(lso,INST_IO,asynLsoOctetWrite,"asynOctetWrite")
+device(printf,INST_IO,asynPfOctetWrite,"asynOctetWrite")
diff --git a/asyn/devEpics/devAsynUInt32Digital.c b/asyn/devEpics/devAsynUInt32Digital.c
index 9465173..dd5be82 100644
--- a/asyn/devEpics/devAsynUInt32Digital.c
+++ b/asyn/devEpics/devAsynUInt32Digital.c
@@ -51,6 +51,7 @@
#include "asynEnum.h"
#include "asynEnumSyncIO.h"
#include "asynEpicsUtils.h"
+#include "devEpicsPvt.h"
#define INIT_OK 0
#define INIT_DO_NOT_CONVERT 2
@@ -88,6 +89,7 @@ typedef struct devPvt{
int ringSize;
int ringBufferOverflows;
ringBufferElement result;
+ asynStatus lastStatus;
interruptCallbackUInt32Digital interruptCallback;
CALLBACK processCallback;
CALLBACK outputCallback;
@@ -105,9 +107,9 @@ typedef struct devPvt{
}devPvt;
#define NUM_BITS 16
-
-static void setEnums(char *outStrings, int *outVals, epicsEnum16 *outSeverities,
- char *inStrings[], int *inVals, int *inSeverities,
+
+static void setEnums(char *outStrings, int *outVals, epicsEnum16 *outSeverities,
+ char *inStrings[], int *inVals, int *inSeverities,
size_t numIn, size_t numOut);
static long createRingBuffer(dbCommon *pr);
static long getIoIntInfo(int cmd, dbCommon *pr, IOSCANPVT *iopvt);
@@ -143,7 +145,7 @@ typedef struct analogDset { /* analog dset */
long number;
DEVSUPFUN dev_report;
DEVSUPFUN init;
- DEVSUPFUN init_record;
+ DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN processCommon;/*(0)=>(success ) */
} analogDset;
@@ -173,7 +175,7 @@ epicsExportAddress(dset, asynMbbiUInt32Digital);
epicsExportAddress(dset, asynMbboUInt32Digital);
epicsExportAddress(dset, asynMbbiDirectUInt32Digital);
epicsExportAddress(dset, asynMbboDirectUInt32Digital);
-
+
static long initCommon(dbCommon *pr, DBLINK *plink,
userCallback processCallback,interruptCallbackUInt32Digital interruptCallback, interruptCallbackEnum callbackEnum,
int maxEnums, char *pFirstString, int *pFirstValue, epicsEnum16 *pFirstSeverity)
@@ -193,7 +195,7 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
pPvt->pasynUser = pasynUser;
pPvt->devPvtLock = epicsMutexCreate();
/* Parse the link to get addr and port */
- status = pasynEpicsUtils->parseLinkMask(pasynUser, plink,
+ status = pasynEpicsUtils->parseLinkMask(pasynUser, plink,
&pPvt->portName, &pPvt->addr, &pPvt->mask,&pPvt->userParam);
if (status != asynSuccess) {
printf("%s %s::%s %s\n",
@@ -255,7 +257,7 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
size_t numRead;
asynEnum *pasynEnum = pasynInterface->pinterface;
void *registrarPvt;
- status = pasynEnumSyncIO->connect(pPvt->portName, pPvt->addr,
+ status = pasynEnumSyncIO->connect(pPvt->portName, pPvt->addr,
&pPvt->pasynUserEnumSync, pPvt->userParam);
if (status != asynSuccess) {
printf("%s %s::%s EnumSyncIO->connect failed %s\n",
@@ -263,10 +265,10 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
goto bad;
}
status = pasynEnumSyncIO->read(pPvt->pasynUserEnumSync,
- pPvt->enumStrings, pPvt->enumValues, pPvt->enumSeverities, maxEnums,
+ pPvt->enumStrings, pPvt->enumValues, pPvt->enumSeverities, maxEnums,
&numRead, pPvt->pasynUser->timeout);
if (status == asynSuccess) {
- setEnums(pFirstString, pFirstValue, pFirstSeverity,
+ setEnums(pFirstString, pFirstValue, pFirstSeverity,
pPvt->enumStrings, pPvt->enumValues, pPvt->enumSeverities, numRead, maxEnums);
}
status = pasynEnum->registerInterruptUser(
@@ -277,20 +279,11 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
pr->name, driverName, functionName,pPvt->pasynUser->errorMessage);
}
}
- /* If the info field "asyn:READBACK" is 1 and interruptCallback is not NULL
+ /* If the info field "asyn:READBACK" is 1 and interruptCallback is not NULL
* then register for callbacks on output records */
if (interruptCallback) {
int enableCallbacks=0;
- const char *callbackString;
- DBENTRY *pdbentry = dbAllocEntry(pdbbase);
- status = dbFindRecord(pdbentry, pr->name);
- if (status) {
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s error finding record\n",
- pr->name, driverName, functionName);
- goto bad;
- }
- callbackString = dbGetInfo(pdbentry, "asyn:READBACK");
+ const char *callbackString = asynDbGetInfo(pr, "asyn:READBACK");
if (callbackString) enableCallbacks = atoi(callbackString);
if (enableCallbacks) {
status = createRingBuffer(pr);
@@ -314,31 +307,21 @@ static long initCommon(dbCommon *pr, DBLINK *plink,
pr->pact=1;
return INIT_ERROR;
}
-
+
static long createRingBuffer(dbCommon *pr)
{
devPvt *pPvt = (devPvt *)pr->dpvt;
- asynStatus status;
const char *sizeString;
- static const char *functionName="createRingBuffer";
-
+
if (!pPvt->ringBuffer) {
- DBENTRY *pdbentry = dbAllocEntry(pdbbase);
pPvt->ringSize = DEFAULT_RING_BUFFER_SIZE;
- status = dbFindRecord(pdbentry, pr->name);
- if (status) {
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s error finding record\n",
- pr->name, driverName, functionName);
- return -1;
- }
- sizeString = dbGetInfo(pdbentry, "asyn:FIFO");
+ sizeString = asynDbGetInfo(pr, "asyn:FIFO");
if (sizeString) pPvt->ringSize = atoi(sizeString);
- pPvt->ringBuffer = callocMustSucceed(pPvt->ringSize+1, sizeof *pPvt->ringBuffer, "%s::createRingBuffer");
+ pPvt->ringBuffer = callocMustSucceed(pPvt->ringSize+1, sizeof *pPvt->ringBuffer, "devAsynUInt32Digital::createRingBuffer");
}
return asynSuccess;
}
-
+
static long getIoIntInfo(int cmd, dbCommon *pr, IOSCANPVT *iopvt)
{
@@ -377,18 +360,23 @@ static long getIoIntInfo(int cmd, dbCommon *pr, IOSCANPVT *iopvt)
return 0;
}
-static void setEnums(char *outStrings, int *outVals, epicsEnum16 *outSeverities, char *inStrings[], int *inVals, int *inSeverities,
+static void setEnums(char *outStrings, int *outVals, epicsEnum16 *outSeverities, char *inStrings[], int *inVals, int *inSeverities,
size_t numIn, size_t numOut)
{
size_t i;
-
+
for (i=0; i MAX_ENUM_STRING_SIZE-1) len = MAX_ENUM_STRING_SIZE-1;
+ memcpy(&outStrings[i*MAX_ENUM_STRING_SIZE], inStrings[i], len);
+ outStrings[i*MAX_ENUM_STRING_SIZE + len] = '\0';
+ }
if (outVals) outVals[i] = inVals[i];
if (outSeverities) outSeverities[i] = inSeverities[i];
}
@@ -407,13 +395,16 @@ static void processCallbackInput(asynUser *pasynUser)
pPvt->result.alarmSeverity = pPvt->pasynUser->alarmSeverity;
if (pPvt->result.status == asynSuccess) {
asynPrint(pasynUser, ASYN_TRACEIO_DEVICE,
- "%s %s::%s value=%u\n",
- pr->name, driverName, functionName,pPvt->result.value);
+ "%s %s::%s process value=%u\n", pr->name, driverName, functionName,
+ pPvt->result.value);
} else {
- asynPrint(pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s read error %s\n",
- pr->name, driverName, functionName, pasynUser->errorMessage);
+ if (pPvt->result.status != pPvt->lastStatus) {
+ asynPrint(pasynUser, ASYN_TRACE_ERROR,
+ "%s %s::%s process read error %s\n",
+ pr->name, driverName, functionName, pasynUser->errorMessage);
+ }
}
+ pPvt->lastStatus = pPvt->result.status;
if(pr->pact) callbackRequestProcessCallback(&pPvt->processCallback,pr->prio,pr);
}
@@ -428,17 +419,21 @@ static void processCallbackOutput(asynUser *pasynUser)
pPvt->result.time = pPvt->pasynUser->timestamp;
pPvt->result.alarmStatus = pPvt->pasynUser->alarmStatus;
pPvt->result.alarmSeverity = pPvt->pasynUser->alarmSeverity;
- if(pPvt->result.status == asynSuccess) {
+ if (pPvt->result.status == asynSuccess) {
asynPrint(pasynUser, ASYN_TRACEIO_DEVICE,
- "%s %s::%s process value %u\n",pr->name, driverName, functionName,pPvt->result.value);
+ "%s %s::%s process value %u\n", pr->name, driverName, functionName,
+ pPvt->result.value);
} else {
- asynPrint(pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s process error %s\n",
- pr->name, driverName, functionName, pasynUser->errorMessage);
+ if (pPvt->result.status != pPvt->lastStatus) {
+ asynPrint(pasynUser, ASYN_TRACE_ERROR,
+ "%s %s::%s process write error %s\n",
+ pr->name, driverName, functionName, pasynUser->errorMessage);
+ }
}
+ pPvt->lastStatus = pPvt->result.status;
if(pr->pact) callbackRequestProcessCallback(&pPvt->processCallback,pr->prio,pr);
}
-
+
static void interruptCallbackInput(void *drvPvt, asynUser *pasynUser,
epicsUInt32 value)
{
@@ -479,10 +474,10 @@ static void interruptCallbackInput(void *drvPvt, asynUser *pasynUser,
pPvt->ringTail = (pPvt->ringTail==pPvt->ringSize) ? 0 : pPvt->ringTail+1;
pPvt->ringBufferOverflows++;
} else {
- /* We only need to request the record to process if we added a
+ /* We only need to request the record to process if we added a
* new element to the ring buffer, not if we just replaced an element. */
scanIoRequest(pPvt->ioScanPvt);
- }
+ }
epicsMutexUnlock(pPvt->devPvtLock);
}
@@ -514,7 +509,7 @@ static void interruptCallbackOutput(void *drvPvt, asynUser *pasynUser,
* we must defer calling callbackRequest until end of record processing */
if (pPvt->asyncProcessingActive) {
pPvt->numDeferredOutputCallbacks++;
- } else {
+ } else {
callbackRequest(&pPvt->outputCallback);
}
}
@@ -523,7 +518,7 @@ static void interruptCallbackOutput(void *drvPvt, asynUser *pasynUser,
static void outputCallbackCallback(CALLBACK *pcb)
{
- devPvt *pPvt;
+ devPvt *pPvt;
static const char *functionName="outputCallbackCallback";
callbackGetUser(pPvt, pcb);
@@ -532,12 +527,14 @@ static void outputCallbackCallback(CALLBACK *pcb)
dbScanLock(pr);
epicsMutexLock(pPvt->devPvtLock);
pPvt->newOutputCallbackValue = 1;
+ /* We need to set udf=0 here so that it is already cleared when dbProcess is called */
+ pr->udf = 0;
dbProcess(pr);
if (pPvt->newOutputCallbackValue != 0) {
- /* We called dbProcess but the record did not process, perhaps because PACT was 1
+ /* We called dbProcess but the record did not process, perhaps because PACT was 1
* Need to remove ring buffer element */
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s warning dbProcess did not process record, PACT=%d\n",
+ asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
+ "%s %s::%s warning dbProcess did not process record, PACT=%d\n",
pr->name, driverName, functionName,pr->pact);
getCallbackValue(pPvt);
pPvt->newOutputCallbackValue = 0;
@@ -555,7 +552,7 @@ static void interruptCallbackEnumMbbi(void *drvPvt, asynUser *pasynUser,
if (!interruptAccept) return;
dbScanLock((dbCommon*)pr);
- setEnums((char*)&pr->zrst, (int*)&pr->zrvl, &pr->zrsv,
+ setEnums((char*)&pr->zrst, (int*)&pr->zrvl, &pr->zrsv,
strings, values, severities, nElements, MAX_ENUM_STATES);
db_post_events(pr, &pr->val, DBE_PROPERTY);
dbScanUnlock((dbCommon*)pr);
@@ -569,7 +566,7 @@ static void interruptCallbackEnumMbbo(void *drvPvt, asynUser *pasynUser,
if (!interruptAccept) return;
dbScanLock((dbCommon*)pr);
- setEnums((char*)&pr->zrst, (int*)&pr->zrvl, &pr->zrsv,
+ setEnums((char*)&pr->zrst, (int*)&pr->zrvl, &pr->zrsv,
strings, values, severities, nElements, MAX_ENUM_STATES);
db_post_events(pr, &pr->val, DBE_PROPERTY);
dbScanUnlock((dbCommon*)pr);
@@ -583,7 +580,7 @@ static void interruptCallbackEnumBi(void *drvPvt, asynUser *pasynUser,
if (!interruptAccept) return;
dbScanLock((dbCommon*)pr);
- setEnums((char*)&pr->znam, NULL, &pr->zsv,
+ setEnums((char*)&pr->znam, NULL, &pr->zsv,
strings, NULL, severities, nElements, 2);
db_post_events(pr, &pr->val, DBE_PROPERTY);
dbScanUnlock((dbCommon*)pr);
@@ -597,7 +594,7 @@ static void interruptCallbackEnumBo(void *drvPvt, asynUser *pasynUser,
if (!interruptAccept) return;
dbScanLock((dbCommon*)pr);
- setEnums((char*)&pr->znam, NULL, &pr->zsv,
+ setEnums((char*)&pr->znam, NULL, &pr->zsv,
strings, NULL, severities, nElements, 2);
db_post_events(pr, &pr->val, DBE_PROPERTY);
dbScanUnlock((dbCommon*)pr);
@@ -647,17 +644,17 @@ static void reportQueueRequestStatus(devPvt *pPvt, asynStatus status)
pPvt->previousQueueRequestStatus = status;
if (status == asynSuccess) {
asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s queueRequest status returned to normal\n",
+ "%s %s::%s queueRequest status returned to normal\n",
pPvt->pr->name, driverName, functionName);
} else {
asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
- "%s %s::%s queueRequest error %s\n",
+ "%s %s::%s queueRequest error %s\n",
pPvt->pr->name, driverName, functionName,pPvt->pasynUser->errorMessage);
}
}
}
-
+
static long initBi(biRecord *pr)
{
devPvt *pPvt;
@@ -684,12 +681,12 @@ static long processBi(biRecord *pr)
reportQueueRequestStatus(pPvt, status);
}
pr->time = pPvt->result.time;
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
READ_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
if(pPvt->result.status==asynSuccess) {
- pr->rval = pPvt->result.value & pr->mask;
+ pr->rval = pPvt->result.value & pr->mask;
pr->udf=0;
return 0;
}
@@ -698,7 +695,7 @@ static long processBi(biRecord *pr)
return -1;
}
}
-
+
static long initBo(boRecord *pr)
{
devPvt *pPvt;
@@ -733,7 +730,6 @@ static long processBo(boRecord *pr)
if (pPvt->result.status == asynSuccess) {
pr->rval = pPvt->result.value & pr->mask;
pr->val = (pr->rval) ? 1 : 0;
- pr->udf = 0;
}
} else if(pr->pact == 0) {
pPvt->result.value = pr->rval;;
@@ -748,7 +744,7 @@ static long processBo(boRecord *pr)
epicsMutexLock(pPvt->devPvtLock);
reportQueueRequestStatus(pPvt, status);
}
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
WRITE_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
@@ -767,7 +763,7 @@ static long processBo(boRecord *pr)
return -1;
}
}
-
+
static long initLi(longinRecord *pr)
{
int status;
@@ -791,8 +787,8 @@ static long processLi(longinRecord *pr)
if(pPvt->canBlock) pr->pact = 0;
reportQueueRequestStatus(pPvt, status);
}
- pr->time = pPvt->result.time;
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pr->time = pPvt->result.time;
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
READ_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
@@ -806,7 +802,7 @@ static long processLi(longinRecord *pr)
return -1;
}
}
-
+
static long initLo(longoutRecord *pr)
{
devPvt *pPvt;
@@ -838,7 +834,6 @@ static long processLo(longoutRecord *pr)
/* We got a callback from the driver */
if (pPvt->result.status == asynSuccess) {
pr->val = pPvt->result.value & pPvt->mask;
- pr->udf = 0;
}
} else if(pr->pact == 0) {
pPvt->result.value = pr->val & pPvt->mask;
@@ -853,7 +848,7 @@ static long processLo(longoutRecord *pr)
epicsMutexLock(pPvt->devPvtLock);
reportQueueRequestStatus(pPvt, status);
}
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
WRITE_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
@@ -871,7 +866,7 @@ static long processLo(longoutRecord *pr)
return -1;
}
}
-
+
static long initMbbi(mbbiRecord *pr)
{
devPvt *pPvt;
@@ -900,12 +895,12 @@ static long processMbbi(mbbiRecord *pr)
reportQueueRequestStatus(pPvt, status);
}
pr->time = pPvt->result.time;
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
READ_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
if(pPvt->result.status==asynSuccess) {
- pr->rval = pPvt->result.value & pr->mask;
+ pr->rval = pPvt->result.value & pr->mask;
pr->udf=0;
return 0;
}
@@ -914,7 +909,7 @@ static long processMbbi(mbbiRecord *pr)
return -1;
}
}
-
+
static long initMbbo(mbboRecord *pr)
{
devPvt *pPvt;
@@ -981,7 +976,7 @@ static long processMbbo(mbboRecord *pr)
epicsMutexLock(pPvt->devPvtLock);
reportQueueRequestStatus(pPvt, status);
}
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
WRITE_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
@@ -1000,7 +995,7 @@ static long processMbbo(mbboRecord *pr)
return -1;
}
}
-
+
static long initMbbiDirect(mbbiDirectRecord *pr)
{
devPvt *pPvt;
@@ -1029,12 +1024,12 @@ static long processMbbiDirect(mbbiDirectRecord *pr)
reportQueueRequestStatus(pPvt, status);
}
pr->time = pPvt->result.time;
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
READ_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
if(pPvt->result.status==asynSuccess) {
- pr->rval = pPvt->result.value & pr->mask;
+ pr->rval = pPvt->result.value & pr->mask;
pr->udf=0;
return 0;
}
@@ -1043,7 +1038,7 @@ static long processMbbiDirect(mbbiDirectRecord *pr)
return -1;
}
}
-
+
static long initMbboDirect(mbboDirectRecord *pr)
{
devPvt *pPvt;
@@ -1113,7 +1108,7 @@ static long processMbboDirect(mbboDirectRecord *pr)
epicsMutexLock(pPvt->devPvtLock);
reportQueueRequestStatus(pPvt, status);
}
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
+ pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status,
WRITE_ALARM, &pPvt->result.alarmStatus,
INVALID_ALARM, &pPvt->result.alarmSeverity);
recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity);
diff --git a/asyn/devEpics/devAsynXXXArray.cpp b/asyn/devEpics/devAsynXXXArray.cpp
new file mode 100644
index 0000000..d331ee5
--- /dev/null
+++ b/asyn/devEpics/devAsynXXXArray.cpp
@@ -0,0 +1,594 @@
+/* devAsynXXXArray.cpp */
+/***********************************************************************
+* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
+* National Laboratory, and the Regents of the University of
+* California, as Operator of Los Alamos National Laboratory, and
+* Berliner Elektronenspeicherring-Gesellschaft m.b.H. (BESSY).
+* asynDriver is distributed subject to a Software License Agreement
+* found in file LICENSE that is included with this distribution.
+***********************************************************************/
+/*
+ Authors: Mark Rivers
+ 30-Sept-2022
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "devEpicsPvt.h"
+
+#define DEFAULT_RING_BUFFER_SIZE 0
+#define INIT_OK 0
+#define INIT_DO_NOT_CONVERT 2
+#define INIT_ERROR -1
+
+static const char *driverName = "devAsynXXXArray";
+
+
+// We use an anonymous namespace to hide these definitions
+namespace {
+
+template
+class devAsynXXXArray
+{
+
+private:
+ struct ringBufferElement {
+ EPICS_TYPE *pValue;
+ size_t len;
+ epicsTimeStamp time;
+ asynStatus status;
+ epicsAlarmCondition alarmStatus;
+ epicsAlarmSeverity alarmSeverity;
+ };
+
+ RECORD_TYPE *pRecord_;
+ asynUser *pasynUser_;
+ INTERFACE *pInterface_;
+ void *pInterfacePvt_;
+ void *registrarPvt_;
+ int canBlock_;
+ CALLBACK callback_;
+ IOSCANPVT ioScanPvt_;
+ asynStatus lastStatus_;
+ bool isOutput_;
+ epicsMutexId ringBufferLock_;
+ ringBufferElement *ringBuffer_;
+ int ringHead_;
+ int ringTail_;
+ int ringSize_;
+ int ringBufferOverflows_;
+ ringBufferElement result_;
+ int gotValue_; /* For interruptCallbackInput */
+ INTERRUPT interruptCallback_;
+ char *portName_;
+ char *userParam_;
+ int addr_;
+ const char *interfaceType_;
+ int signedType_;
+ int unsignedType_;
+ asynStatus previousQueueRequestStatus_;
+
+public:
+
+ devAsynXXXArray(dbCommon *pRecord, DBLINK *plink, int signedType, int unsignedType, bool isOutput, const char *interfaceType,
+ userCallback qrCallback, INTERRUPT interruptCallback):
+ pRecord_((RECORD_TYPE*) pRecord),
+ lastStatus_(asynSuccess),
+ isOutput_(isOutput),
+ ringBuffer_(0),
+ ringHead_(0),
+ ringTail_(0),
+ ringSize_(0),
+ ringBufferOverflows_(0),
+ gotValue_(0),
+ interruptCallback_(interruptCallback),
+ interfaceType_(epicsStrDup(interfaceType)),
+ signedType_(signedType),
+ unsignedType_(unsignedType),
+ previousQueueRequestStatus_(asynSuccess)
+ {
+ int status;
+ asynInterface *pasynInterface;
+
+ static const char *functionName = "devAsynXXXArray";
+
+ pRecord_->dpvt = this;
+ pasynUser_ = pasynManager->createAsynUser(qrCallback, 0);
+ pasynUser_->userPvt = this;
+ ringBufferLock_ = epicsMutexCreate();
+ /* This device support only supports signed and unsigned versions of the EPICS data type */
+ if ((pRecord_->ftvl != this->signedType_) && (pRecord_->ftvl != this->unsignedType_)) {
+ errlogPrintf("%s::%s, %s field type must be SIGNED_TYPE or UNSIGNED_TYPE\n",
+ driverName, functionName, pRecord_->name);
+ goto bad;
+ }
+ /* Parse the link to get addr and port */
+ status = pasynEpicsUtils->parseLink(pasynUser_, plink,
+ &portName_, &addr_, &userParam_);
+ if (status != asynSuccess) {
+ errlogPrintf("%s::%s, %s error in link %s\n",
+ driverName, functionName, pRecord_->name, pasynUser_->errorMessage);
+ goto bad;
+ }
+ status = pasynManager->connectDevice(pasynUser_, portName_, addr_);
+ if (status != asynSuccess) {
+ errlogPrintf("%s::%s, %s connectDevice failed %s\n",
+ driverName, functionName, pRecord_->name, pasynUser_->errorMessage);
+ goto bad;
+ }
+ pasynInterface = pasynManager->findInterface(pasynUser_, asynDrvUserType, 1);
+ if (pasynInterface && userParam_) {
+ asynDrvUser *pasynDrvUser;
+ void *drvPvt;
+
+ pasynDrvUser = (asynDrvUser *)pasynInterface->pinterface;
+ drvPvt = pasynInterface->drvPvt;
+ status = pasynDrvUser->create(drvPvt, pasynUser_, userParam_, 0,0);
+ if (status != asynSuccess) {
+ errlogPrintf(
+ "%s::%s, %s drvUserCreate failed %s\n",
+ driverName, functionName, pRecord_->name, pasynUser_->errorMessage);
+ goto bad;
+ }
+ }
+ pasynInterface = pasynManager->findInterface(pasynUser_, interfaceType_, 1);
+ if (!pasynInterface) {
+ errlogPrintf(
+ "%s::%s, %s find %s interface failed %s\n",
+ driverName, functionName, pRecord_->name, this->interfaceType_, pasynUser_->errorMessage);
+ goto bad;
+ }
+ pInterface_ = (INTERFACE*) pasynInterface->pinterface;
+ pInterfacePvt_ = pasynInterface->drvPvt;
+ /* If this is an output record and the info field "asyn:READBACK" is 1
+ * then register for callbacks on output records */
+ if (isOutput_) {
+ int enableCallbacks=0;
+ const char *callbackString = asynDbGetInfo((dbCommon*)pRecord_, "asyn:READBACK");
+ if (callbackString) enableCallbacks = atoi(callbackString);
+ if (enableCallbacks) {
+ status = createRingBuffer();
+ if (status != asynSuccess) goto bad;
+ status = pInterface_->registerInterruptUser(
+ pInterfacePvt_, pasynUser_,
+ interruptCallback_, this, ®istrarPvt_);
+ if (status != asynSuccess) {
+ printf("%s %s::%s error calling registerInterruptUser %s\n",
+ pRecord_->name, driverName, functionName, pasynUser_->errorMessage);
+ }
+ }
+ }
+ scanIoInit(&ioScanPvt_);
+ /* Determine if device can block */
+ pasynManager->canBlock(pasynUser_, &canBlock_);
+ return;
+ bad:
+ recGblSetSevr(pRecord_, LINK_ALARM, INVALID_ALARM);
+ pRecord_->pact=1;
+ }
+
+ long createRingBuffer()
+ {
+ int status;
+ const char *sizeString;
+ static const char *functionName = "createRingBuffer";
+
+ if (!ringBuffer_) {
+ DBENTRY *pdbentry = dbAllocEntry(pdbbase);
+ ringSize_ = DEFAULT_RING_BUFFER_SIZE;
+ status = dbFindRecord(pdbentry, pRecord_->name);
+ if (status)
+ asynPrint(pasynUser_, ASYN_TRACE_ERROR,
+ "%s %s::%s error finding record status=%d\n",
+ pRecord_->name, driverName, functionName, status);
+ sizeString = dbGetInfo(pdbentry, "asyn:FIFO");
+ if (sizeString) ringSize_ = atoi(sizeString);
+ if (ringSize_ > 0) {
+ int i;
+ ringBuffer_ = (ringBufferElement *) callocMustSucceed(
+ ringSize_, sizeof(*ringBuffer_),
+ "devAsynXXXArray::createRingBuffer creating ring buffer");
+ /* Allocate array for each ring buffer element */
+ for (i=0; inelm, sizeof(EPICS_TYPE),
+ "devAsynXXXArray::createRingBuffer creating ring element array");
+ }
+ }
+ }
+ return asynSuccess;
+ }
+
+ long getIoIntInfo(int cmd, IOSCANPVT *iopvt)
+ {
+ int status;
+ static const char *functionName = "getIoIntInfo";
+
+ /* If initCommon failed then pInterface is NULL, return error */
+ if (!pInterface_) return -1;
+
+ if (cmd == 0) {
+ /* Add to scan list. Register interrupts */
+ asynPrint(pasynUser_, ASYN_TRACE_FLOW,
+ "%s %s::%s registering interrupt\n",
+ pRecord_->name, driverName, functionName);
+ createRingBuffer();
+ status = pInterface_->registerInterruptUser(
+ pInterfacePvt_, pasynUser_,
+ interruptCallback_, this, ®istrarPvt_);
+ if (status != asynSuccess) {
+ asynPrint(pasynUser_, ASYN_TRACE_ERROR,
+ "%s %s::%s error calling registerInterruptUser %s\n",
+ pRecord_->name, driverName, functionName, pasynUser_->errorMessage);
+ }
+ } else {
+ asynPrint(pasynUser_, ASYN_TRACE_FLOW,
+ "%s %s::%s cancelling interrupt\n",
+ pRecord_->name, driverName, functionName);
+ status = pInterface_->cancelInterruptUser(pInterfacePvt_,
+ pasynUser_, registrarPvt_);
+ if (status != asynSuccess) {
+ asynPrint(pasynUser_, ASYN_TRACE_ERROR,
+ "%s %s::%s error calling cancelInterruptUser %s\n",
+ pRecord_->name, driverName, functionName, pasynUser_->errorMessage);
+ }
+ }
+ *iopvt = ioScanPvt_;
+ return INIT_OK;
+ }
+
+ void reportQueueRequestStatus(asynStatus status)
+ {
+ if (previousQueueRequestStatus_ != status) {
+ previousQueueRequestStatus_ = status;
+ if (status == asynSuccess) {
+ asynPrint(pasynUser_, ASYN_TRACE_ERROR,
+ "%s %s queueRequest status returned to normal\n",
+ pRecord_->name, driverName);
+ } else {
+ asynPrint(pasynUser_, ASYN_TRACE_ERROR,
+ "%s %s queueRequest %s\n",
+ pRecord_->name, driverName, pasynUser_->errorMessage);
+ }
+ }
+ }
+
+ long process()
+ {
+ int newInputData;
+ asynStatus status;
+ static const char *functionName = "process";
+
+ if (ringSize_ == 0) {
+ newInputData = gotValue_;
+ } else {
+ newInputData = getRingBufferValue();
+ }
+ if (!newInputData && !pRecord_->pact) { /* This is an initial call from record */
+ if(canBlock_) pRecord_->pact = 1;
+ status = pasynManager->queueRequest(pasynUser_, asynQueuePriorityLow, 0);
+ if ((status == asynSuccess) && canBlock_) return 0;
+ if (canBlock_) pRecord_->pact = 0;
+ reportQueueRequestStatus(status);
+ }
+ if (newInputData) {
+ if (ringSize_ == 0){
+ /* Data has already been copied to the record in interruptCallback */
+ gotValue_--;
+ if (gotValue_) {
+ asynPrint(pasynUser_, ASYN_TRACE_WARNING,
+ "%s %s::%s, "
+ "warning: multiple interrupt callbacks between processing\n",
+ pRecord_->name, driverName, functionName);
+ }
+ } else {
+ /* Copy data from ring buffer */
+ EPICS_TYPE *pData = (EPICS_TYPE *)pRecord_->bptr;
+ ringBufferElement *rp = &result_;
+ int i;
+ /* Need to copy the array with the lock because that is shared even though
+ result_ is a copy */
+ if (rp->status == asynSuccess) {
+ epicsMutexLock(ringBufferLock_);
+ for (i=0; i<(int)rp->len; i++) pData[i] = rp->pValue[i];
+ epicsMutexUnlock(ringBufferLock_);
+ pRecord_->nord = (epicsUInt32)rp->len;
+ asynPrintIO(pasynUser_, ASYN_TRACEIO_DEVICE,
+ (char *)pRecord_->bptr, pRecord_->nord*sizeof(EPICS_TYPE),
+ "%s %s::%s nord=%d, pRecord_->bptr data:",
+ pRecord_->name, driverName, driverName, pRecord_->nord);
+ }
+ pRecord_->time = rp->time;
+ }
+ }
+ pasynEpicsUtils->asynStatusToEpicsAlarm(result_.status,
+ READ_ALARM, &result_.alarmStatus,
+ INVALID_ALARM, &result_.alarmSeverity);
+ recGblSetSevr(pRecord_, result_.alarmStatus, result_.alarmSeverity);
+ if (result_.status == asynSuccess) {
+ pRecord_->udf = 0;
+ return 0;
+ } else {
+ result_.status = asynSuccess;
+ return -1;
+ }
+ }
+
+ void queueRequestCallback()
+ {
+ static const char *functionName = "queueRequestCallback";
+ size_t nread;
+
+ if (isOutput_) {
+ result_.status = pInterface_->write(pInterfacePvt_, pasynUser_,
+ (EPICS_TYPE *) pRecord_->bptr, pRecord_->nord);
+ } else {
+ result_.status = pInterface_->read(pInterfacePvt_, pasynUser_, (EPICS_TYPE *) pRecord_->bptr,
+ pRecord_->nelm, &nread);
+ }
+ result_.time = pasynUser_->timestamp;
+ result_.alarmStatus = (epicsAlarmCondition) pasynUser_->alarmStatus;
+ result_.alarmSeverity = (epicsAlarmSeverity) pasynUser_->alarmSeverity;
+ if (result_.status == asynSuccess) {
+ if (!isOutput_) {
+ pRecord_->udf=0;
+ pRecord_->nord = (epicsUInt32)nread;
+ }
+ asynPrint(pasynUser_, ASYN_TRACEIO_DEVICE,
+ "%s %s::%s OK\n", pRecord_->name, driverName, functionName);
+ } else {
+ if (result_.status != lastStatus_) {
+ asynPrint(pasynUser_, ASYN_TRACE_ERROR,
+ "%s %s::%s %s error %s\n",
+ pRecord_->name, driverName, functionName, isOutput_ ? "write" : "read", pasynUser_->errorMessage);
+ }
+ }
+ lastStatus_ = result_.status;
+ if (pRecord_->pact) callbackRequestProcessCallback(&callback_, pRecord_->prio, pRecord_);
+ }
+
+ int getRingBufferValue()
+ {
+ int ret = 0;
+ static const char *functionName = "getRingBufferValue ";
+
+ epicsMutexLock(ringBufferLock_);
+ if (ringTail_ != ringHead_) {
+ if (ringBufferOverflows_ > 0) {
+ asynPrint(pasynUser_, ASYN_TRACE_WARNING,
+ "%s %s::%s error, %d ring buffer overflows\n",
+ pRecord_->name, driverName, functionName, ringBufferOverflows_);
+ ringBufferOverflows_ = 0;
+ }
+ result_ = ringBuffer_[ringTail_];
+ ringTail_ = (ringTail_ == ringSize_-1) ? 0 : ringTail_ + 1;
+ ret = 1;
+ }
+ epicsMutexUnlock(ringBufferLock_);
+ return ret;
+ }
+
+ void interruptCallback(asynUser *pasynUser, EPICS_TYPE *value, size_t len)
+ {
+ int i;
+ EPICS_TYPE *pData = (EPICS_TYPE *)pRecord_->bptr;
+ static const char *functionName = "interruptCallback";
+
+ asynPrintIO(pasynUser_, ASYN_TRACEIO_DEVICE,
+ (char *)value, len*sizeof(EPICS_TYPE),
+ "%s %s::%s ringSize=%d, len=%d, callback data:",
+ pRecord_->name, driverName, functionName, ringSize_, (int)len);
+ if (ringSize_ == 0) {
+ /* Not using a ring buffer */
+ dbScanLock((dbCommon *)pRecord_);
+ if (len > pRecord_->nelm) len = pRecord_->nelm;
+ if (pasynUser->auxStatus == asynSuccess) {
+ for (i=0; i<(int)len; i++) pData[i] = value[i];
+ pRecord_->nord = (epicsUInt32)len;
+ }
+ pRecord_->time = pasynUser->timestamp;
+ result_.status = (asynStatus) pasynUser->auxStatus;
+ result_.alarmStatus = (epicsAlarmCondition) pasynUser->alarmStatus;
+ result_.alarmSeverity = (epicsAlarmSeverity) pasynUser->alarmSeverity;
+ gotValue_++;
+ dbScanUnlock((dbCommon *)pRecord_);
+ if (isOutput_)
+ scanOnce((dbCommon *)pRecord_);
+ else
+ scanIoRequest(ioScanPvt_);
+ } else {
+ /* Using a ring buffer */
+ ringBufferElement *rp;
+
+ /* If interruptAccept is false we just return. This prevents more ring pushes than pops.
+ * There will then be nothing in the ring buffer, so the first
+ * read will do a read from the driver, which should be OK. */
+ if (!interruptAccept) return;
+
+ epicsMutexLock(ringBufferLock_);
+ rp = &ringBuffer_[ringHead_];
+ if (len > pRecord_->nelm) len = pRecord_->nelm;
+ rp->len = len;
+ for (i=0; i<(int)len; i++) rp->pValue[i] = value[i];
+ rp->time = pasynUser->timestamp;
+ rp->status = (asynStatus) pasynUser->auxStatus;
+ rp->alarmStatus = (epicsAlarmCondition) pasynUser->alarmStatus;
+ rp->alarmSeverity = (epicsAlarmSeverity) pasynUser->alarmSeverity;
+ ringHead_ = (ringHead_ == ringSize_ - 1) ? 0 : ringHead_ + 1;
+ if (ringHead_ == ringTail_) {
+ /* There was no room in the ring buffer. In the past we just threw away
+ * the new value. However, it is better to remove the oldest value from the
+ * ring buffer and add the new one. That way the final value the record receives
+ * is guaranteed to be the most recent value */
+ ringTail_ = (ringTail_ == ringSize_ - 1) ? 0 : ringTail_ + 1;
+ ringBufferOverflows_++;
+ } else {
+ /* We only need to request the record to process if we added a new
+ * element to the ring buffer, not if we just replaced an element. */
+ if (isOutput_)
+ scanOnce((dbCommon *)pRecord_);
+ else
+ scanIoRequest(ioScanPvt_);
+ }
+ epicsMutexUnlock(ringBufferLock_);
+ }
+ }
+};
+
+struct analogDset { /* analog dset */
+ long number;
+ DEVSUPFUN dev_report;
+ DEVSUPFUN init;
+ long (*init_record)(dbCommon *pr);
+ long (*get_ioint_info)(int cmd, dbCommon *pr, IOSCANPVT *iopvt);
+ long (*process)(dbCommon *pr);
+ DEVSUPFUN special_linconv;
+};
+
+} // End of namespace
+
+#define MAKE_DEVSUP(DSET, REC, LINK, INTERFACE, INTERFACE_NAME, INTERRUPT, EPICS_TYPE, \
+ INIT_FUNC, GET_INFO_FUNC, PROC_FUNC, QRCB_FUNC, INTCB_FUNC, \
+ SIGNED_TYPE, UNSIGNED_TYPE, IS_OUTPUT) \
+static long GET_INFO_FUNC(int cmd, dbCommon *pr, IOSCANPVT *iopvt) { \
+ devAsynXXXArray *pObj = \
+ (devAsynXXXArray *) pr->dpvt; \
+ return pObj->getIoIntInfo(cmd, iopvt); \
+} \
+static long PROC_FUNC(dbCommon *pr) { \
+ devAsynXXXArray *pObj = \
+ (devAsynXXXArray *) pr->dpvt; \
+ return pObj->process(); \
+} \
+static void QRCB_FUNC(asynUser *pasynUser) { \
+ devAsynXXXArray *pObj = \
+ (devAsynXXXArray *) pasynUser->userPvt; \
+ pObj->queueRequestCallback(); \
+} \
+static void INTCB_FUNC(void *drvPvt, asynUser *pasynUser, EPICS_TYPE *value, size_t len) { \
+ devAsynXXXArray *pObj = \
+ (devAsynXXXArray *) drvPvt; \
+ pObj->interruptCallback(pasynUser, value, len); \
+} \
+static long INIT_FUNC(dbCommon *pr) { \
+ new devAsynXXXArray \
+ (pr, &((REC *)pr)->LINK, SIGNED_TYPE, UNSIGNED_TYPE, IS_OUTPUT, \
+ INTERFACE_NAME, QRCB_FUNC, INTCB_FUNC); \
+ return 0; \
+} \
+static analogDset DSET = {6, 0, 0, INIT_FUNC, GET_INFO_FUNC, PROC_FUNC, 0}; \
+epicsExportAddress(dset, DSET);
+
+extern "C" {
+// 8-bit integer arrays
+MAKE_DEVSUP(asynInt8ArrayWfIn, waveformRecord, inp, asynInt8Array, "asynInt8Array", interruptCallbackInt8Array, epicsInt8,
+ initInt8WfIn, getInfoInt8WfIn, processInt8WfIn, qrCallbackInt8WfIn, intCallbackInt8WfIn,
+ menuFtypeCHAR, menuFtypeUCHAR, false);
+MAKE_DEVSUP(asynInt8ArrayWfOut, waveformRecord, inp, asynInt8Array, "asynInt8Array", interruptCallbackInt8Array, epicsInt8,
+ initInt8WfOut, getInfoInt8WfOut, processInt8WfOut, qrCallbackInt8WfOut, intCallbackInt8WfOut,
+ menuFtypeCHAR, menuFtypeUCHAR, true);
+MAKE_DEVSUP(asynInt8ArrayAai, aaiRecord, inp, asynInt8Array, "asynInt8Array", interruptCallbackInt8Array, epicsInt8,
+ initInt8AaiIn, getInfoInt8Aai, processInt8Aai, qrCallbackInt8Aai, intCallbackInt8Aai,
+ menuFtypeCHAR, menuFtypeUCHAR, false);
+MAKE_DEVSUP(asynInt8ArrayAao, aaoRecord, out, asynInt8Array, "asynInt8Array", interruptCallbackInt8Array, epicsInt8,
+ initInt8Aao, getInfoInt8Aao, processInt8Aao, qrCallbackInt8Aao, intCallbackInt8Aao,
+ menuFtypeCHAR, menuFtypeUCHAR, true);
+
+// 16-bit integer arrays
+MAKE_DEVSUP(asynInt16ArrayWfIn, waveformRecord, inp, asynInt16Array, "asynInt16Array", interruptCallbackInt16Array, epicsInt16,
+ initInt16WfIn, getInfoInt16WfIn, processInt16WfIn, qrCallbackInt16WfIn, intCallbackInt16WfIn,
+ menuFtypeSHORT, menuFtypeUSHORT, false);
+MAKE_DEVSUP(asynInt16ArrayWfOut, waveformRecord, inp, asynInt16Array, "asynInt16Array", interruptCallbackInt16Array, epicsInt16,
+ initInt16WfOut, getInfoInt16WfOut, processInt16WfOut, qrCallbackInt16WfOut, intCallbackInt16WfOut,
+ menuFtypeSHORT, menuFtypeUSHORT, true);
+MAKE_DEVSUP(asynInt16ArrayAai, aaiRecord, inp, asynInt16Array, "asynInt16Array", interruptCallbackInt16Array, epicsInt16,
+ initInt16AaiIn, getInfoInt16Aai, processInt16Aai, qrCallbackInt16Aai, intCallbackInt16Aai,
+ menuFtypeSHORT, menuFtypeUSHORT, false);
+MAKE_DEVSUP(asynInt16ArrayAao, aaoRecord, out, asynInt16Array, "asynInt16Array", interruptCallbackInt16Array, epicsInt16,
+ initInt16Aao, getInfoInt16Aao, processInt16Aao, qrCallbackInt16Aao, intCallbackInt16Aao,
+ menuFtypeSHORT, menuFtypeUSHORT, true);
+
+// 32-bit integer arrays
+MAKE_DEVSUP(asynInt32ArrayWfIn, waveformRecord, inp, asynInt32Array, "asynInt32Array", interruptCallbackInt32Array, epicsInt32,
+ initInt32WfIn, getInfoInt32WfIn, processInt32WfIn, qrCallbackInt32WfIn, intCallbackInt32WfIn,
+ menuFtypeLONG, menuFtypeULONG, false);
+MAKE_DEVSUP(asynInt32ArrayWfOut, waveformRecord, inp, asynInt32Array, "asynInt32Array", interruptCallbackInt32Array, epicsInt32,
+ initInt32WfOut, getInfoInt32WfOut, processInt32WfOut, qrCallbackInt32WfOut, intCallbackInt32WfOut,
+ menuFtypeLONG, menuFtypeULONG, true);
+MAKE_DEVSUP(asynInt32ArrayAai, aaiRecord, inp, asynInt32Array, "asynInt32Array", interruptCallbackInt32Array, epicsInt32,
+ initInt32AaiIn, getInfoInt32Aai, processInt32Aai, qrCallbackInt32Aai, intCallbackInt32Aai,
+ menuFtypeLONG, menuFtypeULONG, false);
+MAKE_DEVSUP(asynInt32ArrayAao, aaoRecord, out, asynInt32Array, "asynInt32Array", interruptCallbackInt32Array, epicsInt32,
+ initInt32Aao, getInfoInt32Aao, processInt32Aao, qrCallbackInt32Aao, intCallbackInt32Aao,
+ menuFtypeLONG, menuFtypeULONG, true);
+
+// 64-bit integer arrays
+#ifdef HAVE_DEVINT64
+MAKE_DEVSUP(asynInt64ArrayWfIn, waveformRecord, inp, asynInt64Array, "asynInt64Array", interruptCallbackInt64Array, epicsInt64,
+ initInt64WfIn, getInfoInt64WfIn, processInt64WfIn, qrCallbackInt64WfIn, intCallbackInt64WfIn,
+ menuFtypeINT64, menuFtypeUINT64, false);
+MAKE_DEVSUP(asynInt64ArrayWfOut, waveformRecord, inp, asynInt64Array, "asynInt64Array", interruptCallbackInt64Array, epicsInt64,
+ initInt64WfOut, getInfoInt64WfOut, processInt64WfOut, qrCallbackInt64WfOut, intCallbackInt64WfOut,
+ menuFtypeINT64, menuFtypeUINT64, true);
+MAKE_DEVSUP(asynInt64ArrayAai, aaiRecord, inp, asynInt64Array, "asynInt64Array", interruptCallbackInt64Array, epicsInt64,
+ initInt64AaiIn, getInfoInt64Aai, processInt64Aai, qrCallbackInt64Aai, intCallbackInt64Aai,
+ menuFtypeINT64, menuFtypeUINT64, false);
+MAKE_DEVSUP(asynInt64ArrayAao, aaoRecord, out, asynInt64Array, "asynInt64Array", interruptCallbackInt64Array, epicsInt64,
+ initInt64Aao, getInfoInt64Aao, processInt64Aao, qrCallbackInt64Aao, intCallbackInt64Aao,
+ menuFtypeINT64, menuFtypeUINT64, true);
+#endif
+
+// 32-bit float arrays
+MAKE_DEVSUP(asynFloat32ArrayWfIn, waveformRecord, inp, asynFloat32Array, "asynFloat32Array", interruptCallbackFloat32Array, epicsFloat32,
+ initFloat32WfIn, getInfoFloat32WfIn, processFloat32WfIn, qrCallbackFloat32WfIn, intCallbackFloat32WfIn,
+ menuFtypeFLOAT, menuFtypeFLOAT, false);
+MAKE_DEVSUP(asynFloat32ArrayWfOut, waveformRecord, inp, asynFloat32Array, "asynFloat32Array", interruptCallbackFloat32Array, epicsFloat32,
+ initFloat32WfOut, getInfoFloat32WfOut, processFloat32WfOut, qrCallbackFloat32WfOut, intCallbackFloat32WfOut,
+ menuFtypeFLOAT, menuFtypeFLOAT, true);
+MAKE_DEVSUP(asynFloat32ArrayAai, aaiRecord, inp, asynFloat32Array, "asynFloat32Array", interruptCallbackFloat32Array, epicsFloat32,
+ initFloat32AaiIn, getInfoFloat32Aai, processFloat32Aai, qrCallbackFloat32Aai, intCallbackFloat32Aai,
+ menuFtypeFLOAT, menuFtypeFLOAT, false);
+MAKE_DEVSUP(asynFloat32ArrayAao, aaoRecord, out, asynFloat32Array, "asynFloat32Array", interruptCallbackFloat32Array, epicsFloat32,
+ initFloat32Aao, getInfoFloat32Aao, processFloat32Aao, qrCallbackFloat32Aao, intCallbackFloat32Aao,
+ menuFtypeFLOAT, menuFtypeFLOAT, true);
+
+// 64-bit float arrays
+MAKE_DEVSUP(asynFloat64ArrayWfIn, waveformRecord, inp, asynFloat64Array, "asynFloat64Array", interruptCallbackFloat64Array, epicsFloat64,
+ initFloat64WfIn, getInfoFloat64WfIn, processFloat64WfIn, qrCallbackFloat64WfIn, intCallbackFloat64WfIn,
+ menuFtypeDOUBLE, menuFtypeDOUBLE, false);
+MAKE_DEVSUP(asynFloat64ArrayWfOut, waveformRecord, inp, asynFloat64Array, "asynFloat64Array", interruptCallbackFloat64Array, epicsFloat64,
+ initFloat64WfOut, getInfoFloat64WfOut, processFloat64WfOut, qrCallbackFloat64WfOut, intCallbackFloat64WfOut,
+ menuFtypeDOUBLE, menuFtypeDOUBLE, true);
+MAKE_DEVSUP(asynFloat64ArrayAai, aaiRecord, inp, asynFloat64Array, "asynFloat64Array", interruptCallbackFloat64Array, epicsFloat64,
+ initFloat64AaiIn, getInfoFloat64Aai, processFloat64Aai, qrCallbackFloat64Aai, intCallbackFloat64Aai,
+ menuFtypeDOUBLE, menuFtypeDOUBLE, false);
+MAKE_DEVSUP(asynFloat64ArrayAao, aaoRecord, out, asynFloat64Array, "asynFloat64Array", interruptCallbackFloat64Array, epicsFloat64,
+ initFloat64Aao, getInfoFloat64Aao, processFloat64Aao, qrCallbackFloat64Aao, intCallbackFloat64Aao,
+ menuFtypeDOUBLE, menuFtypeDOUBLE, true);
+
+} /* extern "C" */
diff --git a/asyn/devEpics/devAsynXXXArray.dbd b/asyn/devEpics/devAsynXXXArray.dbd
new file mode 100644
index 0000000..cc0bc18
--- /dev/null
+++ b/asyn/devEpics/devAsynXXXArray.dbd
@@ -0,0 +1,24 @@
+device(waveform, INST_IO, asynInt8ArrayWfIn, "asynInt8ArrayIn")
+device(waveform, INST_IO, asynInt8ArrayWfOut, "asynInt8ArrayOut")
+device(aai, INST_IO, asynInt8ArrayAai, "asynInt8ArrayIn")
+device(aao, INST_IO, asynInt8ArrayAao, "asynInt8ArrayOut")
+
+device(waveform, INST_IO, asynInt16ArrayWfIn, "asynInt16ArrayIn")
+device(waveform, INST_IO, asynInt16ArrayWfOut, "asynInt16ArrayOut")
+device(aai, INST_IO, asynInt16ArrayAai, "asynInt16ArrayIn")
+device(aao, INST_IO, asynInt16ArrayAao, "asynInt16ArrayOut")
+
+device(waveform, INST_IO, asynInt32ArrayWfIn, "asynInt32ArrayIn")
+device(waveform, INST_IO, asynInt32ArrayWfOut, "asynInt32ArrayOut")
+device(aai, INST_IO, asynInt32ArrayAai, "asynInt32ArrayIn")
+device(aao, INST_IO, asynInt32ArrayAao, "asynInt32ArrayOut")
+
+device(waveform, INST_IO, asynFloat32ArrayWfIn, "asynFloat32ArrayIn")
+device(waveform, INST_IO, asynFloat32ArrayWfOut, "asynFloat32ArrayOut")
+device(aai, INST_IO, asynFloat32ArrayAai, "asynFloat32ArrayIn")
+device(aao, INST_IO, asynFloat32ArrayAao, "asynFloat32ArrayOut")
+
+device(waveform, INST_IO, asynFloat64ArrayWfIn, "asynFloat64ArrayIn")
+device(waveform, INST_IO, asynFloat64ArrayWfOut, "asynFloat64ArrayOut")
+device(aai, INST_IO, asynFloat64ArrayAai, "asynFloat64ArrayIn")
+device(aao, INST_IO, asynFloat64ArrayAao, "asynFloat64ArrayOut")
diff --git a/asyn/devEpics/devAsynXXXArray.h b/asyn/devEpics/devAsynXXXArray.h
deleted file mode 100644
index b89a142..0000000
--- a/asyn/devEpics/devAsynXXXArray.h
+++ /dev/null
@@ -1,487 +0,0 @@
-#define INIT_OK 0
-#define INIT_DO_NOT_CONVERT 2
-#define INIT_ERROR -1
-
-#define DEFAULT_RING_BUFFER_SIZE 0
-
-#define ASYN_XXX_ARRAY_FUNCS(DRIVER_NAME, INTERFACE, INTERFACE_TYPE, \
- INTERRUPT, EPICS_TYPE, DSET_IN, DSET_OUT, \
- SIGNED_TYPE, UNSIGNED_TYPE) \
-/* devAsynXXXArray.h */ \
-/*********************************************************************** \
-* Copyright (c) 2002 The University of Chicago, as Operator of Argonne \
-* National Laboratory, and the Regents of the University of \
-* California, as Operator of Los Alamos National Laboratory, and \
-* Berliner Elektronenspeicherring-Gesellschaft m.b.H. (BESSY). \
-* asynDriver is distributed subject to a Software License Agreement \
-* found in file LICENSE that is included with this distribution. \
-***********************************************************************/ \
-/* \
- Oroginal author: Geoff Savage \
- 19NOV2004 \
- \
- Current author: Mark Rivers \
-*/ \
- \
- \
-typedef struct ringBufferElement { \
- EPICS_TYPE *pValue; \
- size_t len; \
- epicsTimeStamp time; \
- asynStatus status; \
- epicsAlarmCondition alarmStatus; \
- epicsAlarmSeverity alarmSeverity; \
-} ringBufferElement; \
- \
-typedef struct devAsynWfPvt{ \
- dbCommon *pr; \
- asynUser *pasynUser; \
- INTERFACE *pArray; \
- void *arrayPvt; \
- void *registrarPvt; \
- int canBlock; \
- CALLBACK callback; \
- IOSCANPVT ioScanPvt; \
- asynStatus status; \
- int isOutput; \
- epicsMutexId ringBufferLock; \
- ringBufferElement *ringBuffer; \
- int ringHead; \
- int ringTail; \
- int ringSize; \
- int ringBufferOverflows; \
- ringBufferElement result; \
- int gotValue; /* For interruptCallbackInput */ \
- INTERRUPT interruptCallback; \
- char *portName; \
- char *userParam; \
- int addr; \
- asynStatus previousQueueRequestStatus; \
-} devAsynWfPvt; \
- \
-static long getIoIntInfo(int cmd, dbCommon *pr, IOSCANPVT *iopvt); \
-static long initCommon(dbCommon *pr, DBLINK *plink, \
- userCallback callback, INTERRUPT interruptCallback, int isOutput); \
-static long processCommon(dbCommon *pr); \
-static long initWfArrayIn(waveformRecord *pwf); \
-static long initWfArrayOut(waveformRecord *pwf); \
-/* processCommon callbacks */ \
-static void callbackWfIn(asynUser *pasynUser); \
-static void callbackWfOut(asynUser *pasynUser); \
-static int getRingBufferValue(devAsynWfPvt *pPvt); \
-static long createRingBuffer(dbCommon *pr); \
-static void interruptCallback(void *drvPvt, asynUser *pasynUser, \
- EPICS_TYPE *value, size_t len); \
- \
-typedef struct analogDset { /* analog dset */ \
- long number; \
- DEVSUPFUN dev_report; \
- DEVSUPFUN init; \
- DEVSUPFUN init_record; \
- DEVSUPFUN get_ioint_info; \
- DEVSUPFUN processCommon;/*(0)=>(success ) */ \
- DEVSUPFUN special_linconv; \
-} analogDset; \
- \
-analogDset DSET_IN = \
- {6, 0, 0, initWfArrayIn, getIoIntInfo, processCommon, 0}; \
-analogDset DSET_OUT = \
- {6, 0, 0, initWfArrayOut, getIoIntInfo, processCommon, 0}; \
- \
-epicsExportAddress(dset, DSET_IN); \
-epicsExportAddress(dset, DSET_OUT); \
- \
-static char *driverName = DRIVER_NAME; \
- \
-static long initCommon(dbCommon *pr, DBLINK *plink, \
- userCallback callback, INTERRUPT interruptCallback, int isOutput) \
-{ \
- waveformRecord *pwf = (waveformRecord *)pr; \
- devAsynWfPvt *pPvt; \
- int status; \
- asynUser *pasynUser; \
- asynInterface *pasynInterface; \
- \
- pPvt = callocMustSucceed(1, sizeof(*pPvt), "devAsynXXXArray::initCommon"); \
- pr->dpvt = pPvt; \
- pPvt->pr = pr; \
- pPvt->isOutput = isOutput; \
- pPvt->interruptCallback = interruptCallback; \
- pasynUser = pasynManager->createAsynUser(callback, 0); \
- pasynUser->userPvt = pPvt; \
- pPvt->pasynUser = pasynUser; \
- pPvt->ringBufferLock = epicsMutexCreate(); \
- /* This device support only supports signed and unsigned versions of the EPICS data type */ \
- if ((pwf->ftvl != SIGNED_TYPE) && (pwf->ftvl != UNSIGNED_TYPE)) { \
- errlogPrintf("%s::initCommon, %s field type must be SIGNED_TYPE or UNSIGNED_TYPE\n", \
- driverName, pr->name); \
- goto bad; \
- } \
- /* Parse the link to get addr and port */ \
- status = pasynEpicsUtils->parseLink(pasynUser, plink, \
- &pPvt->portName, &pPvt->addr, &pPvt->userParam); \
- if (status != asynSuccess) { \
- errlogPrintf("%s::initCommon, %s error in link %s\n", \
- driverName, pr->name, pasynUser->errorMessage); \
- goto bad; \
- } \
- status = pasynManager->connectDevice(pasynUser, pPvt->portName, pPvt->addr); \
- if (status != asynSuccess) { \
- errlogPrintf("%s::initCommon, %s connectDevice failed %s\n", \
- driverName, pr->name, pasynUser->errorMessage); \
- goto bad; \
- } \
- pasynInterface = pasynManager->findInterface(pasynUser,asynDrvUserType,1); \
- if(pasynInterface && pPvt->userParam) { \
- asynDrvUser *pasynDrvUser; \
- void *drvPvt; \
- \
- pasynDrvUser = (asynDrvUser *)pasynInterface->pinterface; \
- drvPvt = pasynInterface->drvPvt; \
- status = pasynDrvUser->create(drvPvt,pasynUser, \
- pPvt->userParam,0,0); \
- if(status!=asynSuccess) { \
- errlogPrintf( \
- "%s::initCommon, %s drvUserCreate failed %s\n", \
- driverName, pr->name, pasynUser->errorMessage); \
- goto bad; \
- } \
- } \
- pasynInterface = pasynManager->findInterface(pasynUser,INTERFACE_TYPE,1); \
- if(!pasynInterface) { \
- errlogPrintf( \
- "%s::initCommon, %s find %s interface failed %s\n", \
- driverName, pr->name, INTERFACE_TYPE,pasynUser->errorMessage); \
- goto bad; \
- } \
- pPvt->pArray = pasynInterface->pinterface; \
- pPvt->arrayPvt = pasynInterface->drvPvt; \
- /* If this is an output record and the info field "asyn:READBACK" is 1 \
- * then register for callbacks on output records */ \
- if (pPvt->isOutput) { \
- int enableCallbacks=0; \
- const char *callbackString; \
- DBENTRY *pdbentry = dbAllocEntry(pdbbase); \
- status = dbFindRecord(pdbentry, pr->name); \
- if (status) { \
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR, \
- "%s %s::initCommon error finding record\n", \
- pr->name, driverName); \
- goto bad; \
- } \
- callbackString = dbGetInfo(pdbentry, "asyn:READBACK"); \
- if (callbackString) enableCallbacks = atoi(callbackString); \
- if (enableCallbacks) { \
- status = createRingBuffer(pr); \
- if (status != asynSuccess) goto bad; \
- status = pPvt->pArray->registerInterruptUser( \
- pPvt->arrayPvt, pPvt->pasynUser, \
- pPvt->interruptCallback, pPvt, &pPvt->registrarPvt); \
- if(status != asynSuccess) { \
- printf("%s %s::initCommon error calling registerInterruptUser %s\n", \
- pr->name, driverName, pPvt->pasynUser->errorMessage); \
- } \
- } \
- } \
- scanIoInit(&pPvt->ioScanPvt); \
- /* Determine if device can block */ \
- pasynManager->canBlock(pasynUser, &pPvt->canBlock); \
- return 0; \
-bad: \
- recGblSetSevr(pr,LINK_ALARM,INVALID_ALARM); \
- pr->pact=1; \
- return INIT_ERROR; \
-} \
- \
-static long createRingBuffer(dbCommon *pr) \
-{ \
- devAsynWfPvt *pPvt = (devAsynWfPvt *)pr->dpvt; \
- asynStatus status; \
- waveformRecord *pwf = (waveformRecord *)pr; \
- const char *sizeString; \
- \
- if (!pPvt->ringBuffer) { \
- DBENTRY *pdbentry = dbAllocEntry(pdbbase); \
- pPvt->ringSize = DEFAULT_RING_BUFFER_SIZE; \
- status = dbFindRecord(pdbentry, pr->name); \
- if (status) \
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR, \
- "%s %s::getIoIntInfo error finding record\n", \
- pr->name, driverName); \
- sizeString = dbGetInfo(pdbentry, "asyn:FIFO"); \
- if (sizeString) pPvt->ringSize = atoi(sizeString); \
- if (pPvt->ringSize > 0) { \
- int i; \
- pPvt->ringBuffer = callocMustSucceed( \
- pPvt->ringSize, sizeof(*pPvt->ringBuffer), \
- "devAsynXXXArray::getIoIntInfo creating ring buffer"); \
- /* Allocate array for each ring buffer element */ \
- for (i=0; iringSize; i++) { \
- pPvt->ringBuffer[i].pValue = \
- (EPICS_TYPE *)callocMustSucceed( \
- pwf->nelm, sizeof(EPICS_TYPE), \
- "devAsynXXXArray::getIoIntInfo creating ring element array"); \
- } \
- } \
- } \
- return asynSuccess; \
-} \
- \
-static long getIoIntInfo(int cmd, dbCommon *pr, IOSCANPVT *iopvt) \
-{ \
- devAsynWfPvt *pPvt = (devAsynWfPvt *)pr->dpvt; \
- int status; \
- \
- /* If initCommon failed then pPvt->pArray is NULL, return error */ \
- if (!pPvt->pArray) return -1; \
- \
- if (cmd == 0) { \
- /* Add to scan list. Register interrupts */ \
- asynPrint(pPvt->pasynUser, ASYN_TRACE_FLOW, \
- "%s %s::getIoIntInfo registering interrupt\n", \
- pr->name, driverName); \
- createRingBuffer(pr); \
- status = pPvt->pArray->registerInterruptUser( \
- pPvt->arrayPvt, pPvt->pasynUser, \
- pPvt->interruptCallback, pPvt, &pPvt->registrarPvt); \
- if(status!=asynSuccess) { \
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR, \
- "%s %s::getIoIntInfo registerInterruptUser %s\n", \
- pr->name, driverName, pPvt->pasynUser->errorMessage); \
- } \
- } else { \
- asynPrint(pPvt->pasynUser, ASYN_TRACE_FLOW, \
- "%s %s::getIoIntInfo cancelling interrupt\n", \
- pr->name, driverName); \
- status = pPvt->pArray->cancelInterruptUser(pPvt->arrayPvt, \
- pPvt->pasynUser, pPvt->registrarPvt); \
- if(status!=asynSuccess) { \
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR, \
- "%s %s::getIoIntInfo cancelInterruptUser %s\n", \
- pr->name, driverName,pPvt->pasynUser->errorMessage); \
- } \
- } \
- *iopvt = pPvt->ioScanPvt; \
- return INIT_OK; \
-} \
- \
-static void reportQueueRequestStatus(devAsynWfPvt *pPvt, asynStatus status) \
-{ \
- if (pPvt->previousQueueRequestStatus != status) { \
- pPvt->previousQueueRequestStatus = status; \
- if (status == asynSuccess) { \
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR, \
- "%s %s queueRequest status returned to normal\n", \
- pPvt->pr->name, driverName); \
- } else { \
- asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR, \
- "%s %s queueRequest %s\n", \
- pPvt->pr->name, driverName, pPvt->pasynUser->errorMessage); \
- } \
- } \
-} \
- \
-static long initWfArrayOut(waveformRecord *pwf) \
-{ return initCommon((dbCommon *)pwf, (DBLINK *)&pwf->inp, \
- callbackWfOut, interruptCallback, 1); } \
- \
-static long initWfArrayIn(waveformRecord *pwf) \
-{ return initCommon((dbCommon *)pwf, (DBLINK *)&pwf->inp, \
- callbackWfIn, interruptCallback, 0); } \
- \
-static long processCommon(dbCommon *pr) \
-{ \
- devAsynWfPvt *pPvt = (devAsynWfPvt *)pr->dpvt; \
- waveformRecord *pwf = (waveformRecord *)pr; \
- int newInputData; \
- asynStatus status; \
- \
- if (pPvt->ringSize == 0) { \
- newInputData = pPvt->gotValue; \
- } else { \
- newInputData = getRingBufferValue(pPvt); \
- } \
- if (!newInputData && !pr->pact) { /* This is an initial call from record */ \
- if(pPvt->canBlock) pr->pact = 1; \
- status = pasynManager->queueRequest(pPvt->pasynUser, 0, 0); \
- if((status==asynSuccess) && pPvt->canBlock) return 0; \
- if(pPvt->canBlock) pr->pact = 0; \
- reportQueueRequestStatus(pPvt, status); \
- } \
- if (newInputData) { \
- if (pPvt->ringSize == 0){ \
- /* Data has already been copied to the record in interruptCallback */ \
- pPvt->gotValue--; \
- if (pPvt->gotValue) { \
- asynPrint(pPvt->pasynUser, ASYN_TRACE_WARNING, \
- "%s %s::processCommon, " \
- "warning: multiple interrupt callbacks between processing\n", \
- pr->name, driverName); \
- } \
- } else { \
- /* Copy data from ring buffer */ \
- EPICS_TYPE *pData = (EPICS_TYPE *)pwf->bptr; \
- ringBufferElement *rp = &pPvt->result; \
- int i; \
- /* Need to copy the array with the lock because that is shared even though \
- pPvt->result is a copy */ \
- if (rp->status == asynSuccess) { \
- epicsMutexLock(pPvt->ringBufferLock); \
- for (i=0; i<(int)rp->len; i++) pData[i] = rp->pValue[i]; \
- epicsMutexUnlock(pPvt->ringBufferLock); \
- pwf->nord = rp->len; \
- asynPrintIO(pPvt->pasynUser, ASYN_TRACEIO_DEVICE, \
- (char *)pwf->bptr, pwf->nord*sizeof(EPICS_TYPE), \
- "%s %s::processCommon nord=%d, pwf->bptr data:", \
- pwf->name, driverName, pwf->nord); \
- } \
- pwf->time = rp->time; \
- } \
- } \
- pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status, \
- READ_ALARM, &pPvt->result.alarmStatus, \
- INVALID_ALARM, &pPvt->result.alarmSeverity); \
- recGblSetSevr(pr, pPvt->result.alarmStatus, pPvt->result.alarmSeverity); \
- if (pPvt->result.status == asynSuccess) { \
- pwf->udf = 0; \
- return 0; \
- } else { \
- pPvt->result.status = asynSuccess; \
- return -1; \
- } \
-} \
- \
-static void callbackWfOut(asynUser *pasynUser) \
-{ \
- devAsynWfPvt *pPvt = (devAsynWfPvt *)pasynUser->userPvt; \
- waveformRecord *pwf = (waveformRecord *)pPvt->pr; \
- \
- asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, \
- "%s %s::callbackWfOut\n", pwf->name, driverName); \
- pPvt->result.status = pPvt->pArray->write(pPvt->arrayPvt, pPvt->pasynUser, \
- pwf->bptr, pwf->nord); \
- pPvt->result.time = pPvt->pasynUser->timestamp; \
- pPvt->result.alarmStatus = pPvt->pasynUser->alarmStatus; \
- pPvt->result.alarmSeverity = pPvt->pasynUser->alarmSeverity; \
- if (pPvt->result.status == asynSuccess) { \
- asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, \
- "%s %s::callbackWfOut OK\n", pwf->name, driverName); \
- } else { \
- asynPrint(pasynUser, ASYN_TRACE_ERROR, \
- "%s %s::callbackWfOut write error %s\n", \
- pwf->name, driverName, pasynUser->errorMessage); \
- } \
- if(pwf->pact) callbackRequestProcessCallback(&pPvt->callback,pwf->prio,pwf); \
-} \
- \
-static void callbackWfIn(asynUser *pasynUser) \
-{ \
- devAsynWfPvt *pPvt = (devAsynWfPvt *)pasynUser->userPvt; \
- waveformRecord *pwf = (waveformRecord *)pPvt->pr; \
- size_t nread; \
- \
- pPvt->result.status = pPvt->pArray->read(pPvt->arrayPvt, pPvt->pasynUser, pwf->bptr, \
- pwf->nelm, &nread); \
- asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, \
- "%s %s::callbackWfIn\n", pwf->name, driverName); \
- pPvt->result.time = pPvt->pasynUser->timestamp; \
- pPvt->result.alarmStatus = pPvt->pasynUser->alarmStatus; \
- pPvt->result.alarmSeverity = pPvt->pasynUser->alarmSeverity; \
- if (pPvt->result.status == asynSuccess) { \
- pwf->udf=0; \
- pwf->nord = (epicsUInt32)nread; \
- } else { \
- asynPrint(pasynUser, ASYN_TRACE_ERROR, \
- "%s %s::callbackWfIn read error %s\n", \
- pwf->name, driverName, pasynUser->errorMessage); \
- } \
- if(pwf->pact) callbackRequestProcessCallback(&pPvt->callback,pwf->prio,pwf); \
-} \
- \
-static int getRingBufferValue(devAsynWfPvt *pPvt) \
-{ \
- int ret = 0; \
- epicsMutexLock(pPvt->ringBufferLock); \
- if (pPvt->ringTail != pPvt->ringHead) { \
- if (pPvt->ringBufferOverflows > 0) { \
- asynPrint(pPvt->pasynUser, ASYN_TRACE_WARNING, \
- "%s %s::getRingBufferValue error, %d ring buffer overflows\n", \
- pPvt->pr->name, driverName, pPvt->ringBufferOverflows); \
- pPvt->ringBufferOverflows = 0; \
- } \
- pPvt->result = pPvt->ringBuffer[pPvt->ringTail]; \
- pPvt->ringTail = (pPvt->ringTail==pPvt->ringSize-1) ? 0 : pPvt->ringTail+1; \
- ret = 1; \
- } \
- epicsMutexUnlock(pPvt->ringBufferLock); \
- return ret; \
-} \
- \
-static void interruptCallback(void *drvPvt, asynUser *pasynUser, \
- EPICS_TYPE *value, size_t len) \
-{ \
- devAsynWfPvt *pPvt = (devAsynWfPvt *)drvPvt; \
- waveformRecord *pwf = (waveformRecord *)pPvt->pr; \
- int i; \
- EPICS_TYPE *pData = (EPICS_TYPE *)pwf->bptr; \
- \
- asynPrintIO(pPvt->pasynUser, ASYN_TRACEIO_DEVICE, \
- (char *)value, len*sizeof(EPICS_TYPE), \
- "%s %s::interruptCallbackInput ringSize=%d, len=%d, callback data:", \
- pwf->name, driverName, pPvt->ringSize, (int)len); \
- if (pPvt->ringSize == 0) { \
- /* Not using a ring buffer */ \
- dbScanLock((dbCommon *)pwf); \
- if (len > pwf->nelm) len = pwf->nelm; \
- if (pasynUser->auxStatus == asynSuccess) { \
- for (i=0; i<(int)len; i++) pData[i] = value[i]; \
- pwf->nord = (epicsUInt32)len; \
- } \
- pwf->time = pasynUser->timestamp; \
- pPvt->result.status = pasynUser->auxStatus; \
- pPvt->result.alarmStatus = pasynUser->alarmStatus; \
- pPvt->result.alarmSeverity = pasynUser->alarmSeverity; \
- pPvt->gotValue++; \
- dbScanUnlock((dbCommon *)pwf); \
- if (pPvt->isOutput) \
- scanOnce((dbCommon *)pwf); \
- else \
- scanIoRequest(pPvt->ioScanPvt); \
- } else { \
- /* Using a ring buffer */ \
- ringBufferElement *rp; \
- \
- /* If interruptAccept is false we just return. This prevents more ring pushes than pops. \
- * There will then be nothing in the ring buffer, so the first \
- * read will do a read from the driver, which should be OK. */ \
- if (!interruptAccept) return; \
- \
- epicsMutexLock(pPvt->ringBufferLock); \
- rp = &pPvt->ringBuffer[pPvt->ringHead]; \
- if (len > pwf->nelm) len = pwf->nelm; \
- rp->len = len; \
- for (i=0; i<(int)len; i++) rp->pValue[i] = value[i]; \
- rp->time = pasynUser->timestamp; \
- rp->status = pasynUser->auxStatus; \
- rp->alarmStatus = pasynUser->alarmStatus; \
- rp->alarmSeverity = pasynUser->alarmSeverity; \
- pPvt->ringHead = (pPvt->ringHead==pPvt->ringSize-1) ? 0 : pPvt->ringHead+1; \
- if (pPvt->ringHead == pPvt->ringTail) { \
- /* There was no room in the ring buffer. In the past we just threw away \
- * the new value. However, it is better to remove the oldest value from the \
- * ring buffer and add the new one. That way the final value the record receives \
- * is guaranteed to be the most recent value */ \
- pPvt->ringTail = (pPvt->ringTail==pPvt->ringSize-1) ? 0 : pPvt->ringTail+1; \
- pPvt->ringBufferOverflows++; \
- } else { \
- /* We only need to request the record to process if we added a new \
- * element to the ring buffer, not if we just replaced an element. */ \
- if (pPvt->isOutput) \
- scanOnce((dbCommon *)pwf); \
- else \
- scanIoRequest(pPvt->ioScanPvt); \
- } \
- epicsMutexUnlock(pPvt->ringBufferLock); \
- } \
-} \
-
diff --git a/asyn/devEpics/devEpics.dbd b/asyn/devEpics/devEpics.dbd
deleted file mode 100644
index 179fb3d..0000000
--- a/asyn/devEpics/devEpics.dbd
+++ /dev/null
@@ -1,12 +0,0 @@
-include "devAsynOctet.dbd"
-include "devAsynInt32.dbd"
-include "devAsynInt8Array.dbd"
-include "devAsynInt16Array.dbd"
-include "devAsynInt32Array.dbd"
-include "devAsynInt32TimeSeries.dbd"
-include "devAsynFloat64.dbd"
-include "devAsynFloat32Array.dbd"
-include "devAsynFloat64Array.dbd"
-include "devAsynFloat64TimeSeries.dbd"
-include "devAsynUInt32Digital.dbd"
-include "devAsynRecord.dbd"
diff --git a/asyn/devEpics/devEpicsPvt.c b/asyn/devEpics/devEpicsPvt.c
new file mode 100644
index 0000000..3d33098
--- /dev/null
+++ b/asyn/devEpics/devEpicsPvt.c
@@ -0,0 +1,36 @@
+/***********************************************************************
+* Copyright (c) 2023 Michael Davidsaver
+* asynDriver is distributed subject to a Software License Agreement
+* found in file LICENSE that is included with this distribution.
+***********************************************************************/
+
+#include
+
+#include
+#include
+#include