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 @@ -[![Build Status](https://travis-ci.org/epics-modules/asyn.svg?branch=master)](https://travis-ci.org/epics-modules/asyn) +[![Github Actions](https://github.com/epics-modules/asyn/actions/workflows/ci-scripts.yml/badge.svg)](https://github.com/epics-modules/asyn/actions/workflows/ci-scripts.yml) +[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/epics-modules/asyn?branch=master&svg=true)](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 + +#include +#include "devEpicsPvt.h" + +#if EPICS_VERSION_INT < VERSION_INT(3, 16, 1, 0) +static +void dbInitEntryFromRecord(struct dbCommon *prec, + struct dbEntry *pdbentry) +{ + long status; + dbInitEntry(pdbbase, pdbentry); + status = dbFindRecord(pdbentry, prec->name); + assert(!status); /* we have dbCommon* so the record must exist */ +} +#endif + +const char* asynDbGetInfo(struct dbCommon *prec, const char *infoname) +{ + const char *ret = NULL; + DBENTRY ent; + dbInitEntryFromRecord(prec, &ent); + ret = dbGetInfo(&ent, infoname); + dbFinishEntry(&ent); + return ret; +} diff --git a/asyn/devEpics/devEpicsPvt.h b/asyn/devEpics/devEpicsPvt.h new file mode 100644 index 0000000..997e210 --- /dev/null +++ b/asyn/devEpics/devEpicsPvt.h @@ -0,0 +1,22 @@ +/*********************************************************************** +* Copyright (c) 2023 Michael Davidsaver +* asynDriver is distributed subject to a Software License Agreement +* found in file LICENSE that is included with this distribution. +***********************************************************************/ + +#ifndef DEVEPICSPVT_H +#define DEVEPICSPVT_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct dbCommon; + +const char* asynDbGetInfo(struct dbCommon *prec, const char *infoname); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // DEVEPICSPVT_H diff --git a/asyn/devGpib/boSRQonOff.c b/asyn/devGpib/boSRQonOff.c index 373ff78..6f738c6 100644 --- a/asyn/devGpib/boSRQonOff.c +++ b/asyn/devGpib/boSRQonOff.c @@ -2,9 +2,9 @@ int boSRQonOff(struct gpibDpvt *pdpvt, int p1, int p2,char **p3) -{ +{ boRecord *pbo = (boRecord *)pdpvt->precord; - asynGpib *pasynGpib = pdpvt->pasynGpib; + asynGpib *pasynGpib = pdpvt->pasynGpib; pasynGpib->pollAddr(pdpvt->asynGpibPvt,pdpvt->pasynUser,pbo->rval); /* initiate a polling round :*/ diff --git a/asyn/devGpib/devCommonGpib.c b/asyn/devGpib/devCommonGpib.c index dc82cc6..d2bb976 100644 --- a/asyn/devGpib/devCommonGpib.c +++ b/asyn/devGpib/devCommonGpib.c @@ -33,8 +33,6 @@ #include #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynGpibDriver.h" #include "devSupportGpib.h" @@ -46,7 +44,7 @@ static void genericFinish(gpibDpvt * pgpibDpvt,int failure) { pdevSupportGpib->completeProcess(pgpibDpvt); } - + static void aiFinish(gpibDpvt *pgpibDpvt,int failure); long devGpib_initAi(aiRecord * pai) { @@ -75,7 +73,7 @@ long devGpib_readAi(aiRecord * pai) gpibDpvt *pgpibDpvt = gpibDpvtGet(pai); int cmdType; DEVSUPFUN got_special_linconv = ((gDset *) pai->dset)->funPtr[5]; - + if(pai->pact) return (got_special_linconv ? 0 : 2); cmdType = gpibCmdGetType(pgpibDpvt); if(cmdType&GPIBSOFT) { @@ -125,7 +123,7 @@ static void aiFinish(gpibDpvt * pgpibDpvt,int failure) if(failure==-1) recGblSetSevr(pai, READ_ALARM, INVALID_ALARM); pdevSupportGpib->completeProcess(pgpibDpvt); } - + static int aoStart(gpibDpvt *pgpibDpvt,int failure); long devGpib_initAo(aoRecord * pao) { @@ -155,7 +153,7 @@ long devGpib_writeAo(aoRecord * pao) { gpibDpvt *pgpibDpvt = gpibDpvtGet(pao); int cmdType = gpibCmdGetType(pgpibDpvt); - + if(pao->pact) return 0; if(cmdType&GPIBSOFT) { pdevSupportGpib->processGPIBSOFT(pgpibDpvt); @@ -182,7 +180,7 @@ static int aoStart(gpibDpvt *pgpibDpvt,int failure) } return failure; } - + static void biFinish(gpibDpvt *pgpibDpvt,int failure); long devGpib_initBi(biRecord * pbi) { @@ -206,10 +204,14 @@ long devGpib_initBi(biRecord * pbi) } pdevGpibNames = devGpibNamesGet(pgpibDpvt); if(pdevGpibNames) { - if (pbi->znam[0] == 0) + if (pbi->znam[0] == 0) { strncpy(pbi->znam, pdevGpibNames->item[0], sizeof(pbi->znam)); - if (pbi->onam[0] == 0) + pbi->znam[sizeof(pbi->znam)-1] = '\0'; + } + if (pbi->onam[0] == 0) { strncpy(pbi->onam, pdevGpibNames->item[1], sizeof(pbi->onam)); + pbi->onam[sizeof(pbi->onam)-1] = '\0'; + } } return 0; } @@ -218,7 +220,7 @@ long devGpib_readBi(biRecord * pbi) { gpibDpvt *pgpibDpvt = gpibDpvtGet(pbi); int cmdType; - + if(pbi->pact) return 0; cmdType = gpibCmdGetType(pgpibDpvt); if(cmdType&GPIBSOFT) { @@ -228,7 +230,7 @@ long devGpib_readBi(biRecord * pbi) } return 0; } - + static void biFinish(gpibDpvt * pgpibDpvt,int failure) { biRecord *pbi = ((biRecord *) (pgpibDpvt->precord)); @@ -271,7 +273,7 @@ static void biFinish(gpibDpvt * pgpibDpvt,int failure) if(failure==-1) recGblSetSevr(pbi, READ_ALARM, INVALID_ALARM); pdevSupportGpib->completeProcess(pgpibDpvt); } - + static int boStart(gpibDpvt *pgpibDpvt,int failure); static void writeBoSpecial(boRecord * pbo); static void boWorkSpecial(gpibDpvt *pgpibDpvt,int failure); @@ -310,10 +312,14 @@ long devGpib_initBo(boRecord * pbo) "%s devGpib_initBo logic error\n",pbo->name); } if (papname) { - if (pbo->znam[0] == 0) + if (pbo->znam[0] == 0) { strncpy(pbo->znam, papname[0], sizeof(pbo->znam)); - if (pbo->onam[0] == 0) + pbo->znam[sizeof(pbo->znam)-1] = '\0'; + } + if (pbo->onam[0] == 0) { strncpy(pbo->onam, papname[1], sizeof(pbo->onam)); + pbo->onam[sizeof(pbo->onam)-1] = '\0'; + } } } else if(!(cmdType&(GPIBWRITE|GPIBCMD|GPIBACMD|GPIBEFASTO|GPIBSOFT|GPIBCVTIO))) { asynPrint(pgpibDpvt->pasynUser,ASYN_TRACE_ERROR, @@ -324,19 +330,23 @@ long devGpib_initBo(boRecord * pbo) } pdevGpibNames = devGpibNamesGet(pgpibDpvt); if(pdevGpibNames) { - if (pbo->znam[0] == 0) + if (pbo->znam[0] == 0) { strncpy(pbo->znam, pdevGpibNames->item[0], sizeof(pbo->znam)); - if (pbo->onam[0] == 0) + pbo->znam[sizeof(pbo->znam)-1] = '\0'; + } + if (pbo->onam[0] == 0) { strncpy(pbo->onam, pdevGpibNames->item[1], sizeof(pbo->onam)); + pbo->onam[sizeof(pbo->onam)-1] = '\0'; + } } return 2; } - + long devGpib_writeBo(boRecord * pbo) { gpibDpvt *pgpibDpvt = gpibDpvtGet(pbo); int cmdType = gpibCmdGetType(pgpibDpvt); - + if(pbo->pact) return 0; if(cmdType&GPIBSOFT) { pdevSupportGpib->processGPIBSOFT(pgpibDpvt); @@ -363,12 +373,12 @@ static int boStart(gpibDpvt * pgpibDpvt,int failure) } return failure; } - + static void writeBoSpecial(boRecord * pbo) { gpibDpvt *pgpibDpvt = gpibDpvtGet(pbo); int cmdType = gpibCmdGetType(pgpibDpvt); - + if(pbo->pact) return; if(cmdType&(GPIBIFC|GPIBDCL|GPIBLLO|GPIBSDC|GPIBGTL)) { if(pbo->val==0) return; @@ -413,7 +423,7 @@ static void boWorkSpecial(gpibDpvt *pgpibDpvt,int failure) if(failure==-1) recGblSetSevr(precord, WRITE_ALARM, INVALID_ALARM); pdevSupportGpib->completeProcess(pgpibDpvt); } - + static void evFinish(gpibDpvt *pgpibDpvt,int failure); long devGpib_initEv(eventRecord * pev) { @@ -441,7 +451,7 @@ long devGpib_readEv(eventRecord * pev) { gpibDpvt *pgpibDpvt = gpibDpvtGet(pev); int cmdType; - + if(pev->pact) return 0; cmdType = gpibCmdGetType(pgpibDpvt); if(cmdType&GPIBSOFT) { @@ -495,7 +505,7 @@ static void evFinish(gpibDpvt * pgpibDpvt,int failure) if(failure==-1) recGblSetSevr(pev, READ_ALARM, INVALID_ALARM); pdevSupportGpib->completeProcess(pgpibDpvt); } - + static void liFinish(gpibDpvt *pgpibDpvt,int failure); static void liSrqHandler(void *userPrivate,asynUser *pasynUser, epicsInt32 statusByte) @@ -536,7 +546,7 @@ long devGpib_readLi(longinRecord * pli) { gpibDpvt *pgpibDpvt = gpibDpvtGet(pli); int cmdType; - + /*printf("READ -- %s %d %p\n", pli->name, pli->val, &pli->val);*/ if(pli->pact) return 0; cmdType = gpibCmdGetType(pgpibDpvt); @@ -584,7 +594,7 @@ static void liFinish(gpibDpvt * pgpibDpvt,int failure) if(failure==-1) recGblSetSevr(pli, READ_ALARM, INVALID_ALARM); pdevSupportGpib->completeProcess(pgpibDpvt); } - + static int loStart(gpibDpvt *pgpibDpvt,int failure); long devGpib_initLo(longoutRecord * plo) { @@ -612,7 +622,7 @@ long devGpib_writeLo(longoutRecord * plo) { gpibDpvt *pgpibDpvt = gpibDpvtGet(plo); int cmdType = gpibCmdGetType(pgpibDpvt); - + if(plo->pact) return 0; if(cmdType&GPIBSOFT) { pdevSupportGpib->processGPIBSOFT(pgpibDpvt); @@ -634,7 +644,7 @@ static int loStart(gpibDpvt * pgpibDpvt,int failure) } return failure; } - + static void mbbiFinish(gpibDpvt *pgpibDpvt,int failure); long devGpib_initMbbi(mbbiRecord * pmbbi) { @@ -689,7 +699,7 @@ long devGpib_readMbbi(mbbiRecord * pmbbi) { gpibDpvt *pgpibDpvt = gpibDpvtGet(pmbbi); int cmdType; - + if(pmbbi->pact) return 0; cmdType = gpibCmdGetType(pgpibDpvt); if(cmdType&GPIBSOFT) { @@ -699,7 +709,7 @@ long devGpib_readMbbi(mbbiRecord * pmbbi) } return 0; } - + static void mbbiFinish(gpibDpvt * pgpibDpvt,int failure) { mbbiRecord *pmbbi = ((mbbiRecord *) (pgpibDpvt->precord)); @@ -742,7 +752,7 @@ static void mbbiFinish(gpibDpvt * pgpibDpvt,int failure) if(failure==-1) recGblSetSevr(pmbbi, READ_ALARM, INVALID_ALARM); pdevSupportGpib->completeProcess(pgpibDpvt); } - + static void mbbiDirectFinish(gpibDpvt *pgpibDpvt,int failure); long devGpib_initMbbiDirect(mbbiDirectRecord * pmbbiDirect) { @@ -770,7 +780,7 @@ long devGpib_readMbbiDirect(mbbiDirectRecord * pmbbiDirect) { gpibDpvt *pgpibDpvt = gpibDpvtGet(pmbbiDirect); int cmdType; - + if(pmbbiDirect->pact) return 0; cmdType = gpibCmdGetType(pgpibDpvt); if(cmdType&GPIBSOFT) { @@ -816,7 +826,7 @@ static void mbbiDirectFinish(gpibDpvt * pgpibDpvt,int failure) if(failure==-1) recGblSetSevr(pmbbiDirect, READ_ALARM, INVALID_ALARM); pdevSupportGpib->completeProcess(pgpibDpvt); } - + static int mbboStart(gpibDpvt *pgpibDpvt,int failure); long devGpib_initMbbo(mbboRecord * pmbbo) { @@ -866,12 +876,12 @@ long devGpib_initMbbo(mbboRecord * pmbbo) } return 2; } - + long devGpib_writeMbbo(mbboRecord * pmbbo) { gpibDpvt *pgpibDpvt = gpibDpvtGet(pmbbo); int cmdType = gpibCmdGetType(pgpibDpvt); - + if(pmbbo->pact) return 0; if(cmdType&GPIBSOFT) { pdevSupportGpib->processGPIBSOFT(pgpibDpvt); @@ -895,7 +905,7 @@ static int mbboStart(gpibDpvt * pgpibDpvt,int failure) } return failure; } - + static int mbboDirectStart(gpibDpvt *pgpibDpvt,int failure); long devGpib_initMbboDirect(mbboDirectRecord * pmbboDirect) { @@ -923,7 +933,7 @@ long devGpib_writeMbboDirect(mbboDirectRecord * pmbboDirect) { gpibDpvt *pgpibDpvt = gpibDpvtGet(pmbboDirect); int cmdType = gpibCmdGetType(pgpibDpvt); - + if(pmbboDirect->pact) return 0; if(cmdType&GPIBSOFT) { pdevSupportGpib->processGPIBSOFT(pgpibDpvt); @@ -946,7 +956,7 @@ static int mbboDirectStart(gpibDpvt * pgpibDpvt,int failure) } return failure; } - + static void siFinish(gpibDpvt *pgpibDpvt,int failure); long devGpib_initSi(stringinRecord * psi) { @@ -974,7 +984,7 @@ long devGpib_readSi(stringinRecord * psi) { gpibDpvt *pgpibDpvt = gpibDpvtGet(psi); int cmdType; - + if(psi->pact) return 0; cmdType = gpibCmdGetType(pgpibDpvt); if(cmdType&GPIBSOFT) { @@ -1018,7 +1028,7 @@ static void siFinish(gpibDpvt * pgpibDpvt,int failure) if(failure==-1) recGblSetSevr(psi, READ_ALARM, INVALID_ALARM); pdevSupportGpib->completeProcess(pgpibDpvt); } - + static int soStart(gpibDpvt *pgpibDpvt,int failure); long devGpib_initSo(stringoutRecord * pso) { @@ -1046,7 +1056,7 @@ long devGpib_writeSo(stringoutRecord * pso) { gpibDpvt *pgpibDpvt = gpibDpvtGet(pso); int cmdType = gpibCmdGetType(pgpibDpvt); - + if(pso->pact) return 0; if(cmdType&GPIBSOFT) { pdevSupportGpib->processGPIBSOFT(pgpibDpvt); @@ -1068,7 +1078,7 @@ static int soStart(gpibDpvt *pgpibDpvt,int failure) } return failure; } - + static int wfStart(gpibDpvt *pgpibDpvt,int failure); static void wfFinish(gpibDpvt *pgpibDpvt,int failure); long devGpib_initWf(waveformRecord * pwf) @@ -1106,7 +1116,7 @@ long devGpib_readWf(waveformRecord * pwf) { gpibDpvt *pgpibDpvt = gpibDpvtGet(pwf); int cmdType = gpibCmdGetType(pgpibDpvt); - + if(pwf->pact) return 0; if(cmdType&GPIBSOFT) { pdevSupportGpib->processGPIBSOFT(pgpibDpvt); @@ -1119,7 +1129,7 @@ long devGpib_readWf(waveformRecord * pwf) } return 0; } - + static int wfStart(gpibDpvt * pgpibDpvt,int failure) { waveformRecord *pwf = (waveformRecord *)pgpibDpvt->precord; @@ -1159,7 +1169,7 @@ static void wfFinish(gpibDpvt * pgpibDpvt,int failure) } else if(pwf->ftvl!=menuFtypeCHAR) { asynPrint(pgpibDpvt->pasynUser,ASYN_TRACE_ERROR, "%s ftvl != CHAR but no convert\n",pwf->name); - failure = -1; + failure = -1; } else { char *format = (pgpibCmd->format) ? pgpibCmd->format : "%s"; int lenDest = pwf->nelm; diff --git a/asyn/devGpib/devCommonGpib.h b/asyn/devGpib/devCommonGpib.h index 83d23bc..5260afe 100644 --- a/asyn/devGpib/devCommonGpib.h +++ b/asyn/devGpib/devCommonGpib.h @@ -18,40 +18,39 @@ #define INCdevCommonGpibh #include -#include "shareLib.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -epicsShareFunc long devGpib_initAi(struct aiRecord * pai); -epicsShareFunc long devGpib_readAi(struct aiRecord * pai); -epicsShareFunc long devGpib_initAo(struct aoRecord * pao); -epicsShareFunc long devGpib_writeAo(struct aoRecord * pao); -epicsShareFunc long devGpib_initBi(struct biRecord * pbi); -epicsShareFunc long devGpib_readBi(struct biRecord * pbi); -epicsShareFunc long devGpib_initBo(struct boRecord * pbo); -epicsShareFunc long devGpib_writeBo(struct boRecord * pbo); -epicsShareFunc long devGpib_initEv(struct eventRecord * pev); -epicsShareFunc long devGpib_readEv(struct eventRecord * pev); -epicsShareFunc long devGpib_initLi(struct longinRecord * pli); -epicsShareFunc long devGpib_readLi(struct longinRecord * pli); -epicsShareFunc long devGpib_initLo(struct longoutRecord * plo); -epicsShareFunc long devGpib_writeLo(struct longoutRecord * plo); -epicsShareFunc long devGpib_initMbbi(struct mbbiRecord * pmbbi); -epicsShareFunc long devGpib_readMbbi(struct mbbiRecord * pmbbi); -epicsShareFunc long devGpib_initMbbiDirect(struct mbbiDirectRecord * pmbbiDirect); -epicsShareFunc long devGpib_readMbbiDirect(struct mbbiDirectRecord * pmbbiDirect); -epicsShareFunc long devGpib_initMbbo(struct mbboRecord * pmbbo); -epicsShareFunc long devGpib_writeMbbo(struct mbboRecord * pmbbo); -epicsShareFunc long devGpib_initMbboDirect(struct mbboDirectRecord * pmbboDirect); -epicsShareFunc long devGpib_writeMbboDirect(struct mbboDirectRecord * pmbboDirect); -epicsShareFunc long devGpib_initSi(struct stringinRecord * psi); -epicsShareFunc long devGpib_readSi(struct stringinRecord * psi); -epicsShareFunc long devGpib_initSo(struct stringoutRecord * pso); -epicsShareFunc long devGpib_writeSo(struct stringoutRecord * pso); -epicsShareFunc long devGpib_initWf(struct waveformRecord * pwf); -epicsShareFunc long devGpib_readWf(struct waveformRecord * pwf); +ASYN_API long devGpib_initAi(struct aiRecord * pai); +ASYN_API long devGpib_readAi(struct aiRecord * pai); +ASYN_API long devGpib_initAo(struct aoRecord * pao); +ASYN_API long devGpib_writeAo(struct aoRecord * pao); +ASYN_API long devGpib_initBi(struct biRecord * pbi); +ASYN_API long devGpib_readBi(struct biRecord * pbi); +ASYN_API long devGpib_initBo(struct boRecord * pbo); +ASYN_API long devGpib_writeBo(struct boRecord * pbo); +ASYN_API long devGpib_initEv(struct eventRecord * pev); +ASYN_API long devGpib_readEv(struct eventRecord * pev); +ASYN_API long devGpib_initLi(struct longinRecord * pli); +ASYN_API long devGpib_readLi(struct longinRecord * pli); +ASYN_API long devGpib_initLo(struct longoutRecord * plo); +ASYN_API long devGpib_writeLo(struct longoutRecord * plo); +ASYN_API long devGpib_initMbbi(struct mbbiRecord * pmbbi); +ASYN_API long devGpib_readMbbi(struct mbbiRecord * pmbbi); +ASYN_API long devGpib_initMbbiDirect(struct mbbiDirectRecord * pmbbiDirect); +ASYN_API long devGpib_readMbbiDirect(struct mbbiDirectRecord * pmbbiDirect); +ASYN_API long devGpib_initMbbo(struct mbboRecord * pmbbo); +ASYN_API long devGpib_writeMbbo(struct mbboRecord * pmbbo); +ASYN_API long devGpib_initMbboDirect(struct mbboDirectRecord * pmbboDirect); +ASYN_API long devGpib_writeMbboDirect(struct mbboDirectRecord * pmbboDirect); +ASYN_API long devGpib_initSi(struct stringinRecord * psi); +ASYN_API long devGpib_readSi(struct stringinRecord * psi); +ASYN_API long devGpib_initSo(struct stringoutRecord * pso); +ASYN_API long devGpib_writeSo(struct stringoutRecord * pso); +ASYN_API long devGpib_initWf(struct waveformRecord * pwf); +ASYN_API long devGpib_readWf(struct waveformRecord * pwf); /* * SRQ support diff --git a/asyn/devGpib/devGpib.h b/asyn/devGpib/devGpib.h index 3fd0db0..49ca8b7 100644 --- a/asyn/devGpib/devGpib.h +++ b/asyn/devGpib/devGpib.h @@ -43,7 +43,7 @@ #include /* forward declaration: */ static devGpibParmBlock devSupParms; - + /* init_ai MUST be implemented by device specific support*/ static long init_ai(int pass); static gDset DSET_AI = { @@ -108,7 +108,7 @@ static gDset DSET_EV = { }; epicsExportAddress(dset,DSET_EV); #endif - + #ifdef DSET_LI static gDset DSET_LI = { 6, @@ -162,7 +162,7 @@ static gDset DSET_MBBOD = { }; epicsExportAddress(dset,DSET_MBBOD); #endif - + #ifdef DSET_SI static gDset DSET_SI = { 6, diff --git a/asyn/devGpib/devGpibConvertExample.c b/asyn/devGpib/devGpibConvertExample.c index a685f4d..cd4d51e 100644 --- a/asyn/devGpib/devGpibConvertExample.c +++ b/asyn/devGpib/devGpibConvertExample.c @@ -50,7 +50,7 @@ #include #include #include - + #define TIMEOUT 1.0 #define TIMEWINDOW 2.0 @@ -64,7 +64,7 @@ static int writeCvtio(gpibDpvt *pgpibDpvt,int P1, int P2, char **P3); * easier changes when testing the driver. */ -static struct gpibCmd gpibCmds[] = +static struct gpibCmd gpibCmds[] = { /* Param 0 */ {&DSET_SI,GPIBREAD,IB_Q_LOW,"*IDN?", 0,0,200,0,0,0,0,0,0}, @@ -83,7 +83,7 @@ static struct gpibCmd gpibCmds[] = /* The following is the number of elements in the command array above. */ #define NUMPARAMS sizeof(gpibCmds)/sizeof(struct gpibCmd) - + /****************************************************************************** * * Initialization for device support @@ -179,13 +179,13 @@ static int writeString(gpibDpvt *pgpibDpvt,int P1, int P2, char **P3) return -1; } nchars = epicsSnprintf(pgpibDpvt->msg,pgpibCmd->msgLen,format,precord->val); - if(nchars>pgpibCmd->msgLen) { - asynPrint(pasynUser,ASYN_TRACE_ERROR, - "%s msg buffer too small. msgLen %d message length %d\n", - precord->name,pgpibCmd->msgLen,nchars); - recGblSetSevr(precord,WRITE_ALARM, INVALID_ALARM); - return -1; - } + if(nchars>pgpibCmd->msgLen) { + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s msg buffer too small. msgLen %d message length %d\n", + precord->name,pgpibCmd->msgLen,nchars); + recGblSetSevr(precord,WRITE_ALARM, INVALID_ALARM); + return -1; + } asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s writeMsgString\n",precord->name); return nchars; } diff --git a/asyn/devGpib/devSkeletonGpib.c b/asyn/devGpib/devSkeletonGpib.c index e6a2f8d..eb59b67 100644 --- a/asyn/devGpib/devSkeletonGpib.c +++ b/asyn/devGpib/devSkeletonGpib.c @@ -23,7 +23,7 @@ /****************************************************************************** * * The following define statements are used to declare the names to be used - * for the dset tables. + * for the dset tables. * * A DSET_AI entry must be declared here and referenced in an application * database description file even if the device provides no AI records. @@ -43,7 +43,7 @@ #include /* must be included after DSET defines */ - + #define TIMEOUT 1.0 #define TIMEWINDOW 2.0 @@ -107,7 +107,7 @@ static struct devGpibNames intExtSsBmStop = { ******************************************************************************/ static char *userOffOn[] = {"USER OFF;","USER ON;",0}; - + /****************************************************************************** * Array of structures that define all GPIB messages * supported for this type of instrument. diff --git a/asyn/devGpib/devSupportGpib.c b/asyn/devGpib/devSupportGpib.c index d774e07..f705903 100644 --- a/asyn/devGpib/devSupportGpib.c +++ b/asyn/devGpib/devSupportGpib.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -46,7 +45,7 @@ #define DEFAULT_QUEUE_TIMEOUT 60.0 #define DEFAULT_SRQ_WAIT_TIMEOUT 5.0 - + typedef struct commonGpibPvt { ELLLIST portInstanceList; epicsTimerQueueId timerQueue; @@ -69,7 +68,7 @@ typedef struct srqPvt { typedef struct deviceInstance { ELLNODE node; /*For portInstance.deviceInstanceList*/ - portInstance *pportInstance; + portInstance *pportInstance; int gpibAddr; unsigned long errorCount; /* total number of errors since boot time */ double queueTimeout; @@ -85,7 +84,7 @@ typedef struct deviceInstance { struct portInstance { ELLNODE node; /*For commonGpibPvt.portInstanceList*/ ELLLIST deviceInstanceList; - epicsMutexId lock; + epicsMutexId lock; int link; char *portName; asynCommon *pasynCommon; @@ -112,7 +111,7 @@ struct devGpibPvt { gpibStart start; gpibFinish finish; }; - + static long initRecord(dbCommon* precord, struct link * plink); static void processGPIBSOFT(gpibDpvt *pgpibDpvt); static void queueReadRequest(gpibDpvt *pgpibDpvt,gpibStart start,gpibFinish finish); @@ -145,7 +144,7 @@ static devSupportGpib gpibSupport = { restoreEos, completeProcess }; -epicsShareDef devSupportGpib *pdevSupportGpib = &gpibSupport; +devSupportGpib *pdevSupportGpib = &gpibSupport; /*Initialization routines*/ static void commonGpibPvtInit(void); @@ -186,7 +185,7 @@ static void devGpibSrqWaitTimeoutSet( const char *portName, int gpibAddr, double timeout); static long init(int pass); static long report(int interest); - + static long initRecord(dbCommon *precord, struct link *plink) { gDset *pgDset = (gDset *)precord->dset; @@ -256,7 +255,7 @@ static long initRecord(dbCommon *precord, struct link *plink) } return 0; } - + static void processGPIBSOFT(gpibDpvt *pgpibDpvt) { gpibCmd *pgpibCmd = gpibCmdGet(pgpibDpvt); @@ -280,7 +279,7 @@ static void processGPIBSOFT(gpibDpvt *pgpibDpvt) } return; } - + static void queueReadRequest(gpibDpvt *pgpibDpvt,gpibStart start,gpibFinish finish) { devGpibPvt *pdevGpibPvt = pgpibDpvt->pdevGpibPvt; @@ -320,7 +319,7 @@ static int queueRequest(gpibDpvt *pgpibDpvt, gpibWork work) pdevGpibPvt->finish = 0; return queueIt(pgpibDpvt); } - + static void registerSrqHandler(gpibDpvt *pgpibDpvt, interruptCallbackInt32 handler,void *unsollicitedHandlerPvt) { @@ -332,7 +331,7 @@ static void registerSrqHandler(gpibDpvt *pgpibDpvt, srqPvt *psrqPvt = &pdeviceInstance->srq; portInstance *pportInstance = pdevGpibPvt->pportInstance; int failure=0; - + epicsMutexMustLock(pportInstance->lock); if(!pasynGpib) { asynPrint(pasynUser,ASYN_TRACE_ERROR, @@ -359,7 +358,7 @@ static void registerSrqHandler(gpibDpvt *pgpibDpvt, } epicsMutexUnlock(pportInstance->lock); } - + #define writeMsgProlog \ asynUser *pasynUser = pgpibDpvt->pasynUser; \ int nchars; \ @@ -417,24 +416,24 @@ static int writeMsgDouble(gpibDpvt *pgpibDpvt,double val) static int writeMsgString(gpibDpvt *pgpibDpvt,const char *str) { - asynUser *pasynUser = pgpibDpvt->pasynUser; - int nchars; - dbCommon *precord = (dbCommon *)pgpibDpvt->precord; + asynUser *pasynUser = pgpibDpvt->pasynUser; + int nchars; + dbCommon *precord = (dbCommon *)pgpibDpvt->precord; gpibCmd *pgpibCmd = gpibCmdGet(pgpibDpvt); char *format = (pgpibCmd->format) ? pgpibCmd->format : "%s"; if(!pgpibDpvt->msg) { asynPrint(pasynUser,ASYN_TRACE_ERROR, - "%s no msg buffer. Must define gpibCmd.msgLen > 0.\n", + "%s no msg buffer. Must define gpibCmd.msgLen > 0.\n", precord->name); - recGblSetSevr(precord,WRITE_ALARM, INVALID_ALARM); - return -1; + recGblSetSevr(precord,WRITE_ALARM, INVALID_ALARM); + return -1; } nchars = epicsSnprintf(pgpibDpvt->msg,pgpibCmd->msgLen,format,str); asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s writeMsgString\n",precord->name); writeMsgPostLog } - + /* * Read IEEE-488.2 Arbitrary Block Program Data. * Allows arbitrary data to be read from serial line. @@ -584,11 +583,11 @@ static int readArbitraryBlockProgramData(gpibDpvt *pgpibDpvt) "%s readArbitraryBlockProgramData\n",pgpibDpvt->precord->name); return pgpibDpvt->msgInputLen; } - + static int setEos(gpibDpvt *pgpibDpvt, gpibCmd *pgpibCmd) { deviceInstance *pdeviceInstance = pgpibDpvt->pdevGpibPvt->pdeviceInstance; - asynUser *pasynUser = pgpibDpvt->pasynUser; + asynUser *pasynUser = pgpibDpvt->pasynUser; dbCommon *precord = pgpibDpvt->precord; asynOctet *pasynOctet = pgpibDpvt->pasynOctet; void *drvPvt = pgpibDpvt->asynOctetPvt; @@ -620,7 +619,7 @@ static int setEos(gpibDpvt *pgpibDpvt, gpibCmd *pgpibCmd) static int restoreEos(gpibDpvt *pgpibDpvt, gpibCmd *pgpibCmd) { deviceInstance *pdeviceInstance = pgpibDpvt->pdevGpibPvt->pdeviceInstance; - asynUser *pasynUser = pgpibDpvt->pasynUser; + asynUser *pasynUser = pgpibDpvt->pasynUser; dbCommon *precord = pgpibDpvt->precord; asynOctet *pasynOctet = pgpibDpvt->pasynOctet; void *drvPvt = pgpibDpvt->asynOctetPvt; @@ -658,8 +657,8 @@ static void completeProcess(gpibDpvt *pgpibDpvt) precord->pact = FALSE; } } - -static void commonGpibPvtInit(void) + +static void commonGpibPvtInit(void) { if(pcommonGpibPvt) return; pcommonGpibPvt = (commonGpibPvt *)callocMustSucceed(1,sizeof(commonGpibPvt), @@ -710,7 +709,7 @@ static void setMsgRsp(gpibDpvt *pgpibDpvt) if(pportInstance->rspLenMaxrspLenMax = rspLenMax; if(pportInstance->msgLenMaxmsgLenMax = msgLenMax; } - + static portInstance *createPortInstance( int link,asynUser *pasynUser,const char *portName) { @@ -737,26 +736,26 @@ static portInstance *createPortInstance( pportInstance->asynCommonPvt = pasynInterface->drvPvt; pasynInterface = pasynManager->findInterface(pasynUser,asynOctetType,1); if(pasynInterface) { - pportInstance->pasynOctet = + pportInstance->pasynOctet = (asynOctet *)pasynInterface->pinterface; pportInstance->asynOctetPvt = pasynInterface->drvPvt; } pasynInterface = pasynManager->findInterface(pasynUser,asynInt32Type,1); if(pasynInterface) { - pportInstance->pasynInt32 = + pportInstance->pasynInt32 = (asynInt32 *)pasynInterface->pinterface; pportInstance->asynInt32Pvt = pasynInterface->drvPvt; } pasynInterface = pasynManager->findInterface(pasynUser,asynGpibType,1); if(pasynInterface) { - pportInstance->pasynGpib = + pportInstance->pasynGpib = (asynGpib *)pasynInterface->pinterface; pportInstance->asynGpibPvt = pasynInterface->drvPvt; } ellAdd(&pcommonGpibPvt->portInstanceList,&pportInstance->node); return pportInstance; } - + static int getDeviceInstance(gpibDpvt *pgpibDpvt,int link,int gpibAddr) { devGpibPvt *pdevGpibPvt = pgpibDpvt->pdevGpibPvt; @@ -765,7 +764,7 @@ static int getDeviceInstance(gpibDpvt *pgpibDpvt,int link,int gpibAddr) portInstance *pportInstance; deviceInstance *pdeviceInstance; asynStatus status; - + if(!pcommonGpibPvt) commonGpibPvtInit(); sprintf(portName,"L%d",link); status = pasynManager->connectDevice(pasynUser,portName,gpibAddr); @@ -818,10 +817,10 @@ static int getDeviceInstance(gpibDpvt *pgpibDpvt,int link,int gpibAddr) pdevGpibPvt->pdeviceInstance = pdeviceInstance; return 0; } - + static int queueIt(gpibDpvt *pgpibDpvt) { - asynUser *pasynUser = pgpibDpvt->pasynUser; + asynUser *pasynUser = pgpibDpvt->pasynUser; dbCommon *precord = pgpibDpvt->precord; devGpibParmBlock *pdevGpibParmBlock = pgpibDpvt->pdevGpibParmBlock; gpibCmd *pgpibCmd = &pdevGpibParmBlock->gpibCmds[pgpibDpvt->parm]; @@ -857,10 +856,10 @@ static int queueIt(gpibDpvt *pgpibDpvt) epicsMutexUnlock(pportInstance->lock); return 1; } - + static void prepareToRead(gpibDpvt *pgpibDpvt,int failure) { - asynUser *pasynUser = pgpibDpvt->pasynUser; + asynUser *pasynUser = pgpibDpvt->pasynUser; dbCommon *precord = pgpibDpvt->precord; gpibCmd *pgpibCmd = gpibCmdGet(pgpibDpvt); int cmdType = pgpibCmd->type; @@ -924,7 +923,7 @@ static void prepareToRead(gpibDpvt *pgpibDpvt,int failure) if(failure) recGblSetSevr(precord,READ_ALARM, INVALID_ALARM); gpibRead(pgpibDpvt,failure); } - + static void readAfterWait(gpibDpvt *pgpibDpvt,int failure) { asynUser *pasynUser = pgpibDpvt->pasynUser; @@ -954,10 +953,10 @@ static void readAfterWait(gpibDpvt *pgpibDpvt,int failure) } gpibRead(pgpibDpvt,failure); } - + static void gpibRead(gpibDpvt *pgpibDpvt,int failure) { - asynUser *pasynUser = pgpibDpvt->pasynUser; + asynUser *pasynUser = pgpibDpvt->pasynUser; dbCommon *precord = pgpibDpvt->precord; gpibCmd *pgpibCmd = gpibCmdGet(pgpibDpvt); int cmdType = pgpibCmd->type; @@ -991,13 +990,13 @@ static void gpibRead(gpibDpvt *pgpibDpvt,int failure) } pgpibDpvt->msgInputLen = (int)nchars; if((int)ncharsmsgLen) pgpibDpvt->msg[nchars] = 0; - if(cmdType&(GPIBEFASTI|GPIBEFASTIW)) + if(cmdType&(GPIBEFASTI|GPIBEFASTIW)) pgpibDpvt->efastVal = checkEnums(pgpibDpvt->msg, pgpibCmd->P3); done: restoreEos(pgpibDpvt,pgpibCmd); if(pdevGpibPvt->finish) pdevGpibPvt->finish(pgpibDpvt,failure); } - + static void gpibWrite(gpibDpvt *pgpibDpvt,int failure) { dbCommon *precord = pgpibDpvt->precord; @@ -1115,7 +1114,7 @@ static void gpibWrite(gpibDpvt *pgpibDpvt,int failure) if(failure) recGblSetSevr(precord,WRITE_ALARM, INVALID_ALARM); if(pdevGpibPvt->finish) pdevGpibPvt->finish(pgpibDpvt,failure); } - + static void queueCallback(asynUser *pasynUser) { gpibDpvt *pgpibDpvt = (gpibDpvt *)pasynUser->userPvt; @@ -1166,7 +1165,7 @@ static void queueCallback(asynUser *pasynUser) epicsMutexUnlock(pportInstance->lock); work(pgpibDpvt,failure); } - + static void queueTimeoutCallback(asynUser *pasynUser) { gpibDpvt *pgpibDpvt = (gpibDpvt *)pasynUser->userPvt; @@ -1192,7 +1191,7 @@ static void queueTimeoutCallback(asynUser *pasynUser) epicsMutexUnlock(pportInstance->lock); work(pgpibDpvt,-1); } - + static void srqPvtInit(asynUser *pasynUser, deviceInstance *pdeviceInstance) { srqPvt *psrqPvt = &pdeviceInstance->srq; @@ -1233,7 +1232,7 @@ static asynStatus srqReadWait(gpibDpvt *pgpibDpvt) epicsMutexUnlock(pportInstance->lock); return status; } - + static void srqHandlerGpib(void *parm, asynUser *pasynUser, epicsInt32 statusByte) { deviceInstance *pdeviceInstance = (deviceInstance *)parm; @@ -1248,7 +1247,7 @@ static void srqHandlerGpib(void *parm, asynUser *pasynUser, epicsInt32 statusByt epicsTimerCancel(psrqPvt->waitTimer); queueIt(psrqPvt->pgpibDpvt); return; - case srqWaitDone: + case srqWaitDone: epicsMutexUnlock(pportInstance->lock); printf( "portName %s link %d gpibAddr %d " "Extra SRQ before readAfterWait\n", @@ -1297,12 +1296,12 @@ static void waitTimeoutCallback(void *parm) epicsMutexUnlock(pportInstance->lock); queueIt(psrqPvt->pgpibDpvt); } - + static int gpibCmdIsConsistant(gpibDpvt *pgpibDpvt) { - asynUser *pasynUser = pgpibDpvt->pasynUser; + asynUser *pasynUser = pgpibDpvt->pasynUser; gpibCmd *pgpibCmd = gpibCmdGet(pgpibDpvt); - dbCommon *precord = pgpibDpvt->precord; + dbCommon *precord = pgpibDpvt->precord; /* If gpib spscific command make sure that pasynGpib is available*/ if(!pgpibDpvt->pasynGpib) { @@ -1369,7 +1368,7 @@ static int checkEnums(char *msg, char **enums) } return -1; } - + static int writeIt(gpibDpvt *pgpibDpvt,char *message,size_t len) { gpibCmd *pgpibCmd = gpibCmdGet(pgpibDpvt); @@ -1422,7 +1421,7 @@ static void gpibErrorHappened(gpibDpvt *pgpibDpvt) asynPrint(pgpibDpvt->pasynUser,ASYN_TRACE_ERROR, "%s error.\n", pgpibDpvt->precord->name); } - + static int isTimeWindowActive(gpibDpvt *pgpibDpvt) { devGpibPvt *pdevGpibPvt = pgpibDpvt->pdevGpibPvt; @@ -1485,7 +1484,7 @@ static void devGpibSrqWaitTimeoutSet( pdeviceInstance->srq.waitTimeout = timeout; } - + static const iocshArg devGpibQueueTimeoutArg0 = {"portName",iocshArgString}; static const iocshArg devGpibQueueTimeoutArg1 = {"gpibAddr",iocshArgInt}; static const iocshArg devGpibQueueTimeoutArg2 = {"timeout",iocshArgDouble}; diff --git a/asyn/devGpib/devSupportGpib.h b/asyn/devGpib/devSupportGpib.h index 5887bb5..efd70f3 100644 --- a/asyn/devGpib/devSupportGpib.h +++ b/asyn/devGpib/devSupportGpib.h @@ -20,7 +20,6 @@ #include #include #include -#include /* supported record types */ #include @@ -57,7 +56,7 @@ typedef struct gDset gDset; typedef struct gpibDpvt gpibDpvt; typedef struct devGpibPvt devGpibPvt; typedef struct devSupportGpib devSupportGpib; - + struct gpibCmd { gDset *dset; /* used to indicate record type supported */ int type; /* enum - GPIBREAD...GPIBSRQHANDLER */ @@ -127,7 +126,7 @@ struct devGpibParmBlock { static char *xxxx[] = {"xxx","yyy",...,0}; IT MUST PROVIDE A 0 AS THE LAST STRING */ - + struct gDset { long number; DEVSUPFUN funPtr[6]; @@ -135,7 +134,7 @@ struct gDset { }; struct gpibDpvt { - devGpibParmBlock *pdevGpibParmBlock; + devGpibParmBlock *pdevGpibParmBlock; CALLBACK callback; dbCommon *precord; asynUser *pasynUser; @@ -176,7 +175,7 @@ struct devSupportGpib { int (*restoreEos)(gpibDpvt *pgpibDpvt,gpibCmd *pgpibCmd); void (*completeProcess)(gpibDpvt *pgpibDpvt); }; -epicsShareExtern devSupportGpib *pdevSupportGpib; +ASYN_API extern devSupportGpib *pdevSupportGpib; /* macros for accessing some commonly used fields*/ #define gpibDpvtGet(precord) ((gpibDpvt *)(precord)->dpvt) @@ -187,7 +186,7 @@ epicsShareExtern devSupportGpib *pdevSupportGpib; ((pdpvt)->pdevGpibParmBlock->gpibCmds[((pdpvt))->parm].type) #define devGpibNamesGet(pdpvt) \ ((pdpvt)->pdevGpibParmBlock->gpibCmds[((pdpvt))->parm].pdevGpibNames) - + /* gpibCmd.type ************************************************************ * * GPIBREAD: (1) gpibDpvt.cmd is sent to the instrument @@ -235,7 +234,7 @@ epicsShareExtern devSupportGpib *pdevSupportGpib; * convert(pgpibDpvt,P1,P2,P3); * where P1,P2,P3 are from gpibCmd ******************************************************************************/ - + /* devGpibNames ************************************************ * devGpibNames defines strings that are put into the record's * znam & onam fields for BI an BO records @@ -278,7 +277,7 @@ epicsShareExtern devSupportGpib *pdevSupportGpib; * rsp rspLen * Set by devSupportGpib. The rsp size is the largest rspLen in all gppibCmds ******************************************************************************/ - + /* gDset ************************************ * Overloads the EPICS base definition of a DSET. * It allows for exactly 6 methods. diff --git a/asyn/drvAsynFTDI/drvAsynFTDIPort.cpp b/asyn/drvAsynFTDI/drvAsynFTDIPort.cpp new file mode 100644 index 0000000..e66ac8f --- /dev/null +++ b/asyn/drvAsynFTDI/drvAsynFTDIPort.cpp @@ -0,0 +1,680 @@ +/*************************************************** +* Asyn device support for FTDI comms library * +****************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "asynDriver.h" +#include "asynOctet.h" +#include "asynOption.h" +#include "asynInterposeCom.h" +#include "asynInterposeEos.h" +#include "drvAsynFTDIPort.h" +#include "ftdiDriver.h" + +/* + * This structure holds the hardware-specific information for a single + * asyn link. There is one for each IP socket. + */ +typedef struct { + asynUser *pasynUser; /* Not currently used */ + int FTDIvendor; + int FTDIproduct; + int FTDIbaudrate; + int FTDIlatency; + int FTDImode; /* UART = 0; SPI = 1 */ + char *portName; + FTDIDriver *driver; + unsigned long nRead; + unsigned long nWritten; + int haveAddress; + osiSockAddr farAddr; + asynInterface common; + asynInterface option; + asynInterface octet; +} ftdiController_t; + +/* + * asynOption methods + */ +static asynStatus +getOption(void *drvPvt, asynUser *pasynUser, const char *key, char *val, int valSize) +{ + ftdiController_t *ftdi = (ftdiController_t *)drvPvt; + int l; + + if (epicsStrCaseCmp(key, "baud") == 0) + l = epicsSnprintf(val, valSize, "%d", ftdi->driver->getBaudRate()); + + else if (epicsStrCaseCmp(key, "bits") == 0) { + const char *v; + switch (ftdi->driver->getBits()) { + case BITS_7: v = "7"; break; + case BITS_8: v = "8"; break; + default: v = "?"; + } + + l = epicsSnprintf(val, valSize, "%s", v); + } + + else if (epicsStrCaseCmp(key, "parity") == 0) { + const char *v; + switch(ftdi->driver->getParity()) { + case NONE: v = "none"; break; + case ODD: v = "odd"; break; + case EVEN: v = "even"; break; + case MARK: v = "mark"; break; + case SPACE: v = "space"; break; + default: v = "?"; + } + l = epicsSnprintf(val, valSize, "%s", v); + } + + else if (epicsStrCaseCmp(key, "stop") == 0) { + const char *v; + switch(ftdi->driver->getStopBits()) { + case STOP_BIT_1: v = "1"; break; + case STOP_BIT_15: v = "1.5"; break; + case STOP_BIT_2: v = "2"; break; + default: v = "?"; + } + l = epicsSnprintf(val, valSize, "%s", v); + } + + else if (epicsStrCaseCmp(key, "break") == 0) { + const char *v; + switch(ftdi->driver->getBreak()) { + case BREAK_OFF: v = "off"; break; + case BREAK_ON: v = "on"; break; + default: v = "?"; + } + l = epicsSnprintf(val, valSize, "%s", v); + } + + else if (epicsStrCaseCmp(key, "flow")) { + int flowctrl = ftdi->driver->getFlowControl(); + if (flowctrl == SIO_DISABLE_FLOW_CTRL) + l = epicsSnprintf(val, valSize, "%s", "none"); + else { + char v[256] = {}; + int n = 0; + if (flowctrl & SIO_RTS_CTS_HS) { strcat(v, "rts_cts"); ++n; } + if (n) { strcat(v, "|"); } + if (flowctrl & SIO_DTR_DSR_HS) { strcat(v, "dtr_dsr"); ++n; } + if (n) { strcat(v, "|"); } + if (flowctrl & SIO_XON_XOFF_HS) { strcat(v, "xon_xoff"); } + l = epicsSnprintf(val, valSize, "%s", v); + } + } + + else { + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "Unsupported key \"%s\"", key); + return asynError; + } + + if (l >= valSize) { + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "Value buffer for key '%s' is too small.", key); + return asynError; + } + return asynSuccess; +} + +static asynStatus +setOption(void *drvPvt, asynUser *pasynUser, const char *key, const char *val) +{ + ftdiController_t *ftdi = (ftdiController_t *)drvPvt; + assert(ftdi); + + asynPrint(pasynUser, ASYN_TRACE_FLOW, + "%s setOption key %s val %s\n", ftdi->portName, key, val); + + if (epicsStrCaseCmp(key, "baud") == 0) { + int baud; + if (sscanf(val, "%d", &baud) != 1) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Bad number"); + return asynError; + } + if (ftdi->driver->setBaudrate(baud)) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Unsupported data rate (%d baud)", baud); + return asynError; + } + } else if (epicsStrCaseCmp(key, "parity") == 0) { + enum ftdi_parity_type parity; + if (epicsStrCaseCmp(val, "none") == 0) parity = NONE; + else if (epicsStrCaseCmp(val, "even") == 0) parity = EVEN; + else if (epicsStrCaseCmp(val, "odd") == 0) parity = ODD; + else if (epicsStrCaseCmp(val, "mark") == 0) parity = MARK; + else if (epicsStrCaseCmp(val, "space") == 0) parity = SPACE; + else { + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "Invalid parity \"%s\".", val); + return asynError; + } + if (ftdi->driver->setParity(parity)) + return asynError; + } + else if (epicsStrCaseCmp(key, "stop") == 0) { + enum ftdi_stopbits_type sbits; + if (epicsStrCaseCmp(val, "1") == 0) sbits = STOP_BIT_1; + else if (epicsStrCaseCmp(val, "1.5") == 0) sbits = STOP_BIT_15; + else if (epicsStrCaseCmp(val, "2") == 0) sbits = STOP_BIT_2; + else { + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "Invalid number of stop bits \"%s\".", val); + return asynError; + } + if (ftdi->driver->setStopBits(sbits)) + return asynError; + } + else if (epicsStrCaseCmp(key, "break") == 0) { + enum ftdi_break_type brk; + if (epicsStrCaseCmp(val, "on") == 0) brk = BREAK_ON; + else if (epicsStrCaseCmp(val, "off") == 0) brk = BREAK_OFF; + else { + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "Invalid break \"%s\".", val); + return asynError; + } + if (ftdi->driver->setBreak(brk)) + return asynError; + } + else if (epicsStrCaseCmp(key, "flow") == 0) { + int flowctrl = SIO_DISABLE_FLOW_CTRL; + if (epicsStrCaseCmp(val, "none") != 0) { + char *str = epicsStrDup(val); + char *token; + char *rest = str; + + while ((token = strtok_r(rest, "|", &rest))) { + if (epicsStrCaseCmp(token, "rts_cts") == 0) flowctrl |= SIO_RTS_CTS_HS; + else if (epicsStrCaseCmp(token, "dtr_dsr") == 0) flowctrl |= SIO_DTR_DSR_HS; + else if (epicsStrCaseCmp(token, "xon_xoff") == 0) flowctrl |= SIO_XON_XOFF_HS; + else { + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "Invalid flow control \"%s\".", val); + free(str); + return asynError; + } + } + free(str); + } + if (ftdi->driver->setFlowControl(flowctrl)) + return asynError; + } + else if (epicsStrCaseCmp(key, "") != 0) { + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "Unsupported key \"%s\"", key); + return asynError; + } + + return asynSuccess; +} +static const struct asynOption asynOptionMethods = { setOption, getOption }; + +/* + * Close a connection + */ +static void +closeConnection(asynUser *pasynUser,ftdiController_t *ftdi,const char *why) +{ + asynPrint(pasynUser, ASYN_TRACE_FLOW, + "Close %d:%d connection (driver %p): %s\n", ftdi->FTDIvendor, ftdi->FTDIproduct, ftdi->driver, why); + if (ftdi->driver){ + ftdi->driver->disconnectFTDI(); + delete(ftdi->driver); + ftdi->driver = 0; + } +} + +/*Beginning of asynCommon methods*/ +/* + * Report link parameters + */ +static void +asynCommonReport(void *drvPvt, FILE *fp, int details) +{ + ftdiController_t *ftdi = (ftdiController_t *)drvPvt; + + assert(ftdi); + if (details >= 1) { + fprintf(fp, " Port %d:%d: %sonnected\n", + ftdi->FTDIvendor, ftdi->FTDIproduct, + ftdi->driver ? "C" : "Disc"); + } + if (details >= 2) { + fprintf(fp, " Characters written: %lu\n", ftdi->nWritten); + fprintf(fp, " Characters read: %lu\n", ftdi->nRead); + } +} + +/* + * Clean up a connection on exit + */ +static void +cleanup (void *arg) +{ + asynStatus status; + ftdiController_t *ftdi = (ftdiController_t *)arg; + + if (!ftdi) return; + status=pasynManager->lockPort(ftdi->pasynUser); + if(status!=asynSuccess) + asynPrint(ftdi->pasynUser, ASYN_TRACE_ERROR, "%s: cleanup locking error\n", ftdi->portName); + + if (ftdi->driver){ + asynPrint(ftdi->pasynUser, ASYN_TRACE_FLOW, "%s: shutdown socket\n", ftdi->portName); + ftdi->driver->disconnectFTDI(); + delete(ftdi->driver); + } + + if(status==asynSuccess) + pasynManager->unlockPort(ftdi->pasynUser); +} + +/* + * Create a link +*/ +static asynStatus +connectIt(void *drvPvt, asynUser *pasynUser) +{ + ftdiController_t *ftdi = (ftdiController_t *)drvPvt; + + /* + * Sanity check + */ + assert(ftdi); + asynPrint(pasynUser, ASYN_TRACE_FLOW, + "Open connection to %d:%d reason:%d \n", ftdi->FTDIvendor, ftdi->FTDIproduct, + pasynUser->reason); + + if (ftdi->driver){ + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "%d:%d: Link already open!", ftdi->FTDIvendor, ftdi->FTDIproduct); + return asynError; + } + + // Create the driver + + printf("connectIt: ftdi->FTDImode=%d - ", ftdi->FTDImode); + if( (ftdi->FTDImode & FTDImode::SPI) == FTDImode::SPI ) printf( "SPI\n"); + else printf("UART\n"); + + ftdi->driver = new FTDIDriver(ftdi->FTDImode); + + // Set the vendor & product IDs + ftdi->driver->setVPID(ftdi->FTDIvendor, ftdi->FTDIproduct); + + // Set the baud rate + ftdi->driver->setBaudrate(ftdi->FTDIbaudrate); + + // Set the latency + ftdi->driver->setLatency(ftdi->FTDIlatency); + + // Connect to the remote host + if (ftdi->driver->connectFTDI() != FTDIDriverSuccess){ + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "Can't connect to %d:%d", + ftdi->FTDIvendor, ftdi->FTDIproduct); + ftdi->haveAddress = 0; + delete(ftdi->driver); + ftdi->driver = 0; + return asynError; + } + + asynPrint(pasynUser, ASYN_TRACE_FLOW, "Opened connection to %d:%d\n", ftdi->FTDIvendor, ftdi->FTDIproduct); + return asynSuccess; +} + +static asynStatus +asynCommonConnect(void *drvPvt, asynUser *pasynUser) +{ + asynStatus status = asynSuccess; + + status = connectIt(drvPvt, pasynUser); + + if (status == asynSuccess) + pasynManager->exceptionConnect(pasynUser); + return status; +} + +static asynStatus +asynCommonDisconnect(void *drvPvt, asynUser *pasynUser) +{ + ftdiController_t *ftdi = (ftdiController_t *)drvPvt; + + assert(ftdi); + closeConnection(pasynUser,ftdi,"Disconnect request"); + return asynSuccess; +} + +/*Beginning of asynOctet methods*/ +/* + * Write to the USB FTDI port + */ +static asynStatus writeIt(void *drvPvt, asynUser *pasynUser, + const char *data, size_t numchars,size_t *nbytesTransfered) +{ + ftdiController_t *ftdi = (ftdiController_t *)drvPvt; + size_t thisWrite; + asynStatus status = asynSuccess; + + assert(ftdi); + asynPrint(pasynUser, ASYN_TRACE_FLOW, + "%d:%d write.\n", ftdi->FTDIvendor, ftdi->FTDIproduct); + asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, numchars, + "%d:%d write %lu\n", ftdi->FTDIvendor, ftdi->FTDIproduct, numchars); + *nbytesTransfered = 0; + + // Here we will simply issue the write to the driver + if (!ftdi->driver){ + if ((status = connectIt(drvPvt, pasynUser)) != asynSuccess){ + return status; + } + } + if (numchars == 0){ + return asynSuccess; + } + if (ftdi->driver->write((unsigned char *)data, numchars, &thisWrite, (int)(pasynUser->timeout*1000.0)) != FTDIDriverSuccess){ + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%d:%d write error", ftdi->FTDIvendor, ftdi->FTDIproduct); + closeConnection(pasynUser,ftdi,"Write error"); + status = asynError; + } + *nbytesTransfered = thisWrite; + asynPrint(pasynUser, ASYN_TRACE_FLOW, + "wrote %lu to %d:%d, return %s.\n", (unsigned long)*nbytesTransfered, + ftdi->FTDIvendor, ftdi->FTDIproduct, + pasynManager->strStatus(status)); + return status; +} + +/* + * Read from the TCP port + */ +static asynStatus readIt(void *drvPvt, asynUser *pasynUser, + char *data, size_t maxchars,size_t *nbytesTransfered,int *gotEom) +{ + ftdiController_t *ftdi = (ftdiController_t *)drvPvt; + size_t thisRead; + int reason = 0; + asynStatus status = asynSuccess; + FTDIDriverStatus driverStatus = FTDIDriverSuccess; + + assert(ftdi); + asynPrint(pasynUser, ASYN_TRACE_FLOW, + "%d:%d read.\n", ftdi->FTDIvendor, ftdi->FTDIproduct); + if (!ftdi->driver){ + if ((status = connectIt(drvPvt, pasynUser)) != asynSuccess){ + return status; + } + } + if (maxchars <= 0) { + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "%d:%d maxchars %d. Why <=0?\n",ftdi->FTDIvendor, ftdi->FTDIproduct,(int)maxchars); + return asynError; + } + + if (gotEom) *gotEom = 0; + driverStatus = ftdi->driver->read((unsigned char *)data, maxchars, &thisRead, (int)(pasynUser->timeout*1000.0)); + if (driverStatus != FTDIDriverSuccess){ + if (driverStatus == FTDIDriverError){ + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%d:%d read error", ftdi->FTDIvendor, ftdi->FTDIproduct); + closeConnection(pasynUser,ftdi,"Read error"); + status = asynError; + } else if (driverStatus == FTDIDriverTimeout){ + status = asynTimeout; + } + } + + if (thisRead < 0){ + thisRead = 0; + } + *nbytesTransfered = thisRead; + + /* If there is room add a null byte */ + if (thisRead < maxchars) + data[thisRead] = 0; + else + reason |= ASYN_EOM_CNT; + + if (gotEom) *gotEom = reason; + + if (thisRead == 0 && pasynUser->timeout == 0){ + status = asynTimeout; + } + + return status; +} + +/* + * Flush pending input + */ +static asynStatus +flushIt(void *drvPvt,asynUser *pasynUser) +{ + ftdiController_t *ftdi = (ftdiController_t *)drvPvt; + + assert(ftdi); + asynPrint(pasynUser, ASYN_TRACE_FLOW, "%d:%d flush\n", ftdi->FTDIvendor, ftdi->FTDIproduct); + if (ftdi->driver){ + ftdi->driver->flush(); + } + return asynSuccess; +} + +/* + * Clean up a ftdiController + */ +static void +ftdiCleanup(ftdiController_t *ftdi) +{ + if (ftdi) { + if (ftdi->driver) + free(ftdi->portName); +/* free(ftdi->FTDIDeviceName); */ + free(ftdi); + } +} + +/* + * asynCommon methods + */ +static const struct asynCommon drvAsynFTDIPortAsynCommon = { + asynCommonReport, + asynCommonConnect, + asynCommonDisconnect +}; + +/* + * Configure and register a USB port from a hostInfo string + */ +ASYN_API int +drvAsynFTDIPortConfigure(const char *portName, + int vendor, + int product, + int baudrate, + int latency, + unsigned int priority, + int noAutoConnect, + int noProcessEos, + int mode) +{ + int SPI = ((mode & UART_SPI_BIT)==UART_SPI_BIT)? 1:0; + + printf("drvAsynFTDIPortConfigure: latency=%d\n", latency); + printf("drvAsynFTDIPortConfigure: priority=%d\n", priority); + printf("drvAsynFTDIPortConfigure: noAutoconnect=%d\n", noAutoConnect); + printf("drvAsynFTDIPortConfigure: noProcessEos=%d\n", noProcessEos); + printf("drvAsynFTDIPortConfigure: mode="); SPI ? printf("SPI\n") : printf("UART\n"); + + ftdiController_t *ftdi; + asynInterface *pasynInterface; + asynStatus status; + int nbytes; + asynOctet *pasynOctet; + + /* Latency must be between 1 and 255 */ + if (latency < 1) + latency = 1; + else if (latency > 255) + latency= 255; + + /* + * Check arguments + * + if (vendor == 0) { + printf("asynFTDI vendor ID missing.\n"); + return -1; + } + if (product == NULL) { + printf("asynFTDI product ID missing.\n"); + return -1; + } + if (baudrate == NULL) { + printf("asynFTDI username missing.\n"); + return -1; + } */ + + + /* + * Create a driver + */ + nbytes = sizeof(*ftdi) + sizeof(asynOctet); + + ftdi = (ftdiController_t *)callocMustSucceed(1, nbytes, + "drvAsynFTDIPortConfigure()"); + + pasynOctet = (asynOctet *)(ftdi+1); + ftdi->driver = NULL; + + ftdi->FTDIvendor = vendor; + ftdi->FTDIproduct = product; + ftdi->FTDIbaudrate = baudrate; + ftdi->FTDIlatency = latency; + ftdi->FTDImode = SPI; + ftdi->portName = epicsStrDup(portName); + + /* + * Link with higher level routines + */ + pasynInterface = (asynInterface *)callocMustSucceed(2, sizeof *pasynInterface, "drvAsynFTDIPortConfigure"); + ftdi->common.interfaceType = asynCommonType; + ftdi->common.pinterface = (void *)&drvAsynFTDIPortAsynCommon; + ftdi->common.drvPvt = ftdi; + ftdi->option.interfaceType = asynOptionType; + ftdi->option.pinterface = (void*)&asynOptionMethods; + ftdi->option.drvPvt = ftdi; + + if (pasynManager->registerPort(ftdi->portName, + ASYN_CANBLOCK, + !noAutoConnect, + priority, + 500000) != asynSuccess) { + printf("drvAsynFTDIPortConfigure: Can't register myself.\n"); + ftdiCleanup(ftdi); + return -1; + } + + status = pasynManager->registerInterface(ftdi->portName,&ftdi->common); + if(status != asynSuccess) { + printf("drvAsynFTDIPortConfigure: Can't register common.\n"); + ftdiCleanup(ftdi); + return -1; + } + + status = pasynManager->registerInterface(ftdi->portName,&ftdi->option); + if(status != asynSuccess) { + printf("drvAsynFTDIPortConfigure: Can't register option.\n"); + ftdiCleanup(ftdi); + return -1; + } + + pasynOctet->read = readIt; + pasynOctet->write = writeIt; + pasynOctet->flush = flushIt; + ftdi->octet.interfaceType = asynOctetType; + ftdi->octet.pinterface = pasynOctet; + ftdi->octet.drvPvt = ftdi; + status = pasynOctetBase->initialize(ftdi->portName,&ftdi->octet, 0, 0, 1); + if(status != asynSuccess) { + printf("drvAsynFTDIPortConfigure: pasynOctetBase->initialize failed.\n"); + ftdiCleanup(ftdi); + return -1; + } + if (!noProcessEos) + asynInterposeEosConfig(ftdi->portName, -1, 1, 1); + ftdi->pasynUser = pasynManager->createAsynUser(0,0); + status = pasynManager->connectDevice(ftdi->pasynUser,ftdi->portName,-1); + if(status != asynSuccess) { + printf("connectDevice failed %s\n",ftdi->pasynUser->errorMessage); + ftdiCleanup(ftdi); + return -1; + } + /* + * Register for socket cleanup + */ + epicsAtExit(cleanup, ftdi); + return 0; +} + +/* + * IOC shell command registration + */ +static const iocshArg drvAsynFTDIPortConfigureArg0 = { "port name",iocshArgString}; +static const iocshArg drvAsynFTDIPortConfigureArg1 = { "vendor ID",iocshArgInt}; +static const iocshArg drvAsynFTDIPortConfigureArg2 = { "product ID",iocshArgInt}; +static const iocshArg drvAsynFTDIPortConfigureArg3 = { "baudrate",iocshArgInt}; +static const iocshArg drvAsynFTDIPortConfigureArg4 = { "latency",iocshArgInt}; +static const iocshArg drvAsynFTDIPortConfigureArg5 = { "priority",iocshArgInt}; +static const iocshArg drvAsynFTDIPortConfigureArg6 = { "disable auto-connect",iocshArgInt}; +static const iocshArg drvAsynFTDIPortConfigureArg7 = { "noProcessEos",iocshArgInt}; +static const iocshArg drvAsynFTDIPortConfigureArg8 = { "mode",iocshArgInt}; +static const iocshArg *drvAsynFTDIPortConfigureArgs[] = { + &drvAsynFTDIPortConfigureArg0, &drvAsynFTDIPortConfigureArg1, + &drvAsynFTDIPortConfigureArg2, &drvAsynFTDIPortConfigureArg3, + &drvAsynFTDIPortConfigureArg4, &drvAsynFTDIPortConfigureArg5, + &drvAsynFTDIPortConfigureArg6, &drvAsynFTDIPortConfigureArg7, + &drvAsynFTDIPortConfigureArg8}; +static const iocshFuncDef drvAsynFTDIPortConfigureFuncDef = + {"drvAsynFTDIPortConfigure",9,drvAsynFTDIPortConfigureArgs}; +static void drvAsynFTDIPortConfigureCallFunc(const iocshArgBuf *args) +{ + drvAsynFTDIPortConfigure(args[0].sval, args[1].ival, args[2].ival, args[3].ival, args[4].ival, args[5].ival, args[6].ival, args[7].ival, args[8].ival); +} + +/* + * This routine is called before multitasking has started, so there's + * no race condition in the test/set of firstTime. + */ +static void +drvAsynFTDIPortRegisterCommands(void) +{ + static int firstTime = 1; + if (firstTime) { + iocshRegister(&drvAsynFTDIPortConfigureFuncDef,drvAsynFTDIPortConfigureCallFunc); + firstTime = 0; + } +} +epicsExportRegistrar(drvAsynFTDIPortRegisterCommands); + diff --git a/asyn/drvAsynFTDI/drvAsynFTDIPort.dbd b/asyn/drvAsynFTDI/drvAsynFTDIPort.dbd new file mode 100644 index 0000000..a5bb517 --- /dev/null +++ b/asyn/drvAsynFTDI/drvAsynFTDIPort.dbd @@ -0,0 +1 @@ +registrar(drvAsynFTDIPortRegisterCommands) diff --git a/asyn/drvAsynFTDI/drvAsynFTDIPort.h b/asyn/drvAsynFTDI/drvAsynFTDIPort.h new file mode 100644 index 0000000..897c51d --- /dev/null +++ b/asyn/drvAsynFTDI/drvAsynFTDIPort.h @@ -0,0 +1,26 @@ +/********************************************************************** +* Asyn device support using FTDI communications library * +**********************************************************************/ +#ifndef DRVASYNFTDIPORT_H +#define DRVASYNFTDIPORT_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define UART_SPI_BIT 0x01 // 0 = UART; 1 = SPI + +ASYN_API int drvAsynFTDIPortConfigure(const char *portname, + const int vendor, + const int product, + const int baudrate, + const int latency, + unsigned int priority, + int noAutoConnect, + int noProcessEos, + int mode); // UART = 0x00; SPI = 0x01; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DRVASYNFTDIPORT_H */ diff --git a/asyn/drvAsynFTDI/ftdiDriver.cpp b/asyn/drvAsynFTDI/ftdiDriver.cpp new file mode 100644 index 0000000..b2d27d0 --- /dev/null +++ b/asyn/drvAsynFTDI/ftdiDriver.cpp @@ -0,0 +1,781 @@ +/******************************************** + * ftdiDriver.cpp + * + * Wrapper class for the libftdi1 library + * This class provides standard read/write + * and flush methods for an FTDI chip USB connection. + * + * Philip Taylor + * 8 Jul 2013 + * + ********************************************/ +#include +#include +#include "ftdiDriver.h" +#include "epicsThread.h" +#ifndef _MINGW +#ifdef _WIN32 +int gettimeofday(struct timeval *tv, struct timezone *tz); +void usleep(__int64 usec); +#else +#include +#endif +#endif + +/* + * Uncomment the DEBUG define and recompile for lots of + * driver debug messages. + */ + +/* +#define DEBUG 1 +*/ + +#ifdef DEBUG +#define debugPrint printf +#else +void debugPrint(...){} +#endif + + +/** + * Constructor for the FTDI driver. Accepts a Vendor ID and + * Product ID. Initializes internal variables. + * + * @param vendor - Vendor ID + * @param product - Product ID + */ +FTDIDriver::FTDIDriver(int mode):spi(mode) +{ + static const char *functionName = "FTDIDriver::FTDIDriver"; + debugPrint("%s : Method called - ", functionName); + if( spi ) debugPrint("SPI\n"); + else debugPrint("UART\n"); + + // Initialize internal FTDI parameters + connected_ = 0; + // Vendor and Product ID set to FTDI FT2232H default values + vendor_ = 0x0403; + product_ = 0x6010; + // Baudrate and latency set to 12 Mb and 2 msecs. + baudrate_ = 12000000; + latency_ = 2; + // Reasonable defaults for line properties and flow control + bits_ = BITS_8; + sbits_ = STOP_BIT_1; + parity_ = NONE; + break_ = BREAK_OFF; + flowctrl_ = SIO_DISABLE_FLOW_CTRL; + spiInit = 0; // Status whether init done + memset(buf, 0, sizeof(buf)); +} + +FTDIDriverStatus FTDIDriver::initSPI() { + unsigned int i = 0; + unsigned int n = 0; + + FTDIDriverStatus rc = FTDIDriverError; + + static const char *functionName = "FTDIDriver::initSPI"; + debugPrint("%s : Method called, spi=%d\n", functionName, spi); + + ftdi_set_bitmode(ftdi_, 0, 0); // reset + ftdi_set_bitmode(ftdi_, 0, BITMODE_MPSSE); // enable mpsse on all bits + ftdi_usb_purge_buffers(ftdi_); + epicsThreadSleep(0.060); + + i = 0; + // MASTER RESET + pinState = Pin::CS|Pin::SYNCIO|Pin::RESET; + pinDirection = Pin::SK|Pin::DO|Pin::CS|Pin::SYNCIO|Pin::RESET; + pbuf = (unsigned char *)&buf[0]; + *(pbuf + i++) = TCK_DIVISOR; // opcode: set clk divisor + *(pbuf + i++) = 0x05; // argument: low bit. 60 MHz / (5+1) = 1 MHz + *(pbuf + i++) = 0x00; // argument: high bit. + *(pbuf + i++) = DIS_ADAPTIVE; // opcode: disable adaptive clocking + *(pbuf + i++) = DIS_3_PHASE; // opcode: disable 3-phase clocking + *(pbuf + i++) = SET_BITS_LOW; // opcode: set low bits (ADBUS[0-7]) + *(pbuf + i++) = pinState; // argument: inital pin states + *(pbuf + i++) = pinDirection; // argument: pin direction + n = ftdi_write_data(ftdi_, pbuf, i); + rc = (n==i)?FTDIDriverSuccess:FTDIDriverError; + if( rc== FTDIDriverSuccess ) { + spiInit = 1; + debugPrint("%s : Method called: MASTER RESET, pinState=0x%02x\n", + functionName, pinState); + } + else debugPrint("%s : Method call FAILED!\n", functionName); + flush(); + epicsThreadSleep(0.1); + + i = 0; // CLEAR MASTER RESET + *(pbuf + i++) = SET_BITS_LOW; // opcode: set low bits (ADBUS[0-7]) + pinState&=~Pin::RESET; + *(pbuf + i++) = pinState; // argument: inital pin states + *(pbuf + i++) = pinDirection; // argument: pin direction + n = ftdi_write_data(ftdi_, pbuf, i); + rc = (n==i)?FTDIDriverSuccess:FTDIDriverError; + if( rc== FTDIDriverSuccess ) { + spiInit = 2; + debugPrint("%s : Method called: CLEAR RESET, pinState=0x%02x\n", + functionName, pinState); + } + else debugPrint("%s : Method call FAILED!\n", functionName); + flush(); + // Wait 1 ms + epicsThreadSleep(0.001); + + // CLEAR SYNCIO + i = 0; + *(pbuf + i++) = SET_BITS_LOW; // opcode: set low bits (ADBUS[0-7]) + pinState&=~Pin::SYNCIO; + *(pbuf + i++) = pinState; // argument: inital pin states + *(pbuf + i++) = pinDirection; // argument: pin direction + n = ftdi_write_data(ftdi_, pbuf, i); + rc = (n==i)?FTDIDriverSuccess:FTDIDriverError; + if( rc== FTDIDriverSuccess ) { + spiInit = 3; + debugPrint("%s : Method called: CLEAR SYNCIO, pinState=0x%02x\n", + functionName, pinState); + } + else debugPrint("%s : Method callFAILED!\n", functionName); + + // PULL CS LOW + i = 0; + *(pbuf + i++) = SET_BITS_LOW; // opcode: set low bits (ADBUS[0-7]) + pinState&=~Pin::CS; + *(pbuf + i++) = pinState; // argument: inital pin states + *(pbuf + i++) = pinDirection; // argument: pin direction + n = ftdi_write_data(ftdi_, pbuf, i); + rc = (n==i)?FTDIDriverSuccess:FTDIDriverError; + if( rc== FTDIDriverSuccess ) { + spiInit = 4; + debugPrint("%s : Method called: PULL CS LOW, pinState=0x%02x\n", + functionName, pinState); + } + else debugPrint("%s : Method call FAILED!\n", functionName); + + return rc; +} + +/** + * Setup the Vendor ID and Product ID for the USB device. + * + * @param vendor - Vendor ID + * @param product - Product ID + * @return - Success or failure. + */ +FTDIDriverStatus FTDIDriver::setVPID(const int vendor, const int product) +{ + static const char *functionName = "FTDIDriver::setVPID"; + debugPrint("%s : Method called: SPI=%d\n", functionName, spi); + + // Store the Vendor ID + vendor_ = vendor; + + // Store the Product ID + product_ = product; + + return FTDIDriverSuccess; +} + +/** + * Setup the baudrate. + * + * @param baudrate - Baud rate + * @return - Success or failure. + */ +FTDIDriverStatus FTDIDriver::setBaudrate(const int baudrate) +{ + static const char *functionName = "FTDIDriver::setBaudrate"; + debugPrint("%s : Method called\n", functionName); + + int f; + if (ftdi_ && (f = ftdi_set_baudrate(ftdi_, baudrate))) { + debugPrint("Failed to set FTDI baudrate: %d (%s)\n", f, ftdi_get_error_string(ftdi_)); + return FTDIDriverError; + } + + baudrate_ = baudrate; + return FTDIDriverSuccess; +} + +/** + * Setup the bits. + * + * @param bits - Bits + * @return - Success or failure. + */ +FTDIDriverStatus FTDIDriver::setBits(enum ftdi_bits_type bits) +{ + static const char *functionName = "FTDIDriver::setBits"; + debugPrint("%s : Method called\n", functionName); + return setLineProperties(bits, sbits_, parity_, break_); +} + +/** + * Setup the stop bits. + * + * @param sbits - Stop bits + * @return - Success or failure. + */ +FTDIDriverStatus FTDIDriver::setStopBits(enum ftdi_stopbits_type sbits) +{ + static const char *functionName = "FTDIDriver::setStopBits"; + debugPrint("%s : Method called\n", functionName); + return setLineProperties(bits_, sbits, parity_, break_); +} + +/** + * Setup the parity. + * + * @param parity - Parity + * @return - Success or failure. + */ +FTDIDriverStatus FTDIDriver::setParity(enum ftdi_parity_type parity) +{ + static const char *functionName = "FTDIDriver::setParity"; + debugPrint("%s : Method called\n", functionName); + return setLineProperties(bits_, sbits_, parity, break_); +} + +/** + * Setup the break. + * + * @param brk - Break + * @return - Success or failure. + */ +FTDIDriverStatus FTDIDriver::setBreak(enum ftdi_break_type brk) +{ + static const char *functionName = "FTDIDriver::setBreak"; + debugPrint("%s : Method called\n", functionName); + return setLineProperties(bits_, sbits_, parity_, brk); +} + +FTDIDriverStatus FTDIDriver::setLineProperties(enum ftdi_bits_type bits, + enum ftdi_stopbits_type sbits, enum ftdi_parity_type parity, enum ftdi_break_type brk) +{ + static const char *functionName = "FTDIDriver::setLineProperties"; + debugPrint("%s : Method called\n", functionName); + + int f; + if (ftdi_ && (f = ftdi_set_line_property2(ftdi_, bits, sbits, parity, brk))) + { + debugPrint("Failed to set FTDI line parameters: %d (%s)\n", f, ftdi_get_error_string(ftdi_)); + return FTDIDriverError; + } + + bits_ = bits; + sbits_ = sbits; + parity_ = parity; + break_ = brk; + + return FTDIDriverSuccess; +} + +/** + * Setup the flow control. + * + * @param flowctrl - Flow control. Either SIO_DISABLE_FLOW_CTRL or + * a OR combination of SIO_RTS_CTS_HS, SIO_DTR_DSR_HS + * and SIO_XON_XOFF_HS. + * @return - Success or failure. + */ +FTDIDriverStatus FTDIDriver::setFlowControl(int flowctrl) +{ + static const char *functionName = "FTDIDriver::setFlowControl"; + debugPrint("%s : Method called\n", functionName); + + int f; + if (ftdi_ && (f = ftdi_setflowctrl(ftdi_, flowctrl))) + { + debugPrint("Failed to set FTDI flow control: %d (%s)\n", f, ftdi_get_error_string(ftdi_)); + return FTDIDriverError; + } + flowctrl_ = flowctrl; + return FTDIDriverSuccess; +} + +/** + * Setup the latency. + * + * @param latency - FTDI chip latency time. The latency timer counts from the + * last time data was sent back to the host. If the latency timer expires, + * the device will send what data it has available to the host regardless + * of how many bytes it is waiting on. The latency timer will then reset + * and begin counting again. The default value for the latency timer is 16ms. + * + * @return - Success or failure. + */ +FTDIDriverStatus FTDIDriver::setLatency(const int latency) +{ + static const char *functionName = "FTDIDriver::setLatency"; + debugPrint("%s : Method called\n", functionName); + + int f; + if (ftdi_ && (f = ftdi_set_latency_timer (ftdi_, latency))) { + debugPrint("Failed to set FTDI latency: %d (%s)\n", f, ftdi_get_error_string(ftdi_)); + return FTDIDriverError; + } + + latency_ = latency; + return FTDIDriverSuccess; +} + +/** + * Get the Baud rate. + * + * @return - The Baud rate. + */ +int FTDIDriver::getBaudRate(void) +{ + return ftdi_->baudrate; +} + +/** + * Get the bits. + * + * @return - The bits. + */ +enum ftdi_bits_type FTDIDriver::getBits(void) +{ + return bits_; +} + +/** + * Get the stop bits. + * + * @return - The stop bits. + */ +enum ftdi_stopbits_type FTDIDriver::getStopBits(void) +{ + return sbits_; +} + +/** + * Get the parity. + * + * @return - The parity. + */ +enum ftdi_parity_type FTDIDriver::getParity(void) +{ + return parity_; +} + +/** + * Get the break. + * + * @return - The break. + */ +enum ftdi_break_type FTDIDriver::getBreak(void) +{ + return break_; +} + +/** + * Get the flow control. + * + * @return - The flow control. + */ +int FTDIDriver::getFlowControl(void) +{ + return flowctrl_; +} + +/** + * Attempt to create a connection Once the connection has + * been established. + * + * @return - Success or failure. + */ +FTDIDriverStatus FTDIDriver::connectFTDI() +{ + int f; + unsigned int chipid; + static const char *functionName = "FTDIDriver::connect"; + debugPrint("%s : Method called\n", functionName); + +#ifdef HAVE_LIBFTDI1 + struct ftdi_version_info version = ftdi_get_library_version(); + printf("Initialized libftdi %s (major: %d, minor: %d, micro: %d, snapshot ver: %s)\n", + version.version_str, version.major, version.minor, version.micro, version.snapshot_str); +#else + printf("Initialized libftdi\n"); +#endif + + // Allocate and initialize a new ftdi context + if ((ftdi_ = ftdi_new()) == NULL) + { + debugPrint("ftdi_new failed: %s\n", ftdi_get_error_string(ftdi_)); + return FTDIDriverError; + } + + // Select interface. In this case just use "ANY" + if ((f = ftdi_set_interface(ftdi_, INTERFACE_ANY)) != 0) + { + debugPrint("ftdi_set_interface failed: %d (%s)\n", f, ftdi_get_error_string(ftdi_)); + return FTDIDriverError; + } + + // Open the FTDI USB device + if ((f = ftdi_usb_open(ftdi_, vendor_, product_)) != 0) + { + debugPrint("Failed to open FTDI device: %d (%s)\n", f, ftdi_get_error_string(ftdi_)); + return FTDIDriverError; + } + + // Read out FTDI chip ID + debugPrint("ftdi->type = %d. ", ftdi_->type); + ftdi_read_chipid(ftdi_, &chipid); + printf("FTDI chipid: %X\n", chipid); + + // Set baudrate + if (setBaudrate(baudrate_)) + return FTDIDriverError; + + // Set line parameters + if (setLineProperties(bits_, sbits_, parity_, break_)) + return FTDIDriverError; + + // Set FTDI chip latency in millisecs. + if (setLatency(latency_)) + return FTDIDriverError; + + // Set FTDI flow control + if (setFlowControl(flowctrl_)) + return FTDIDriverError; + + // Reset device after setting the latency, otherwise the initial communication will result in an error + if ((f = ftdi_usb_reset (ftdi_)) != 0) + { + debugPrint("Failed to reset FTDI: %d (%s)\n", f, ftdi_get_error_string(ftdi_)); + return FTDIDriverError; + } + + // Purge the send and receive buffers + if ((f = ftdi_usb_purge_tx_buffer (ftdi_)) != 0) + { + debugPrint("Failed to purge FTDI tx buffer: %d (%s)\n", f, ftdi_get_error_string(ftdi_)); + return FTDIDriverError; + } + + if ((f = ftdi_usb_purge_rx_buffer (ftdi_)) != 0) + { + debugPrint("Failed to purge FTDI rx buffer: %d (%s)\n", f, ftdi_get_error_string(ftdi_)); + return FTDIDriverError; + } + + // Wait 60 ms. for purge to complete + epicsThreadSleep(0.060); + + if ((f = ftdi_read_data_set_chunksize(ftdi_, 8192)) != 0) + { + debugPrint("Failed to set FTDI read chunk size: %d (%s)\n", f, ftdi_get_error_string(ftdi_)); + return FTDIDriverError; + } + + if ((f = ftdi_write_data_set_chunksize(ftdi_, 8192)) != 0) + { + debugPrint("Failed to set FTDI write chunk size: %d (%s)\n", f, ftdi_get_error_string(ftdi_)); + return FTDIDriverError; + } + + debugPrint("%s : FTDI Connection ready...\n", functionName); + connected_ = 1; + + if( spi ) { + debugPrint("INIT SPI-\n"); + FTDIDriver::initSPI(); + } + + return FTDIDriverSuccess; +} + +/** + * Flush the FTDI connection as best as possible. + * + * @return - Success or failure. + */ +FTDIDriverStatus FTDIDriver::flush() +{ + int f; + static const char *functionName = "FTDIDriver::flush"; + debugPrint("%s : Method called\n", functionName); + + if (connected_ == 0){ + debugPrint("%s : FTDI not connected\n", functionName); + return FTDIDriverError; + } + + // Clears read & write buffers on the chip and the internal read buffer + f = ftdi_usb_purge_buffers(ftdi_); + if (f < 0){ + debugPrint("Failed to purge FTDI buffers: %d (%s)\n", f, ftdi_get_error_string(ftdi_)); + return FTDIDriverError; + } + return FTDIDriverSuccess; +} + +/** + * Write data to the connected channel. A timeout should be + * specified in milliseconds. + * + * @param buffer - The string buffer to be written. + * @param bufferSize - The number of bytes to write. + * @param bytesWritten - The number of bytes that were written. + * @param timeout - A timeout in ms for the write. + * @return - Success or failure. + */ +FTDIDriverStatus FTDIDriver::write(const unsigned char *buffer, int bufferSize, size_t *bytesWritten, int timeout) +{ + /*********************************************************************************/ + /* Array for collecting Return Codes from various stages of (SPI) write */ + /* (for compilation of a single debugPrint message at the end). Good to have */ + /* while debugging MSSP protocol and monitoring pinState with a scope. */ + /* AD9915 read back data is clocked "back" synchronously while writing under */ + /* condition that bit[7] of the instruction byte was 1: 'ftdi_transfer_data_done'*/ + /* to AD9915 can fail at different stages if CS, SYNCIO, I/O_UPDATE are not */ + /* pulled in timely manner. Currently these lines (pinState) are controlled by */ + /* (hard coded) binary bytes embedded into the 'stream' protocol. */ + /*********************************************************************************/ + size_t rc[16]; + size_t i = 0; + int err =0; + + unsigned short sz = (unsigned short)bufferSize - 1; + + static const char *functionName = "FTDIDriver::write"; + debugPrint("%s : Method called\n", functionName); + *bytesWritten = 0; + + if (connected_ == 0){ + debugPrint("%s : FTDI not connected\n", functionName); + return FTDIDriverError; + } + + debugPrint("%s : Writing: bufferSize=%d", functionName, bufferSize); + if( spi ) debugPrint("\n"); // SPI data binary, no ASCII = don't print + else debugPrint(" buffer=%s\n", buffer); + timeval stime; + timeval ctime; + gettimeofday(&stime, NULL); + long mtimeout = (stime.tv_usec / 1000) + timeout; + long tnow = 0; + + // Set timeout value + ftdi_->usb_write_timeout = timeout; + +#ifdef HAS_LIBFTDI1 + struct ftdi_transfer_control *tc = ftdi_write_data_submit ( + ftdi_, (unsigned char *) buffer, (int) bufferSize + ); + rc[8] = ftdi_transfer_data_done (tc); +#else + if( spi ) { + if( !spiInit ) initSPI(); + i = 0; + pbuf = (unsigned char *)&buf[0]; + + memcpy((pbuf+i), buffer, bufferSize); + i+= bufferSize; + + debugPrint("Preamble+buffer:"); + for (size_t j = 0; j < i; j++) debugPrint("=[%02X] ", *(pbuf+j)); + debugPrint("\n"); + + flush(); + rc[3] = ftdi_write_data(ftdi_, pbuf, i); + if( rc[3] != i ) err = FTDIDriverError; + + } // if SPI - + else { + rc[7] = ftdi_write_data(ftdi_, (unsigned char *) buffer, (int) bufferSize); + if( rc[7] != i ) err = FTDIDriverError; + debugPrint("%s : 7. pinState=0x%02x\n", + functionName, pinState); + } +#endif + + gettimeofday(&ctime, NULL); + tnow = ((ctime.tv_sec - stime.tv_sec) * 1000) + (ctime.tv_usec / 1000); + debugPrint("%s : Time taken for write => %ld ms\n", functionName, (tnow-(mtimeout-timeout))); + if (rc[3] > 0){ + // Since we write also the address byte byteswritten = sz+1 + *bytesWritten = (size_t)(sz+1); + debugPrint("%s : %d bytes written err=%d: ", functionName, *bytesWritten, err); + if( err == FTDIDriverError ) debugPrint("FTDIDriverError\n"); + else debugPrint("FTDIDriverSUCCESS\n"); + } else { + debugPrint("FTDI write error: %d (%s)\n", rc, ftdi_get_error_string(ftdi_)); + *bytesWritten = 0; + return FTDIDriverError; + } + + return FTDIDriverSuccess; +} + +/** + * Read data from the connected channel. A timeout should be + * specified in milliseconds. The read method will continue to + * read data from the channel until either data arrives or the + * timeout is reached. + * + * @param buffer - A string buffer to hold the read data. + * @param bufferSize - The maximum number of bytes to read. + * @param bytesWritten - The number of bytes that have been read. + * @param timeout - A timeout in ms for the read. + * @return - Success or failure. + */ +FTDIDriverStatus FTDIDriver::read(unsigned char *buffer, size_t bufferSize, size_t *bytesRead, int timeout) +{ + static const char *functionName = "FTDIDriver::read"; + debugPrint("%s : Method called\n", functionName); + + if (connected_ == 0){ + debugPrint("%s : Not connected\n", functionName); + return FTDIDriverError; + } + + debugPrint("%s : Reading: bufferSize=%d, timeout=%d\n", functionName, bufferSize, timeout); + + timeval stime; + timeval ctime; + gettimeofday(&stime, NULL); + long mtimeout = (stime.tv_usec / 1000) + timeout; + long tnow = 0; + int rc = 0; + + *bytesRead = 0; + + if( spi ) ftdi_usb_purge_tx_buffer(ftdi_); + while ((*bytesRead == 0) && (tnow < mtimeout)) { + rc = ftdi_read_data (ftdi_, &buffer[*bytesRead], (bufferSize-*bytesRead)); + debugPrint("%s rc=%d\n", functionName, rc); + if (rc > 0) *bytesRead+=rc; + if (*bytesRead == 0) { + if( spi ) return FTDIDriverTimeout; + usleep(50); + gettimeofday(&ctime, NULL); + tnow = ((ctime.tv_sec - stime.tv_sec) * 1000) + (ctime.tv_usec / 1000); + } + } + + if (*bytesRead < bufferSize) + buffer[*bytesRead] = '\0'; + + debugPrint("%s %d Bytes =>\n", functionName, (int)*bytesRead); + for (int j = 0; j < (int)*bytesRead; j++){ + debugPrint("[%02X] ", buffer[j]); + } + debugPrint("\n"); + + gettimeofday(&ctime, NULL); + tnow = ((ctime.tv_sec - stime.tv_sec) * 1000) + (ctime.tv_usec / 1000); + debugPrint("%s : Time taken for read => %ld ms\n", functionName, (tnow-(mtimeout-timeout))); + + if ((timeout > 0) && (tnow >= mtimeout)){ + debugPrint("%s : TIMEOUT-\n", functionName); + return FTDIDriverTimeout; + } + debugPrint("%s : SUCCESS!\n", functionName); + return FTDIDriverSuccess; +} + + +/** + * Close the connection. + * + * @return - Success or failure. + */ +FTDIDriverStatus FTDIDriver::disconnectFTDI() +{ + static const char *functionName = "FTDIDriver::disconnect"; + debugPrint("%s : Method called\n", functionName); + + if (connected_ == 1){ + ftdi_usb_close(ftdi_); + ftdi_deinit(ftdi_); + connected_ = 0; + } + else { + debugPrint("%s : Connection was not established\n", functionName); + } + return FTDIDriverSuccess; +} + +/** + * Destructor, cleanup. + */ +FTDIDriver::~FTDIDriver() +{ + static const char *functionName = "FTDIDriver::~FTDIDriver"; + debugPrint("%s : Method called\n", functionName); +} + +#ifndef _MINGW +#ifdef _WIN32 +/* Windows implemenation of gettimeofday and usleep */ +#include < time.h > +#include < windows.h > + +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 +#else + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL +#endif + +struct timezone +{ + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; + unsigned __int64 tmpres = 0; + static int tzflag = 0; + + if (NULL != tv) + { + GetSystemTimeAsFileTime(&ft); + + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + + tmpres /= 10; /*convert into microseconds*/ + /*converting file time to unix epoch*/ + tmpres -= DELTA_EPOCH_IN_MICROSECS; + tv->tv_sec = (long)(tmpres / 1000000UL); + tv->tv_usec = (long)(tmpres % 1000000UL); + } + + if (NULL != tz) + { + if (!tzflag) + { + _tzset(); + tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + + return 0; +} + +void usleep(__int64 usec) +{ + HANDLE timer; + LARGE_INTEGER ft; + + ft.QuadPart = -(10*usec); // Convert to 100 nanosecond interval, negative value indicates relative time + + timer = CreateWaitableTimer(NULL, TRUE, NULL); + SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0); + WaitForSingleObject(timer, INFINITE); + CloseHandle(timer); +} +#endif +#endif diff --git a/asyn/drvAsynFTDI/ftdiDriver.h b/asyn/drvAsynFTDI/ftdiDriver.h new file mode 100644 index 0000000..fd1e661 --- /dev/null +++ b/asyn/drvAsynFTDI/ftdiDriver.h @@ -0,0 +1,118 @@ + +#ifndef ftdiDriver_H +#define ftdiDriver_H + +#ifdef HAVE_LIBFTDI1 +#include +#else +#include +#endif + +#include + +# ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +# include +#endif + +#include +#include +#include +#include +#include + +#define UART_SPI_BIT 0x01 // 0 = UART; 1 = SPI + +namespace Pin { + enum bus_t { + SK = 0x01, //SPI clock + DO = 0x02, //MOSI + DI = 0x04, //MISO + CS = 0x08, + IO_UPDATE= 0x10, + SYNCIO = 0x20, + RESET = 0x40 + }; +} + +namespace FTDImode { + enum mode { + UART = 0x00, + SPI = 0x01 + }; +} + +typedef enum e_FTDIDriverStatus +{ + FTDIDriverSuccess, + FTDIDriverTimeout, + FTDIDriverError +} FTDIDriverStatus; + +/** + * The FTDIDriver class provides a wrapper around the libftdi1 library. + * It simplifies creating FTDI connections and provides a simple read/write/flush + * interface. Setting up an FTDI chip USB connection can be configured with a + * Vendor ID, Product ID, baudrate & latency + * + * @author Philip Taylor (pbt@observatorysciences.co.uk) + */ +class FTDIDriver { + + public: + FTDIDriver(int spi = 0); // SPI = 0 => UART; SPI = 1 = SPI; + FTDIDriverStatus initSPI(); + FTDIDriverStatus setVPID(const int vendor, const int product); + FTDIDriverStatus setBaudrate(const int baudrate); + FTDIDriverStatus setBits(enum ftdi_bits_type bits); + FTDIDriverStatus setStopBits(enum ftdi_stopbits_type sbits); + FTDIDriverStatus setParity(enum ftdi_parity_type parity); + FTDIDriverStatus setBreak(enum ftdi_break_type brk); + FTDIDriverStatus setFlowControl(int flowctrl); + FTDIDriverStatus setLatency(const int latency); + FTDIDriverStatus setLineProperties(enum ftdi_bits_type bits, + enum ftdi_stopbits_type sbits, enum ftdi_parity_type parity, + enum ftdi_break_type brk); + int getBaudRate(void); + enum ftdi_bits_type getBits(void); + enum ftdi_stopbits_type getStopBits(void); + enum ftdi_parity_type getParity(void); + enum ftdi_break_type getBreak(void); + int getFlowControl(void); + FTDIDriverStatus connectFTDI(); + FTDIDriverStatus flush(); + FTDIDriverStatus write(const unsigned char *buffer, int bufferSize, size_t *bytesWritten, int timeout); + FTDIDriverStatus read(unsigned char *buffer, size_t bufferSize, size_t *bytesRead, int timeout); + FTDIDriverStatus disconnectFTDI(); + virtual ~FTDIDriver(); + + private: + struct ftdi_context *ftdi_; + + int spi; + int spiInit; + int buf[0x10000]; + unsigned char *pbuf; + + int connected_; + int vendor_; + int product_; + int baudrate_; + int pinState; + int pinDirection; + enum ftdi_bits_type bits_; + enum ftdi_stopbits_type sbits_; + enum ftdi_parity_type parity_; + enum ftdi_break_type break_; + int flowctrl_; + int latency_; + off_t got_; + +}; + + +#endif + + diff --git a/asyn/drvAsynSerial/drvAsynIPPort.c b/asyn/drvAsynSerial/drvAsynIPPort.c index 35da4cf..ff521f0 100644 --- a/asyn/drvAsynSerial/drvAsynIPPort.c +++ b/asyn/drvAsynSerial/drvAsynIPPort.c @@ -1,6 +1,6 @@ /********************************************************************** * Asyn device support using TCP stream or UDP datagram port * -**********************************************************************/ +**********************************************************************/ /*********************************************************************** * Copyright (c) 2002 The University of Chicago, as Operator of Argonne * National Laboratory, and the Regents of the University of @@ -29,7 +29,7 @@ * 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 + * 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. */ @@ -85,6 +85,11 @@ # endif #endif +/* If SO_REUSEPORT is not defined then use SO_REUSEADDR instead. + It is not defined on RTEMS, Windows and older Linux versions. */ +#ifndef SO_REUSEPORT +# define USE_SO_REUSEADDR +#endif /* This delay is needed in cleanup() else sockets are not always really closed cleanly */ #define CLOSE_SOCKET_DELAY 0.02 @@ -127,6 +132,7 @@ typedef struct { #define FLAG_BROADCAST 0x1 #define FLAG_CONNECT_PER_TRANSACTION 0x2 #define FLAG_SHUTDOWN 0x4 +#define FLAG_SO_REUSEPORT 0x8 #define FLAG_NEED_LOOKUP 0x100 #define FLAG_DONE_LOOKUP 0x200 @@ -156,7 +162,7 @@ static int poll(struct pollfd fds[], int nfds, int timeout) } else { ptv = NULL; } - return select(fds[0].fd + 1, + return select(fds[0].fd + 1, (fds[0].events & POLLIN) ? &fdset : NULL, (fds[0].events & POLLOUT) ? &fdset : NULL, NULL, @@ -226,7 +232,7 @@ asynCommonReport(void *drvPvt, FILE *fp, int details) tty->fd != INVALID_SOCKET ? "C" : "Disc"); } if (details >= 2) { - fprintf(fp, " fd: %d\n", tty->fd); + fprintf(fp, " fd: %d\n", (int)tty->fd); fprintf(fp, " Characters written: %lu\n", tty->nWritten); fprintf(fp, " Characters read: %lu\n", tty->nRead); } @@ -351,6 +357,10 @@ static int parseHostInfo(ttyController_t *tty, const char* hostInfo) || (epicsStrCaseCmp(protocol, "tcp") == 0)) { tty->socketType = SOCK_STREAM; } + else if (epicsStrCaseCmp(protocol, "tcp&") == 0) { + tty->socketType = SOCK_STREAM; + tty->flags |= FLAG_SO_REUSEPORT; + } else if (epicsStrCaseCmp(protocol, "com") == 0) { isCom = 1; tty->socketType = SOCK_STREAM; @@ -362,10 +372,19 @@ static int parseHostInfo(ttyController_t *tty, const char* hostInfo) else if (epicsStrCaseCmp(protocol, "udp") == 0) { tty->socketType = SOCK_DGRAM; } + else if (epicsStrCaseCmp(protocol, "udp&") == 0) { + tty->socketType = SOCK_DGRAM; + tty->flags |= FLAG_SO_REUSEPORT; + } else if (epicsStrCaseCmp(protocol, "udp*") == 0) { tty->socketType = SOCK_DGRAM; tty->flags |= FLAG_BROADCAST; } + else if (epicsStrCaseCmp(protocol, "udp*&") == 0) { + tty->socketType = SOCK_DGRAM; + tty->flags |= FLAG_BROADCAST; + tty->flags |= FLAG_SO_REUSEPORT; + } else { printf("%s: Unknown protocol \"%s\".\n", functionName, protocol); return -1; @@ -374,7 +393,7 @@ static int parseHostInfo(ttyController_t *tty, const char* hostInfo) if (tty->isCom == ISCOM_UNKNOWN) { tty->isCom = isCom; } else if (isCom != tty->isCom) { - printf("%s: Ignoring attempt to change COM flag to %d from %d\n", + printf("%s: Ignoring attempt to change COM flag to %d from %d\n", functionName, isCom, tty->isCom); } /* Successfully parsed socket information, turn off FLAG_SHUTDOWN */ @@ -391,6 +410,7 @@ connectIt(void *drvPvt, asynUser *pasynUser) ttyController_t *tty = (ttyController_t *)drvPvt; SOCKET fd; int i; + int sockOpt; /* * Sanity check @@ -438,6 +458,24 @@ connectIt(void *drvPvt, asynUser *pasynUser) return asynError; } + /* + * Enable SO_REUSEPORT if so requested + */ + i = 1; + #ifdef USE_SO_REUSEADDR + sockOpt = SO_REUSEADDR; + #else + sockOpt = SO_REUSEPORT; + #endif + if ((tty->flags & FLAG_SO_REUSEPORT) + && (setsockopt(fd, SOL_SOCKET, sockOpt, (void *)&i, sizeof i) < 0)) { + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "Can't set %s socket SO_REUSEPORT option: %s", + tty->IPDeviceName, strerror(SOCKERRNO)); + epicsSocketDestroy(fd); + return asynError; + } + /* * Convert host name/number to IP address. * We delay doing this until now in case a device @@ -453,7 +491,7 @@ connectIt(void *drvPvt, asynUser *pasynUser) tty->flags &= ~FLAG_NEED_LOOKUP; tty->flags |= FLAG_DONE_LOOKUP; } - + /* * Bind to the local IP address if it was specified. * This is a very unusual configuration @@ -605,7 +643,7 @@ static asynStatus writeIt(void *drvPvt, asynUser *pasynUser, return asynError; } epicsTimeGetCurrent(&endTime); - if (epicsTimeDiffInSeconds(&endTime, &startTime)*1000 > writePollmsec) break; + if (epicsTimeDiffInSeconds(&endTime, &startTime)*1000 > writePollmsec) break; } if (pollstatus == 0) { epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, @@ -730,7 +768,7 @@ static asynStatus readIt(void *drvPvt, asynUser *pasynUser, return asynError; } epicsTimeGetCurrent(&endTime); - if (epicsTimeDiffInSeconds(&endTime, &startTime)*1000. > readPollmsec) break; + if (epicsTimeDiffInSeconds(&endTime, &startTime)*1000. > readPollmsec) break; } } #endif @@ -744,7 +782,7 @@ static asynStatus readIt(void *drvPvt, asynUser *pasynUser, char inetBuff[32]; ipAddrToDottedIP(&oa.ia, inetBuff, sizeof(inetBuff)); asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, thisRead, - "%s (from %s) read %d\n", + "%s (from %s) read %d\n", tty->IPDeviceName, inetBuff, thisRead); } tty->nRead += (unsigned long)thisRead; @@ -838,6 +876,7 @@ ttyCleanup(ttyController_t *tty) epicsSocketDestroy(tty->fd); free(tty->portName); free(tty->IPDeviceName); + free(tty->IPHostName); free(tty); } } @@ -852,6 +891,7 @@ getOption(void *drvPvt, asynUser *pasynUser, ttyController_t *tty = (ttyController_t *)drvPvt; int l; + val[0] = '\0'; assert(tty); if (epicsStrCaseCmp(key, "disconnectOnReadTimeout") == 0) { l = epicsSnprintf(val, valSize, "%c", tty->disconnectOnReadTimeout ? 'Y' : 'N'); @@ -880,7 +920,7 @@ setOption(void *drvPvt, asynUser *pasynUser, const char *key, const char *val) assert(tty); asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s setOption key %s val %s\n", tty->portName, key, val); - + if (epicsStrCaseCmp(key, "disconnectOnReadTimeout") == 0) { if (epicsStrCaseCmp(val, "Y") == 0) { tty->disconnectOnReadTimeout = 1; @@ -919,7 +959,7 @@ static const struct asynCommon drvAsynIPPortAsynCommon = { /* * Configure and register the drvAsynIPPort driver */ -epicsShareFunc int +ASYN_API int drvAsynIPPortConfigure(const char *portName, const char *hostInfo, unsigned int priority, diff --git a/asyn/drvAsynSerial/drvAsynIPPort.h b/asyn/drvAsynSerial/drvAsynIPPort.h index 9ee0ed8..ae2a806 100644 --- a/asyn/drvAsynSerial/drvAsynIPPort.h +++ b/asyn/drvAsynSerial/drvAsynIPPort.h @@ -13,13 +13,13 @@ #ifndef DRVASYNIPPORT_H #define DRVASYNIPPORT_H -#include +#include "asynAPI.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -epicsShareFunc int drvAsynIPPortConfigure(const char *portName, +ASYN_API int drvAsynIPPortConfigure(const char *portName, const char *hostInfo, unsigned int priority, int noAutoConnect, diff --git a/asyn/drvAsynSerial/drvAsynIPServerPort.c b/asyn/drvAsynSerial/drvAsynIPServerPort.c index 633607e..de12359 100644 --- a/asyn/drvAsynSerial/drvAsynIPServerPort.c +++ b/asyn/drvAsynSerial/drvAsynIPServerPort.c @@ -57,6 +57,7 @@ typedef struct { unsigned int portNumber; char *portName; char *serverInfo; + char *interfaceInfo; int maxClients; int socketType; int priority; @@ -382,6 +383,7 @@ int createServerSocket(ttyController_t *tty) { int i; struct sockaddr_in serverAddr; int oneVal=1; + char srvaddrtxt[256]; assert(tty); /* * Create the socket @@ -395,6 +397,25 @@ int createServerSocket(ttyController_t *tty) { serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = INADDR_ANY; serverAddr.sin_port = htons(tty->portNumber); + + /* + * Got host or interface name, resolve it unless we see "localhost": + * This may be used in existing start scripts and we don't want to + * break them. If you need the loopback, use "127.0.0.1". + */ + if (tty->interfaceInfo != NULL && *tty->interfaceInfo && + epicsStrCaseCmp(tty->interfaceInfo, "localhost")) { + if (hostToIPAddr(tty->interfaceInfo, &serverAddr.sin_addr) < 0) { + printf("using ANY interface, cannot lookup '%s': %s\n", + tty->interfaceInfo, strerror(SOCKERRNO)); + return -1; + } + } + + if (ipAddrToDottedIP(&serverAddr, &srvaddrtxt[0], sizeof(srvaddrtxt)) > 0) { + srvaddrtxt[sizeof(srvaddrtxt) - 1] = '\0'; + printf("serverAddr: %s\n", srvaddrtxt); + } printf("serverPort: %i\n", tty->portNumber); if (tty->socketType == SOCK_DGRAM) { /* For Port reuse, multiple IOCs */ @@ -479,6 +500,8 @@ static void ttyCleanup(void *pPvt) epicsSocketDestroy(tty->fd); } free(tty->portName); + free(tty->serverInfo); + free(tty->interfaceInfo); free(tty); } @@ -551,6 +574,7 @@ int drvAsynIPServerPortConfigure(const char *portName, return -1; } *cp = '\0'; + tty->interfaceInfo = epicsStrDup(serverInfo); if ((protocol[0] == '\0') || (epicsStrCaseCmp(protocol, "tcp") == 0)) { diff --git a/asyn/drvAsynSerial/drvAsynIPServerPort.h b/asyn/drvAsynSerial/drvAsynIPServerPort.h index dd96de4..bc8d808 100644 --- a/asyn/drvAsynSerial/drvAsynIPServerPort.h +++ b/asyn/drvAsynSerial/drvAsynIPServerPort.h @@ -13,12 +13,14 @@ #ifndef DRVASYNIPSERVERPORT_H #define DRVASYNIPSERVERPORT_H +#include "asynAPI.h" + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -int drvAsynIPServerPortConfigure(const char *portName, const char *serverInfo, - unsigned int maxClients, unsigned int priority, +ASYN_API int drvAsynIPServerPortConfigure(const char *portName, const char *serverInfo, + unsigned int maxClients, unsigned int priority, int noAutoConnect, int noProcessEos); #ifdef __cplusplus diff --git a/asyn/drvAsynSerial/drvAsynSerialPort.c b/asyn/drvAsynSerial/drvAsynSerialPort.c index 0b0caf5..1ed6ab4 100644 --- a/asyn/drvAsynSerial/drvAsynSerialPort.c +++ b/asyn/drvAsynSerial/drvAsynSerialPort.c @@ -1,6 +1,6 @@ /********************************************************************** * Asyn device support using local serial interface * -**********************************************************************/ +**********************************************************************/ /*********************************************************************** * Copyright (c) 2002 The University of Chicago, as Operator of Argonne * National Laboratory, and the Regents of the University of @@ -117,7 +117,7 @@ applyOptions(asynUser *pasynUser, ttyController_t *tty) return asynError; } #else - + tty->termios.c_cflag |= CREAD; if (tcsetattr(tty->fd, TCSANOW, &tty->termios) < 0) { epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, @@ -139,6 +139,7 @@ getOption(void *drvPvt, asynUser *pasynUser, ttyController_t *tty = (ttyController_t *)drvPvt; int l; + val[0] = '\0'; if (epicsStrCaseCmp(key, "baud") == 0) { l = epicsSnprintf(val, valSize, "%d", tty->baud); } @@ -243,8 +244,8 @@ setOption(void *drvPvt, asynUser *pasynUser, const char *key, const char *val) assert(tty); asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s setOption key %s val %s\n", tty->portName, key, val); - - /* Make a copy of tty->termios and tty->baud so we can restore them in case of errors */ + + /* Make a copy of tty->termios and tty->baud so we can restore them in case of errors */ termiosPrev = tty->termios; baudPrev = tty->baud; #ifdef ASYN_RS485_SUPPORTED @@ -258,10 +259,10 @@ setOption(void *drvPvt, asynUser *pasynUser, const char *key, const char *val) "Bad number"); return asynError; } -#ifndef vxWorks +#ifndef vxWorks { speed_t baudCode; -/* On this system is the baud code the actual baud rate? +/* On this system is the baud code the actual baud rate? * If so use it directly, else compare against known baud codes */ #if (defined(B300) && (B300 == 300) && defined(B9600) && (B9600 == 9600)) baudCode = baud; @@ -462,7 +463,7 @@ setOption(void *drvPvt, asynUser *pasynUser, const char *key, const char *val) #ifdef vxWorks epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Option ixany not supported on vxWorks"); - return asynError; + return asynError; #else if (epicsStrCaseCmp(val, "Y") == 0) { tty->termios.c_iflag |= IXANY; @@ -481,7 +482,7 @@ setOption(void *drvPvt, asynUser *pasynUser, const char *key, const char *val) #ifdef vxWorks epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Option ixoff not supported on vxWorks"); - return asynError; + return asynError; #else if (epicsStrCaseCmp(val, "Y") == 0) { tty->termios.c_iflag |= IXOFF; @@ -690,7 +691,7 @@ connectIt(void *drvPvt, asynUser *pasynUser) } #endif applyOptions(pasynUser, tty); - + /* * Turn off non-blocking mode */ @@ -876,7 +877,7 @@ static asynStatus readIt(void *drvPvt, asynUser *pasynUser, tty->termios.c_cc[VMIN] = 1; tty->termios.c_cc[VTIME] = 0; } - + if (tcsetattr(tty->fd, TCSANOW, &tty->termios) < 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Can't set \"%s\" c_cc[VTIME]: %s", @@ -998,7 +999,7 @@ static const struct asynCommon asynCommonMethods = { /* * Configure and register a generic serial device */ -epicsShareFunc int +ASYN_API int drvAsynSerialPortConfigure(char *portName, char *ttyName, unsigned int priority, diff --git a/asyn/drvAsynSerial/drvAsynSerialPort.h b/asyn/drvAsynSerial/drvAsynSerialPort.h index 7a3a5b9..04f8e30 100644 --- a/asyn/drvAsynSerial/drvAsynSerialPort.h +++ b/asyn/drvAsynSerial/drvAsynSerialPort.h @@ -13,7 +13,7 @@ #ifndef DRVASYNLOCALSERIALPORT_H #define DRVASYNLOCALSERIALPORT_H -#include +#include "asynAPI.h" #ifdef __cplusplus extern "C" { @@ -23,7 +23,7 @@ extern "C" { #define ASYN_ERROR_PARITY 0x0001 #define ASYN_ERROR_FRAMING 0x0002 -epicsShareFunc int drvAsynSerialPortConfigure(char *portName, +ASYN_API int drvAsynSerialPortConfigure(char *portName, char *ttyName, unsigned int priority, int noAutoConnect, diff --git a/asyn/drvAsynSerial/drvAsynSerialPortWin32.c b/asyn/drvAsynSerial/drvAsynSerialPortWin32.c index 0bbea87..2ffbf15 100644 --- a/asyn/drvAsynSerial/drvAsynSerialPortWin32.c +++ b/asyn/drvAsynSerial/drvAsynSerialPortWin32.c @@ -3,7 +3,7 @@ * * Mark Rivers * July 26, 2011 -**********************************************************************/ +**********************************************************************/ /*********************************************************************** * Copyright (c) 2002 The University of Chicago, as Operator of Argonne * National Laboratory, and the Regents of the University of @@ -90,7 +90,8 @@ getOption(void *drvPvt, asynUser *pasynUser, BOOL ret; DWORD error; int l; - + + val[0] = '\0'; assert(tty); if (tty->commHandle == INVALID_HANDLE_VALUE) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, @@ -278,7 +279,7 @@ setOption(void *drvPvt, asynUser *pasynUser, const char *key, const char *val) else if (epicsStrCaseCmp(key, "ixany") == 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Option ixany not supported on Windows"); - return asynError; + return asynError; } else if (epicsStrCaseCmp(key, "ixoff") == 0) { if (epicsStrCaseCmp(val, "Y") == 0) { @@ -351,7 +352,7 @@ report(void *drvPvt, FILE *fp, int details) tty->serialDeviceName, tty->commHandle != INVALID_HANDLE_VALUE ? "C" : "Disc"); if (details >= 1) { - fprintf(fp, " commHandle: %d\n", tty->commHandle); + fprintf(fp, " commHandle: %p\n", tty->commHandle); fprintf(fp, " Characters written: %lu\n", tty->nWritten); fprintf(fp, " Characters read: %lu\n", tty->nRead); } @@ -398,7 +399,7 @@ connectIt(void *drvPvt, asynUser *pasynUser) } /* setOption(tty, tty->pasynUser, "baud", "9600"); */ - + /* * Turn off non-blocking mode */ @@ -531,19 +532,19 @@ static asynStatus readIt(void *drvPvt, asynUser *pasynUser, if (tty->readTimeout != pasynUser->timeout) { if (pasynUser->timeout >= 0) { if (pasynUser->timeout == 0) { - ctimeout.ReadIntervalTimeout = MAXDWORD; - ctimeout.ReadTotalTimeoutMultiplier = 0; - ctimeout.ReadTotalTimeoutConstant = 0; - ctimeout.WriteTotalTimeoutMultiplier = 0; + ctimeout.ReadIntervalTimeout = MAXDWORD; + ctimeout.ReadTotalTimeoutMultiplier = 0; + ctimeout.ReadTotalTimeoutConstant = 0; + ctimeout.WriteTotalTimeoutMultiplier = 0; ctimeout.WriteTotalTimeoutConstant = 0; } else { - ctimeout.ReadIntervalTimeout = (int)(pasynUser->timeout*1000.); - ctimeout.ReadTotalTimeoutMultiplier = 1; - ctimeout.ReadTotalTimeoutConstant = (int)(pasynUser->timeout*1000.); - ctimeout.WriteTotalTimeoutMultiplier = 1; + ctimeout.ReadIntervalTimeout = (int)(pasynUser->timeout*1000.); + ctimeout.ReadTotalTimeoutMultiplier = 1; + ctimeout.ReadTotalTimeoutConstant = (int)(pasynUser->timeout*1000.); + ctimeout.WriteTotalTimeoutMultiplier = 1; ctimeout.WriteTotalTimeoutConstant = (int)(pasynUser->timeout*1000.); - } + } ret = SetCommTimeouts(tty->commHandle, &ctimeout); if (ret == 0) { @@ -665,7 +666,7 @@ static const struct asynCommon asynCommonMethods = { /* * Configure and register a generic serial device */ -epicsShareFunc int +ASYN_API int drvAsynSerialPortConfigure(char *portName, char *ttyName, unsigned int priority, @@ -706,14 +707,14 @@ drvAsynSerialPortConfigure(char *portName, } tty->commHandle = INVALID_HANDLE_VALUE; if ( (epicsStrnCaseCmp(ttyName, "\\\\.\\", 4) != 0)) { - /* + /* * The user did not pass a Windows device name, so prepend \\.\ */ epicsSnprintf(winTtyName, sizeof(winTtyName), "\\\\.\\%s", ttyName); - } + } else { strncpy(winTtyName, ttyName, sizeof(winTtyName)); - } + } tty->serialDeviceName = epicsStrDup(winTtyName); tty->portName = epicsStrDup(portName); diff --git a/asyn/drvAsynSerial/os/Linux/serial_rs485.h b/asyn/drvAsynSerial/os/Linux/serial_rs485.h index f0bf025..edc7489 100644 --- a/asyn/drvAsynSerial/os/Linux/serial_rs485.h +++ b/asyn/drvAsynSerial/os/Linux/serial_rs485.h @@ -6,7 +6,7 @@ #include -/* Older Linux systems don't support RS485. +/* Older Linux systems don't support RS485. * The features we need were introduced in 2.6.35 */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) #define ASYN_RS485_SUPPORTED 1 diff --git a/asyn/drvAsynUSBTMC/drvAsynUSBTMC.c b/asyn/drvAsynUSBTMC/drvAsynUSBTMC.c old mode 100644 new mode 100755 index fca9f56..e6c8d0f --- a/asyn/drvAsynUSBTMC/drvAsynUSBTMC.c +++ b/asyn/drvAsynUSBTMC/drvAsynUSBTMC.c @@ -32,16 +32,19 @@ #define MESSAGE_ID_REQUEST_DEV_DEP_MSG_IN 2 #define MESSAGE_ID_DEV_DEP_MSG_IN 2 -#define BULK_IO_HEADER_SIZE 12 -#define BULK_IO_PAYLOAD_CAPACITY 4096 -#define IDSTRING_CAPACITY 100 +#define BULK_IO_HEADER_SIZE 12 +#define BULK_IO_PAYLOAD_CAPACITY (1024*1024) +#define BULK_IO_OUTPUT_EOS_CAPACITY 2 +#define IDSTRING_CAPACITY 100 #define ASYN_REASON_SRQ 4345 #define ASYN_REASON_STB 4346 #define ASYN_REASON_REN 4347 +#define ASYN_REASON_GTL 4348 +#define ASYN_REASON_LLO 4349 #if (!defined(LIBUSBX_API_VERSION) || (LIBUSBX_API_VERSION < 0x01000102)) -# error "You need to get a newer version of libsb-1.0 (16 at the very least)" +# error "You need to get a newer version of libusb-1.0 (16 at the very least)" #endif typedef struct drvPvt { @@ -107,11 +110,19 @@ typedef struct drvPvt { /* * I/O buffer */ - unsigned char buf[BULK_IO_HEADER_SIZE+BULK_IO_PAYLOAD_CAPACITY]; + unsigned char buf[BULK_IO_HEADER_SIZE + + BULK_IO_PAYLOAD_CAPACITY + + BULK_IO_OUTPUT_EOS_CAPACITY]; int bufCount; const unsigned char *bufp; unsigned char bulkInPacketFlags; + /* + * Output EOS + */ + int outputEOSlen; + unsigned char outputEOS[BULK_IO_OUTPUT_EOS_CAPACITY]; + /* * Statistics */ @@ -250,7 +261,7 @@ pcomma(FILE *fp, size_t n) pcomma(fp, n/1000); fprintf(fp, ",%03zu", n%1000); } - + static void showCount(FILE *fp, const char *label, size_t count) { @@ -282,7 +293,15 @@ report(void *pvt, FILE *fp, int details) default: fprintf(fp, "\n"); break; } if (pdpvt->termChar >= 0) - fprintf(fp, "%28s: %x\n", "Terminator", pdpvt->termChar); + fprintf(fp, "%28s: %02X\n", "Input terminator", pdpvt->termChar); + if (pdpvt->outputEOSlen > 0) { + int i; + fprintf(fp, "%28s:", "Output terminator"); + for (i = 0 ; i < pdpvt->outputEOSlen ; i++) { + fprintf(fp, " %02X", pdpvt->outputEOS[i]); + } + fprintf(fp, "\n"); + } showHexval(fp, "TMC Interface Capabilities", pdpvt->tmcInterfaceCapabilities, 0x4, "Accepts INDICATOR_PULSE", @@ -292,7 +311,7 @@ report(void *pvt, FILE *fp, int details) 0); showHexval(fp, "TMC Device Capabilities", pdpvt->tmcDeviceCapabilities, - 0x1, "Supports termChar", + 0x1, "Supports bulk-IN terminator", 0); if (pdpvt->bInterfaceProtocol == 1) { showHexval(fp, "488 Interface Capabilities", @@ -325,7 +344,7 @@ report(void *pvt, FILE *fp, int details) if (details >= 100) { int l = details % 100; fprintf(fp, "==== Set libusb debug level %d ====\n", l); - libusb_set_debug(pdpvt->usb, l); + libusb_set_option(pdpvt->usb, LIBUSB_OPTION_LOG_LEVEL, l); } } @@ -628,15 +647,19 @@ connect(void *pvt, asynUser *pasynUser) return asynError; } if (getCapabilities(pdpvt, pasynUser) != asynSuccess) { + char *msg = epicsStrDup(pasynUser->errorMessage); libusb_close(pdpvt->handle); epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Can't get device capabilities: %s", pasynUser->errorMessage); + "Can't get device capabilities: %s", msg); + free(msg); return asynError; } if (clearBuffers(pdpvt, pasynUser) != asynSuccess) { + char *msg = epicsStrDup(pasynUser->errorMessage); libusb_close(pdpvt->handle); epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Can't clear buffers: %s", pasynUser->errorMessage); + "Can't clear buffers: %s", msg); + free(msg); return asynError; } pdpvt->bulkInPacketFlags = 0; @@ -729,6 +752,11 @@ asynOctetWrite(void *pvt, asynUser *pasynUser, else { nSend = numchars; pdpvt->buf[8] = 1; + if (pdpvt->outputEOSlen) { + memcpy(&pdpvt->buf[BULK_IO_HEADER_SIZE + nSend], + pdpvt->outputEOS, pdpvt->outputEOSlen); + nSend += pdpvt->outputEOSlen; + } } pdpvt->buf[1] = pdpvt->bTag; pdpvt->buf[2] = ~pdpvt->bTag; @@ -756,6 +784,9 @@ asynOctetWrite(void *pvt, asynUser *pasynUser, "Asked to send %d, actually sent %d", pkSend, pkSent); return asynError; } + if (pdpvt->buf[8] & 0x1) { + nSend -= pdpvt->outputEOSlen; + } data += nSend; numchars -= nSend; *nbytesTransfered += nSend; @@ -936,14 +967,14 @@ asynOctetSetInputEos(void *pvt, asynUser *pasynUser, const char *eos, int eoslen case 1: if ((pdpvt->tmcDeviceCapabilities & 0x1) == 0) { epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Device does not support terminating characters"); + "Device does not support bulk-IN terminating character"); return asynError; } pdpvt->termChar = *eos & 0xFF; break; default: epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Device does not support multiple terminating characters"); + "USBTMC does not support multiple input terminating characters"); return asynError; } return asynSuccess; @@ -968,18 +999,33 @@ asynOctetGetInputEos(void *pvt, asynUser *pasynUser, char *eos, int eossize, int static asynStatus asynOctetSetOutputEos(void *pvt, asynUser *pasynUser, const char *eos, int eoslen) { - return asynError; + drvPvt *pdpvt = (drvPvt *)pvt; + if (eoslen > BULK_IO_OUTPUT_EOS_CAPACITY) { + return asynError; + } + if (eoslen < 0) { + eoslen = 0; + } + memcpy(pdpvt->outputEOS, eos, eoslen); + pdpvt->outputEOSlen = eoslen; + return asynSuccess; } static asynStatus asynOctetGetOutputEos(void *pvt, asynUser *pasynUser, char *eos, int eossize, int *eoslen) { - return asynError; + drvPvt *pdpvt = (drvPvt *)pvt; + if (eossize < pdpvt->outputEOSlen) { + return asynError; + } + memcpy(eos, pdpvt->outputEOS, pdpvt->outputEOSlen); + *eoslen = pdpvt->outputEOSlen; + return asynSuccess; } -static asynOctet octetMethods = { - .write = asynOctetWrite, - .read = asynOctetRead, +static asynOctet octetMethods = { + .write = asynOctetWrite, + .read = asynOctetRead, .flush = asynOctetFlush, .setInputEos = asynOctetSetInputEos, .getInputEos = asynOctetGetInputEos, @@ -995,35 +1041,33 @@ asynInt32Write(void *pvt, asynUser *pasynUser, epicsInt32 value) { drvPvt *pdpvt = (drvPvt *)pvt; int s; - asynStatus status; unsigned char cbuf[1]; + int bRequest, wValue; + const char *msg = NULL; switch (pasynUser->reason) { - case ASYN_REASON_REN: - if ((pdpvt->usb488InterfaceCapabilities & 0x2) == 0) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "Device does not support REN operations."); - return asynError; - } - s = libusb_control_transfer(pdpvt->handle, - 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE - 160, // bRequest: USBTMC REN_CONTROL - (value != 0), // wValue - pdpvt->bInterfaceNumber, // wIndex - cbuf, // data - 1, // wLength - 100); // timeout (ms) - status = checkControlTransfer("REN_CONTROL", pdpvt, pasynUser, - s, 1, cbuf[0]); - if (status != asynSuccess) - return status; - return asynSuccess; - + case ASYN_REASON_REN: msg="REN"; bRequest=160; wValue=(value!=0); break; + case ASYN_REASON_GTL: msg="GTL"; bRequest=161; wValue=0; break; + case ASYN_REASON_LLO: msg="LLO"; bRequest=162; wValue=0; break; default: epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "asynInt32Write -- invalid drvUser (reason) %d", pasynUser->reason); return asynError; } + if ((pdpvt->usb488InterfaceCapabilities & 0x2) == 0) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Device does not support REN operations."); + return asynError; + } + s = libusb_control_transfer(pdpvt->handle, + 0xA1, // bmRequestType: Dir=IN, Type=CLASS, Recipient=INTERFACE + bRequest, + wValue, + pdpvt->bInterfaceNumber, // wIndex + cbuf, // data + 1, // wLength + 100); // timeout (ms) + return checkControlTransfer(msg, pdpvt, pasynUser, s, 1, cbuf[0]); } static asynStatus @@ -1136,6 +1180,12 @@ asynDrvUserCreate(void *pvt, asynUser *pasynUser, else if (epicsStrCaseCmp(drvInfo, "REN") == 0) { pasynUser->reason = ASYN_REASON_REN; } + else if (epicsStrCaseCmp(drvInfo, "GTL") == 0) { + pasynUser->reason = ASYN_REASON_GTL; + } + else if (epicsStrCaseCmp(drvInfo, "LLO") == 0) { + pasynUser->reason = ASYN_REASON_LLO; + } else if (epicsStrCaseCmp(drvInfo, "STB") == 0) { pasynUser->reason = ASYN_REASON_STB; } diff --git a/asyn/drvPrologixGPIB/drvPrologixGPIB.c b/asyn/drvPrologixGPIB/drvPrologixGPIB.c new file mode 100644 index 0000000..ee36853 --- /dev/null +++ b/asyn/drvPrologixGPIB/drvPrologixGPIB.c @@ -0,0 +1,628 @@ +/* + * Prologic Ethernet/GPIB driver + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Driver private storage + */ +typedef struct dPvt { + char *portName; + void *asynGpibPvt; + + /* + * Link to lower-level driver + */ + char *hostTCP; + char *portNameTCP; + asynUser *pasynUserTCPcommon; + asynUser *pasynUserTCPoctet; + int isConnected; + int autoConnect; + + /* + * Input/Output staging buffer + */ + char *buf; + size_t bufCapacity; + size_t bufCount; + size_t bufIndex; + + /* + * Miscellaneous + */ + char versionString[200]; + int lastAddress; + int lastPrimaryAddress; + int lastSecondaryAddress; + int eos; +} dPvt; + +#define EOT_MARKER 0xEF + +/* + * Set the address of the device to which we wish to communicate. + * Uses buf. + */ +static asynStatus +setAddress(dPvt *pdpvt, asynUser *pasynUser) +{ + int address, primary, secondary; + size_t n, nt; + asynStatus status; + + if ((status = pasynManager->getAddr(pasynUser, &address)) != asynSuccess) + return status; + if (address < 100) { + primary = address; + secondary = -1; + } else { + primary = address / 100; + secondary = address % 100; + if ((secondary < 0) || (secondary >= 31)) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Invalid GPIB secondary address %d", secondary); + return asynError; + } + } + if ((primary < 0) || (primary >= 31)) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Invalid GPIB primary address %d", primary); + return asynError; + } + if ((primary == pdpvt->lastPrimaryAddress) + && (secondary == pdpvt->lastSecondaryAddress)) + return asynSuccess; + if (secondary < 0) + n = epicsSnprintf(pdpvt->buf, pdpvt->bufCapacity, "++addr %d\n", primary); + else + n = epicsSnprintf(pdpvt->buf, pdpvt->bufCapacity, "++addr %d %d\n", primary, secondary + 96); + status = pasynOctetSyncIO->write(pdpvt->pasynUserTCPoctet, pdpvt->buf, + n, 1.0, &nt); + if (status != asynSuccess) { + pdpvt->lastPrimaryAddress = -1; + pdpvt->lastSecondaryAddress = -1; + return status; + } + pdpvt->lastPrimaryAddress = primary; + pdpvt->lastSecondaryAddress = secondary; + pdpvt->lastAddress = address; + return asynSuccess; +} + +/* + * Get more space for I/O buffer + */ +static asynStatus +resizeBuffer(dPvt *pdpvt, asynUser *pasynUser, size_t size) +{ + char *np; + size_t newCapacity = size + 4096; + + if ((size <= pdpvt->bufCapacity) + || (newCapacity <= pdpvt->bufCapacity) + || ((np = realloc(pdpvt->buf, newCapacity)) == NULL)) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Can't allocate memory for output buffer"); + return asynError; + } + pdpvt->buf = np; + pdpvt->bufCapacity = size + newCapacity; + return asynSuccess; +} + +/* + * Place a character into output buffer + * Escape special characters + */ +static asynStatus +stashChar(dPvt *pdpvt, asynUser *pasynUser, int c) +{ + if (pdpvt->bufCount >= (pdpvt->bufCapacity - 3)) { + if (resizeBuffer(pdpvt, pasynUser, pdpvt->bufCapacity) != asynSuccess) + return asynError; + } + switch (c) { + case '\r': + case '\n': + case '\033': + case '+': + pdpvt->buf[pdpvt->bufCount++] = '\033'; + break; + } + pdpvt->buf[pdpvt->bufCount++] = c; + return asynSuccess; +} + +static void +prologixReport(void *drvPvt, FILE *fd, int details) +{ + dPvt *pdpvt = (dPvt *)drvPvt; + + fprintf(fd, " Version: %s\n", pdpvt->versionString); +} + +static asynStatus +prologixConnect(void *drvPvt, asynUser *pasynUser) +{ + dPvt *pdpvt = (dPvt *)drvPvt; + size_t n, nt; + int address; + asynStatus status; + char *cp; + int eom; + + pdpvt->lastPrimaryAddress = -1; + pdpvt->lastSecondaryAddress = -1; + pdpvt->bufCount = 0; + if ((status = pasynManager->getAddr(pasynUser, &address)) != asynSuccess) + return status; + if (address < 0) { + status = pasynCommonSyncIO->connectDevice(pdpvt->pasynUserTCPcommon); + if (status != asynSuccess) + return status; + n = epicsSnprintf(pdpvt->buf, pdpvt->bufCapacity, + "++savecfg 0\n" /* Don't save changes in EEPROM */ + "++mode 1\n" /* We are controller */ + "++ifc\n" /* Clear the bus */ + "++eos 3\n" /* Handle EOS ourselves */ + "++eoi 1\n" /* Generate EOI on output */ + "++eot_char %d\n" /* Mark EOT on input */ + "++eot_enable 1\n" + "++ver\n" /* Request version information */ + , EOT_MARKER + ); + status = pasynOctetSyncIO->write(pdpvt->pasynUserTCPoctet, pdpvt->buf, + n, 1.0, &nt); + if (status != asynSuccess) + return status; + cp = pdpvt->versionString; + n = sizeof pdpvt->versionString; + for (;;) { + status = pasynOctetSyncIO->read(pdpvt->pasynUserTCPoctet, cp, n, 0.5, + &nt, &eom); + if (status != asynSuccess) + return status; + n -= nt; + if (n == 0) { + epicsSnprintf(pasynUser->errorMessage, + pasynUser->errorMessageSize, + "Version string too long"); + return asynError; + } + cp += nt; + if ((n <= (sizeof pdpvt->versionString - 2)) + && (cp[-2] == '\r') + && (cp[-1] == '\n')) { + cp[-2] = '\0'; + break; + } + } + } + pasynManager->exceptionConnect(pasynUser); + return asynSuccess; +} + +static asynStatus +prologixDisconnect(void *drvPvt, asynUser *pasynUser) +{ + dPvt *pdpvt = (dPvt *)drvPvt; + int address; + asynStatus status; + + if ((status = pasynManager->getAddr(pasynUser, &address)) != asynSuccess) + return status; + if (address < 0) { + status = pasynCommonSyncIO->disconnectDevice(pdpvt->pasynUserTCPcommon); + if (status != asynSuccess) + return status; + } + pasynManager->exceptionDisconnect(pasynUser); + return asynSuccess; +} + +/* + * Read from a GPIB device. + */ +static asynStatus +prologixRead(void *drvPvt, asynUser *pasynUser, + char *data, int maxchars, int *nbytesTransfered, int *eomReason) +{ + dPvt *pdpvt = (dPvt *)drvPvt; + size_t n; + int eom; + + /* + * Get entire reply on first invocation of this method following + * a write, flush or connect. + */ + if (pdpvt->bufCount == 0) { + char *cp = pdpvt->buf; + size_t nt; + double timeout = pasynUser->timeout; + asynStatus status; + int atEOT = 0; + int terminator = (pdpvt->eos >= 0) ? pdpvt->eos : EOT_MARKER; + + /* + * Address the device + */ + if ((status = setAddress(pdpvt, pasynUser)) != asynSuccess) + return status; + + /* + * Read + */ + if (pdpvt->eos >= 0) + n = epicsSnprintf(pdpvt->buf, pdpvt->bufCapacity, "++read %d\n", pdpvt->eos); + else + n = epicsSnprintf(pdpvt->buf, pdpvt->bufCapacity, "++read eoi\n"); + status = pasynOctetSyncIO->write(pdpvt->pasynUserTCPoctet, pdpvt->buf, + n, 1.0, &nt); + if (status != asynSuccess) + return status; + + /* + * Read until we see the appropriate terminator + */ + *nbytesTransfered = 0; + for (;;) { + /* + * Ensure that there's space for the read + */ + for (;;) { + n = pdpvt->bufCapacity - pdpvt->bufCount; + if (n) + break; + if (resizeBuffer(pdpvt, pasynUser, pdpvt->bufCapacity + 16384) != asynSuccess) { + pdpvt->bufCount = 0; + return asynError; + } + } + + /* + * Read a chunk + */ + status = pasynOctetSyncIO->read(pdpvt->pasynUserTCPoctet, cp, n, + timeout, &nt, &eom); + if (atEOT && (status == asynTimeout)) + break; + if (status != asynSuccess) + return status; + pdpvt->bufCount += nt; + cp += nt; + n -= nt; + + /* + * See if we've received the terminator + */ + if ((nt >= 1) && ((cp[-1] & 0xFF) == terminator)) { + /* + * If there's no EOS character we might be in binary mode and + * the EOT marker at the end of the buffer might actually + * be part of the data stream. + * The only way to determine if we're really at the end of + * the message is to try another read and see if times out. + * + * Yuck. + */ + if (pdpvt->eos >= 0) + break; + timeout = 0.005; + atEOT = 1; + } + else { + timeout = pasynUser->timeout; + atEOT = 0; + } + } + if (pdpvt->eos < 0) + pdpvt->bufCount--; /* Drop EOT marker */ + pdpvt->bufIndex = 0; + } + eom = 0; + n = pdpvt->bufCount - pdpvt->bufIndex; + if (maxchars >= n) { + if (pdpvt->eos >= 0) + eom |= ASYN_EOM_EOS; + else + eom |= ASYN_EOM_END; + } + if (n >= maxchars) { + n = maxchars; + eom |= ASYN_EOM_CNT; + } + memcpy(data, pdpvt->buf + pdpvt->bufIndex, n); + pdpvt->bufIndex += n; + if (eomReason) *eomReason = eom; + *nbytesTransfered = n; + asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, n, + "%s %d prologixRead %d EOM:%#x\n", + pdpvt->portName, pdpvt->lastAddress, (int)n, eom); + return asynSuccess; +} + +static asynStatus +prologixWrite(void *drvPvt, asynUser *pasynUser, + const char *data, int numchars, int *nbytesTransfered) +{ + dPvt *pdpvt = (dPvt *)drvPvt; + size_t n, nt; + asynStatus status; + + /* + * Check for output buffer space. + * Escape stuffing may make this bigger, but at least this gets us close. + */ + if (numchars >= pdpvt->bufCapacity) { + if (resizeBuffer(pdpvt, pasynUser, numchars) != asynSuccess) + return asynError; + } + + /* + * Address the device + */ + if ((status = setAddress(pdpvt, pasynUser)) != asynSuccess) + return status; + + /* + * Create command string + */ + asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, numchars, + "%s %d prologixWrite\n", pdpvt->portName, pdpvt->lastAddress); + *nbytesTransfered = 0; + n = numchars; + pdpvt->bufCount = 0; + while (n) { + if ((status = stashChar(pdpvt, pasynUser, *data++)) != asynSuccess) { + pdpvt->bufCount = 0; + return status; + } + n--; + } + if (pdpvt->eos >= 0) { + if ((status = stashChar(pdpvt, pasynUser, pdpvt->eos)) != asynSuccess) { + pdpvt->bufCount = 0; + return status; + } + } + pdpvt->buf[pdpvt->bufCount++] = '\n'; + + /* + * Send the command + */ + status = pasynOctetSyncIO->write(pdpvt->pasynUserTCPoctet, pdpvt->buf, + pdpvt->bufCount, pasynUser->timeout, &nt); + if (status == asynSuccess) + *nbytesTransfered = numchars; + pdpvt->bufCount = 0; + return status; +} + +static asynStatus +prologixFlush(void *drvPvt, asynUser *pasynUser) +{ + dPvt *pdpvt = (dPvt *)drvPvt; + + pdpvt->bufCount = 0; + return pasynOctetSyncIO->flush(pdpvt->pasynUserTCPoctet); +} + +static asynStatus +prologixGetEos(void *drvPvt, asynUser *pasynUser, + char *eos, int eossize, int *eoslen) +{ + dPvt *pdpvt = (dPvt *)drvPvt; + + if (pdpvt->eos < 0) { + *eoslen = 0; + } + else { + *eoslen = 1; + if (eossize > 0) + *eos = pdpvt->eos; + } + return asynSuccess; +} + +static asynStatus +prologixSetEos(void *drvPvt, asynUser *pasynUser, const char *eos, int eoslen) +{ + dPvt *pdpvt = (dPvt *)drvPvt; + int newEos; + size_t n, nt; + + switch (eoslen) { + case 0: newEos = -1; break; + case 1: newEos = *eos & 0xFF; break; + default: + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Invalid EOS"); + return asynError; + } + if (pdpvt->eos == newEos) + return asynSuccess; + n = epicsSnprintf(pdpvt->buf, pdpvt->bufCapacity, "++eot_enable %d\n", + (pdpvt->eos < 0)); + return pasynOctetSyncIO->write(pdpvt->pasynUserTCPoctet, pdpvt->buf, n, 1.0, &nt); +} + +static asynStatus +prologixAddressedCmd(void *drvPvt, asynUser *pasynUser, + const char *data, int length) +{ + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "prologixAddressedCmd unimplemented"); + return asynError; +} + +static asynStatus +prologixUniversalCmd(void *drvPvt, asynUser *pasynUser, int cmd) +{ + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "prologixUniversalCmd unimplemented"); + return asynError; +} + +static asynStatus +prologixIfc(void *drvPvt, asynUser *pasynUser) +{ + dPvt *pdpvt = (dPvt *)drvPvt; + size_t n, nt; + + n = epicsSnprintf(pdpvt->buf, pdpvt->bufCapacity, "++ifc\n"); + return pasynOctetSyncIO->write(pdpvt->pasynUserTCPoctet, pdpvt->buf, n, 1.0, &nt); +} + +static asynStatus +prologixRen(void *drvPvt, asynUser *pasynUser, int onOff) +{ + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "prologixRen unimplemented"); + return asynError; +} + +static asynStatus +prologixSrqStatus(void *drvPvt, int *srqStatus) +{ + *srqStatus = 0; + return asynSuccess; +} + +static asynStatus +prologixSrqEnable(void *drvPvt, int onOff) +{ + return asynSuccess; +} + +static asynStatus +prologixSerialPollBegin(void *drvPvt) +{ + printf ("=== prologixSerialPollBegin unimplemented\n"); + return asynError; +} + +static asynStatus +prologixSerialPoll(void *drvPvt, int addr, double timeout, int *statusByte) +{ + printf ("=== prologixSerialPoll unimplemented\n"); + return asynError; +} + +static asynStatus +prologixSerialPollEnd(void *drvPvt) +{ + printf ("=== prologixSerialPollEnd unimplemented\n"); + return asynError; +} + +static asynGpibPort prologixMethods = { + prologixReport, + prologixConnect, + prologixDisconnect, + prologixRead, + prologixWrite, + prologixFlush, + prologixSetEos, + prologixGetEos, + prologixAddressedCmd, + prologixUniversalCmd, + prologixIfc, + prologixRen, + prologixSrqStatus, + prologixSrqEnable, + prologixSerialPollBegin, + prologixSerialPoll, + prologixSerialPollEnd +}; + +static void +prologixGPIBConfigure(const char *portName, const char *host, int priority, int noAutoConnect) +{ + dPvt *pdpvt; + asynStatus status; + + /* + * Set up local storage + */ + pdpvt = (dPvt *)callocMustSucceed(1, sizeof(dPvt), portName); + pdpvt->portName = epicsStrDup(portName); + pdpvt->bufCapacity = 4096; + pdpvt->buf = callocMustSucceed(1, pdpvt->bufCapacity, portName); + pdpvt->eos = -1; + + /* + * Create the port that we'll use for I/O. + */ + pdpvt->portNameTCP = callocMustSucceed(1, strlen(portName)+10, portName); + sprintf(pdpvt->portNameTCP, "%s_TCP", portName); + pdpvt->hostTCP = callocMustSucceed(1, strlen(host)+20, portName); + if (strchr (host, ':')) + sprintf(pdpvt->hostTCP, "%s", host); + else + sprintf(pdpvt->hostTCP, "%s:1234 TCP", host); + drvAsynIPPortConfigure(pdpvt->portNameTCP, pdpvt->hostTCP, + priority, + 1, /* No auto connect */ + 1 /* No process EOS */ ); + status = pasynCommonSyncIO->connect(pdpvt->portNameTCP, -1, + &pdpvt->pasynUserTCPcommon, NULL); + if (status != asynSuccess) { + printf("Can't find ASYN port \"%s\".\n", pdpvt->portNameTCP); + return; + } + status = pasynOctetSyncIO->connect(pdpvt->portNameTCP, -1, + &pdpvt->pasynUserTCPoctet, NULL); + if (status != asynSuccess) { + printf("Can't find ASYN port \"%s\".\n", pdpvt->portNameTCP); + return; + } + + /* + * Register as a GPIB driver + */ + pdpvt->asynGpibPvt = pasynGpib->registerPort(pdpvt->portName, + ASYN_CANBLOCK | ASYN_MULTIDEVICE, + !noAutoConnect, + &prologixMethods, + pdpvt, + priority, + 0); + if(pdpvt->asynGpibPvt == NULL) { + printf("registerPort failed\n"); + return; + } +} + +/* + * IOC shell command registration + */ +static const iocshArg prologixGPIBConfigureArg0 = { "port",iocshArgString}; +static const iocshArg prologixGPIBConfigureArg1 = { "host",iocshArgString}; +static const iocshArg prologixGPIBConfigureArg2 = { "priority",iocshArgInt}; +static const iocshArg prologixGPIBConfigureArg3 = { "noAutoConnect",iocshArgInt}; +static const iocshArg *prologixGPIBConfigureArgs[] = { + &prologixGPIBConfigureArg0, &prologixGPIBConfigureArg1, + &prologixGPIBConfigureArg2, &prologixGPIBConfigureArg3 }; +static const iocshFuncDef prologixGPIBConfigureFuncDef = + {"prologixGPIBConfigure", 4, prologixGPIBConfigureArgs}; +static void prologixGPIBConfigureCallFunc(const iocshArgBuf *args) +{ + prologixGPIBConfigure(args[0].sval, args[1].sval, + args[2].ival, args[3].ival); +} + +static void +drvPrologixGPIB_RegisterCommands(void) +{ + iocshRegister(&prologixGPIBConfigureFuncDef,prologixGPIBConfigureCallFunc); +} +epicsExportRegistrar(drvPrologixGPIB_RegisterCommands); diff --git a/asyn/drvPrologixGPIB/drvPrologixGPIB.dbd b/asyn/drvPrologixGPIB/drvPrologixGPIB.dbd new file mode 100644 index 0000000..b5f326f --- /dev/null +++ b/asyn/drvPrologixGPIB/drvPrologixGPIB.dbd @@ -0,0 +1,2 @@ +include "asyn.dbd" +registrar("drvPrologixGPIB_RegisterCommands") diff --git a/asyn/gsIP488/drvGsIP488.c b/asyn/gsIP488/drvGsIP488.c index 3b88c72..29a8dd0 100644 --- a/asyn/gsIP488/drvGsIP488.c +++ b/asyn/gsIP488/drvGsIP488.c @@ -54,7 +54,7 @@ typedef struct gsport { int carrier; /* Which IP carrier board*/ int module; /* module number on carrier*/ CALLBACK callback; - epicsUInt8 isr0; + epicsUInt8 isr0; epicsUInt8 isr1; int srqEnabled; transferState_t transferState; @@ -72,7 +72,7 @@ typedef struct gsport { epicsEventId waitForInterrupt; char errorMessage[ERROR_MESSAGE_BUFFER_SIZE]; }gsport; - + static epicsUInt8 readRegister(gsport *pgsport, int offset); static void writeRegister(gsport *pgsport,int offset, epicsUInt8 value); static void printStatus(gsport *pgsport,const char *source); @@ -134,7 +134,7 @@ static asynGpibPort gpibPort = { gpibPortSerialPoll, gpibPortSerialPollEnd }; - + /* Register definitions */ #define ISR0 0x01 /*Interrupt Status Register 0*/ #define IMR0 0x01 /*Interrupt Mask Register 0*/ @@ -184,7 +184,7 @@ static asynGpibPort gpibPort = { /*Definitions for BSR*/ #define BSRSRQ 0x04 /*SRQ request*/ - + /* * Must wait 5 ti9914 clock cycles between AUXMR commands * Documentation is confusing but experiments indicate that 6 microsecod wait @@ -244,13 +244,13 @@ static void auxCmd(gsport *pgsport,epicsUInt8 value) writeRegister(pgsport,AUXMR,value); microSecondDelay(nmicro); } - + static epicsUInt8 readRegister(gsport *pgsport, int offset) { volatile epicsUInt8 *pregister = (epicsUInt8 *) (((char *)pgsport->registers)+offset); epicsUInt8 value; - + value = *pregister; if(gsip488Debug) { char message[100]; @@ -300,7 +300,7 @@ static void printStatus(gsport *pgsport, const char *source) source, pgsport->isr0,pgsport->isr1, readRegister(pgsport,ADSR),readRegister(pgsport,BSR)); } - + static void waitTimeout(gsport *pgsport,double seconds) { epicsEventWaitStatus status; @@ -342,7 +342,7 @@ static void srqCallback(CALLBACK *pcallback) if(!pgsport->srqEnabled) return; pasynGpib->srqHappened(pgsport->asynGpibPvt); } - + void gsip488(int parameter) { gsport *pgsport = (gsport *)parameter; @@ -417,7 +417,7 @@ void gsip488(int parameter) } auxCmd(pgsport,RHDF); break; - case transferStateIdle: + case transferStateIdle: if(readRegister(pgsport,ADSR&ATN)) goto exit; if(!isr0&BI) @@ -432,7 +432,7 @@ void gsip488(int parameter) /* Force synchronization of VMEbus writes on PPC CPU boards. */ octet = readRegister(pgsport,ADSR); } - + static asynStatus writeCmd(gsport *pgsport,const char *buf, int cnt, double timeout,transferState_t nextState) { @@ -478,9 +478,9 @@ static asynStatus writeAddr(gsport *pgsport,int talk, int listen, cmdbuf[lenCmd++] = primary + LADBASE; cmdbuf[lenCmd++] = secondary + SADBASE; } - return writeCmd(pgsport,cmdbuf,lenCmd,timeout,nextState); + return writeCmd(pgsport,(char *)cmdbuf,lenCmd,timeout,nextState); } - + static asynStatus writeGpib(gsport *pgsport,const char *buf, int cnt, int *actual, int addr, double timeout) { @@ -496,7 +496,7 @@ static asynStatus writeGpib(gsport *pgsport,const char *buf, int cnt, *actual = cnt - pgsport->bytesRemainingWrite; status = pgsport->status; if(status!=asynSuccess) return status; - writeCmd(pgsport,cmdbuf,2,timeout,transferStateIdle); + writeCmd(pgsport,(char *)cmdbuf,2,timeout,transferStateIdle); return status; } @@ -508,7 +508,7 @@ static asynStatus readGpib(gsport *pgsport,char *buf, int cnt, int *actual, *actual=0; *buf=0; pgsport->bytesRemainingRead = cnt; - pgsport->nextByteRead = buf; + pgsport->nextByteRead = (epicsUInt8 *)buf; pgsport->eomReason = 0; auxCmd(pgsport,RHDF); pgsport->status = asynSuccess; @@ -516,10 +516,10 @@ static asynStatus readGpib(gsport *pgsport,char *buf, int cnt, int *actual, if(status!=asynSuccess) return status; *actual = cnt - pgsport->bytesRemainingRead; if(eomReason) *eomReason = pgsport->eomReason; - writeCmd(pgsport,cmdbuf,2,timeout,transferStateIdle); + writeCmd(pgsport,(char *)cmdbuf,2,timeout,transferStateIdle); return status; } - + static void gpibPortReport(void *pdrvPvt,FILE *fd,int details) { gsport *pgsport = (gsport *)pdrvPvt; @@ -587,7 +587,7 @@ static asynStatus gpibPortDisconnect(void *pdrvPvt,asynUser *pasynUser) pasynManager->exceptionDisconnect(pasynUser); return asynSuccess; } - + static asynStatus gpibPortRead(void *pdrvPvt,asynUser *pasynUser, char *data,int maxchars,int *nbytesTransfered,int *eomReason) { @@ -641,7 +641,7 @@ static asynStatus gpibPortWrite(void *pdrvPvt,asynUser *pasynUser, *nbytesTransfered = actual; return status; } - + static asynStatus gpibPortFlush(void *pdrvPvt,asynUser *pasynUser) { /*Nothing to do */ @@ -695,7 +695,7 @@ static asynStatus gpibPortGetEos(void *pdrvPvt,asynUser *pasynUser, "%s gpibPortGetEos eoslen %d\n",pgsport->portName,*eoslen); return asynSuccess; } - + static asynStatus gpibPortAddressedCmd(void *pdrvPvt,asynUser *pasynUser, const char *data, int length) { @@ -723,7 +723,7 @@ static asynStatus gpibPortAddressedCmd(void *pdrvPvt,asynUser *pasynUser, asynPrintIO(pasynUser,ASYN_TRACEIO_DRIVER, data,actual,"%s gpibPortAddressedCmd\n",pgsport->portName); if(status!=asynSuccess) return status; - writeCmd(pgsport,cmdbuf,2,timeout,transferStateIdle); + writeCmd(pgsport,(char *)cmdbuf,2,timeout,transferStateIdle); return status; } @@ -759,7 +759,7 @@ static asynStatus gpibPortIfc(void *pdrvPvt, asynUser *pasynUser) auxCmd(pgsport,IFCC); return asynSuccess; } - + static asynStatus gpibPortRen(void *pdrvPvt,asynUser *pasynUser, int onOff) { gsport *pgsport = (gsport *)pdrvPvt; @@ -827,7 +827,7 @@ static asynStatus gpibPortSerialPollEnd(void *pdrvPvt) status = writeCmd(pgsport,cmd,2,timeout,transferStateIdle); return status; } - + int gsIP488Configure(char *portName,int carrier, int module, int vector, unsigned int priority, int noAutoConnect) { @@ -842,7 +842,7 @@ int gsIP488Configure(char *portName,int carrier, int module, int vector, printf("gsIP488Configure Unable to validate IP module"); return 0; } - registers = (char *)ipmBaseAddr(carrier, module, ipac_addrIO); + registers = (epicsUInt8 *)ipmBaseAddr(carrier, module, ipac_addrIO); if(!registers) { printf("gsIP488Configure no memory allocated " "for carrier %d module %d\n", carrier,module); @@ -877,7 +877,7 @@ int gsIP488Configure(char *portName,int carrier, int module, int vector, !noAutoConnect, &gpibPort,pgsport,priority,0); return 0; } - + /* IOC shell command registration */ #include static const iocshArg gsIP488ConfigureArg0 = { "portName",iocshArgString}; diff --git a/asyn/interfaces/asynCommonSyncIO.c b/asyn/interfaces/asynCommonSyncIO.c index 801bc8a..993e49b 100644 --- a/asyn/interfaces/asynCommonSyncIO.c +++ b/asyn/interfaces/asynCommonSyncIO.c @@ -20,8 +20,6 @@ #include #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynDrvUser.h" #include "asynCommonSyncIO.h" @@ -36,7 +34,7 @@ typedef struct ioPvt{ epicsEventId connectEvent; int connect; asynStatus connectStatus; - + }ioPvt; /*asynCommonSyncIO methods*/ @@ -53,11 +51,11 @@ static asynCommonSyncIO interface = { disconnectDevice, report }; -epicsShareDef asynCommonSyncIO *pasynCommonSyncIO = &interface; +asynCommonSyncIO *pasynCommonSyncIO = &interface; /* Private methods */ static void connectDeviceCallback(asynUser *pasynUser); - + static asynStatus connect(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo) { @@ -71,7 +69,7 @@ static asynStatus connect(const char *port, int addr, pasynUser = pasynManager->createAsynUser(connectDeviceCallback,0); pasynUser->userPvt = pioPvt; *ppasynUser = pasynUser; - status = pasynManager->connectDevice(pasynUser, port, addr); + status = pasynManager->connectDevice(pasynUser, port, addr); if (status != asynSuccess) { return status; } @@ -102,7 +100,7 @@ static asynStatus connect(const char *port, int addr, } return asynSuccess ; } - + static asynStatus disconnect(asynUser *pasynUser) { ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; @@ -122,7 +120,7 @@ static asynStatus disconnect(asynUser *pasynUser) free(pioPvt); return asynSuccess; } - + static void connectDeviceCallback(asynUser *pasynUser) { diff --git a/asyn/interfaces/asynCommonSyncIO.h b/asyn/interfaces/asynCommonSyncIO.h index db71eda..fb8e528 100644 --- a/asyn/interfaces/asynCommonSyncIO.h +++ b/asyn/interfaces/asynCommonSyncIO.h @@ -17,7 +17,6 @@ #include #include #include -#include #ifdef __cplusplus extern "C" { @@ -25,14 +24,14 @@ extern "C" { #define asynCommonSyncIOType "asynCommonSyncIO" typedef struct asynCommonSyncIO { - asynStatus (*connect)(const char *port, int addr, + asynStatus (*connect)(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo); asynStatus (*disconnect)(asynUser *pasynUser); asynStatus (*connectDevice)(asynUser *pasynUser); asynStatus (*disconnectDevice)(asynUser *pasynUser); asynStatus (*report)(asynUser *pasynUser, FILE *fd, int details); } asynCommonSyncIO; -epicsShareExtern asynCommonSyncIO *pasynCommonSyncIO; +ASYN_API extern asynCommonSyncIO *pasynCommonSyncIO; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynDrvUser.h b/asyn/interfaces/asynDrvUser.h index b9a3a2a..65656ca 100644 --- a/asyn/interfaces/asynDrvUser.h +++ b/asyn/interfaces/asynDrvUser.h @@ -17,7 +17,6 @@ #define asynDrvUserH #include -#include "shareLib.h" #ifdef __cplusplus extern "C" { diff --git a/asyn/interfaces/asynEnum.h b/asyn/interfaces/asynEnum.h index bc86b40..5601dc6 100644 --- a/asyn/interfaces/asynEnum.h +++ b/asyn/interfaces/asynEnum.h @@ -17,7 +17,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -50,7 +49,7 @@ typedef struct asynEnumBase { asynStatus (*initialize)(const char *portName, asynInterface *pEnumInterface); } asynEnumBase; -epicsShareExtern asynEnumBase *pasynEnumBase; +ASYN_API extern asynEnumBase *pasynEnumBase; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynEnumBase.c b/asyn/interfaces/asynEnumBase.c index ae3e656..fbe14cb 100644 --- a/asyn/interfaces/asynEnumBase.c +++ b/asyn/interfaces/asynEnumBase.c @@ -14,15 +14,13 @@ #include #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynEnum.h" static asynStatus initialize(const char *portName, asynInterface *pEnumInterface); static asynEnumBase enumBase = {initialize}; -epicsShareDef asynEnumBase *pasynEnumBase = &enumBase; +asynEnumBase *pasynEnumBase = &enumBase; static asynStatus writeDefault(void *drvPvt, asynUser *pasynUser, char *strings[], int values[], int severities[], size_t nElements); @@ -34,7 +32,7 @@ static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, static asynStatus cancelInterruptUser(void *drvPvt, asynUser *pasynUser, void *registrarPvt); - + asynStatus initialize(const char *portName, asynInterface *pdriver) { asynEnum *pasynEnum = (asynEnum *)pdriver->pinterface; @@ -54,7 +52,7 @@ static asynStatus writeDefault(void *drvPvt, asynUser *pasynUser, const char *portName; asynStatus status; int addr; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -94,18 +92,18 @@ static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, interruptNode *pinterruptNode; void *pinterruptPvt; asynEnumInterrupt *pasynEnumInterrupt; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); if(status!=asynSuccess) return status; - status = pasynManager->getInterruptPvt(pasynUser, asynEnumType, + status = pasynManager->getInterruptPvt(pasynUser, asynEnumType, &pinterruptPvt); if(status!=asynSuccess) return status; pasynEnumInterrupt = pasynManager->memMalloc(sizeof(asynEnumInterrupt)); pinterruptNode = pasynManager->createInterruptNode(pinterruptPvt); pinterruptNode->drvPvt = pasynEnumInterrupt; - pasynEnumInterrupt->pasynUser = + pasynEnumInterrupt->pasynUser = pasynManager->duplicateAsynUser(pasynUser, NULL, NULL); pasynEnumInterrupt->addr = addr; pasynEnumInterrupt->callback = callback; @@ -120,12 +118,12 @@ static asynStatus cancelInterruptUser(void *drvPvt, asynUser *pasynUser, void *registrarPvt) { interruptNode *pinterruptNode = (interruptNode *)registrarPvt; - asynEnumInterrupt *pasynEnumInterrupt = + asynEnumInterrupt *pasynEnumInterrupt = (asynEnumInterrupt *)pinterruptNode->drvPvt; asynStatus status; const char *portName; int addr; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); diff --git a/asyn/interfaces/asynEnumSyncIO.c b/asyn/interfaces/asynEnumSyncIO.c index e15930c..409062f 100644 --- a/asyn/interfaces/asynEnumSyncIO.c +++ b/asyn/interfaces/asynEnumSyncIO.c @@ -19,8 +19,6 @@ #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynEnum.h" #include "asynDrvUser.h" @@ -39,13 +37,13 @@ typedef struct ioPvt{ static asynStatus connect(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo); static asynStatus disconnect(asynUser *pasynUser); -static asynStatus writeOp(asynUser *pasynUser, char *strings[], int values[], int severities[], +static asynStatus writeOp(asynUser *pasynUser, char *strings[], int values[], int severities[], size_t nElements, double timeout); -static asynStatus readOp(asynUser *pasynUser, char *strings[], int values[], int severities[], +static asynStatus readOp(asynUser *pasynUser, char *strings[], int values[], int severities[], size_t nElements, size_t *nIn, double timeout); -static asynStatus writeOpOnce(const char *port, int addr, char *strings[], int values[], int severities[], +static asynStatus writeOpOnce(const char *port, int addr, char *strings[], int values[], int severities[], size_t nElements, double timeout,const char *drvInfo); -static asynStatus readOpOnce(const char *port, int addr, char *strings[], int values[], int severities[], +static asynStatus readOpOnce(const char *port, int addr, char *strings[], int values[], int severities[], size_t nElements, size_t *nIn, double timeout, const char *drvInfo); static asynEnumSyncIO interface = { connect, @@ -55,8 +53,8 @@ static asynEnumSyncIO interface = { writeOpOnce, readOpOnce, }; -epicsShareDef asynEnumSyncIO *pasynEnumSyncIO = &interface; - +asynEnumSyncIO *pasynEnumSyncIO = &interface; + static asynStatus connect(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo) { @@ -69,7 +67,7 @@ static asynStatus connect(const char *port, int addr, pasynUser = pasynManager->createAsynUser(0,0); pasynUser->userPvt = pioPvt; *ppasynUser = pasynUser; - status = pasynManager->connectDevice(pasynUser, port, addr); + status = pasynManager->connectDevice(pasynUser, port, addr); if (status != asynSuccess) { return status; } @@ -108,7 +106,7 @@ static asynStatus connect(const char *port, int addr, } return asynSuccess ; } - + static asynStatus disconnect(asynUser *pasynUser) { ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; @@ -127,7 +125,7 @@ static asynStatus disconnect(asynUser *pasynUser) free(pioPvt); return asynSuccess; } - + static asynStatus writeOp(asynUser *pasynUser, char *strings[], int values[], int severities[], size_t nElements, double timeout) { @@ -143,7 +141,7 @@ static asynStatus writeOp(asynUser *pasynUser, char *strings[], int values[], in if (status==asynSuccess) { int i; for (i=0; i<(int)nElements; i++) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynEnumSyncIO wrote: %d string=%s, value=%d severity=%d\n", i, strings[i], values[i], severities[i]); } } @@ -168,7 +166,7 @@ static asynStatus readOp(asynUser *pasynUser, char *strings[], int values[], int if (status==asynSuccess) { int i; for (i=0; i<(int)*nIn; i++) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynEnumSyncIO read: %d string=%s, value=%d, severity=%d\n", i, strings[i], values[i], severities[i]); } } @@ -178,7 +176,7 @@ static asynStatus readOp(asynUser *pasynUser, char *strings[], int values[], int } return(status); } - + static asynStatus writeOpOnce(const char *port, int addr, char *strings[], int values[], int severities[], size_t nElements, double timeout, const char *drvInfo) { diff --git a/asyn/interfaces/asynEnumSyncIO.h b/asyn/interfaces/asynEnumSyncIO.h index a70904f..c1c7446 100644 --- a/asyn/interfaces/asynEnumSyncIO.h +++ b/asyn/interfaces/asynEnumSyncIO.h @@ -16,7 +16,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -24,19 +23,19 @@ extern "C" { #define asynEnumSyncIOType "asynEnumSyncIO" typedef struct asynEnumSyncIO { - asynStatus (*connect)(const char *port, int addr, + asynStatus (*connect)(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo); asynStatus (*disconnect)(asynUser *pasynUser); - asynStatus (*write)(asynUser *pasynUser, char *strings[], int values[], int severities[], + asynStatus (*write)(asynUser *pasynUser, char *strings[], int values[], int severities[], size_t nElements, double timeout); - asynStatus (*read)(asynUser *pasynUser, char *string[], int values[], int severities[], + asynStatus (*read)(asynUser *pasynUser, char *string[], int values[], int severities[], size_t nElements, size_t *nIn, double timeout); - asynStatus (*writeOnce)(const char *port, int addr, char *strings[], int values[], int severities[], + asynStatus (*writeOnce)(const char *port, int addr, char *strings[], int values[], int severities[], size_t nElements, double timeout, const char *drvInfo); - asynStatus (*readOnce)(const char *port, int addr, char *strings[], int values[], int severities[], + asynStatus (*readOnce)(const char *port, int addr, char *strings[], int values[], int severities[], size_t nElements, size_t *nIn, double timeout, const char *drvInfo); } asynEnumSyncIO; -epicsShareExtern asynEnumSyncIO *pasynEnumSyncIO; +ASYN_API extern asynEnumSyncIO *pasynEnumSyncIO; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynFloat32Array.h b/asyn/interfaces/asynFloat32Array.h index 85a4013..f3fb205 100644 --- a/asyn/interfaces/asynFloat32Array.h +++ b/asyn/interfaces/asynFloat32Array.h @@ -16,7 +16,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -57,7 +56,7 @@ typedef struct asynFloat32ArrayBase { asynStatus (*initialize)(const char *portName, asynInterface *pfloat32ArrayInterface); } asynFloat32ArrayBase; -epicsShareExtern asynFloat32ArrayBase *pasynFloat32ArrayBase; +ASYN_API extern asynFloat32ArrayBase *pasynFloat32ArrayBase; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynFloat32ArrayBase.c b/asyn/interfaces/asynFloat32ArrayBase.c index b201a77..4e218e6 100644 --- a/asyn/interfaces/asynFloat32ArrayBase.c +++ b/asyn/interfaces/asynFloat32ArrayBase.c @@ -15,13 +15,11 @@ #include #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynFloat32Array.h" #include "asynXXXArrayBase.h" - + ASYN_XXX_ARRAY_BASE_FUNCS(asynFloat32Array, asynFloat32ArrayType, asynFloat32ArrayBase, pasynFloat32ArrayBase, asynFloat32ArrayInterrupt, interruptCallbackFloat32Array, epicsFloat32) diff --git a/asyn/interfaces/asynFloat32ArraySyncIO.c b/asyn/interfaces/asynFloat32ArraySyncIO.c index bcbaaed..364d624 100644 --- a/asyn/interfaces/asynFloat32ArraySyncIO.c +++ b/asyn/interfaces/asynFloat32ArraySyncIO.c @@ -19,8 +19,6 @@ #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynFloat32Array.h" #include "asynDrvUser.h" @@ -53,8 +51,8 @@ static asynFloat32ArraySyncIO interface = { writeOpOnce, readOpOnce }; -epicsShareDef asynFloat32ArraySyncIO *pasynFloat32ArraySyncIO = &interface; - +asynFloat32ArraySyncIO *pasynFloat32ArraySyncIO = &interface; + static asynStatus connect(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo) { @@ -67,7 +65,7 @@ static asynStatus connect(const char *port, int addr, pasynUser = pasynManager->createAsynUser(0,0); pasynUser->userPvt = pioPvt; *ppasynUser = pasynUser; - status = pasynManager->connectDevice(pasynUser, port, addr); + status = pasynManager->connectDevice(pasynUser, port, addr); if (status != asynSuccess) { return status; } @@ -106,7 +104,7 @@ static asynStatus connect(const char *port, int addr, } return asynSuccess ; } - + static asynStatus disconnect(asynUser *pasynUser) { ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; @@ -125,7 +123,7 @@ static asynStatus disconnect(asynUser *pasynUser) free(pioPvt); return asynSuccess; } - + static asynStatus writeOp(asynUser *pasynUser,epicsFloat32 *pvalue,size_t nelem,double timeout) { asynStatus status, unlockStatus; @@ -138,7 +136,7 @@ static asynStatus writeOp(asynUser *pasynUser,epicsFloat32 *pvalue,size_t nelem, } status = pPvt->pasynFloat32Array->write(pPvt->float32ArrayPvt, pasynUser,pvalue,nelem); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynFloat32ArraySyncIO wrote: %e\n", *pvalue); } @@ -161,7 +159,7 @@ static asynStatus readOp(asynUser *pasynUser,epicsFloat32 *pvalue,size_t nelem,s } status = pPvt->pasynFloat32Array->read(pPvt->float32ArrayPvt, pasynUser, pvalue, nelem, nIn); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynFloat32ArraySyncIO read: %e\n", *pvalue); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -170,7 +168,7 @@ static asynStatus readOp(asynUser *pasynUser,epicsFloat32 *pvalue,size_t nelem,s } return status; } - + static asynStatus writeOpOnce(const char *port, int addr, epicsFloat32 *pvalue,size_t nelem,double timeout,const char *drvInfo) { diff --git a/asyn/interfaces/asynFloat32ArraySyncIO.h b/asyn/interfaces/asynFloat32ArraySyncIO.h index fe2fb41..dc195a8 100644 --- a/asyn/interfaces/asynFloat32ArraySyncIO.h +++ b/asyn/interfaces/asynFloat32ArraySyncIO.h @@ -16,7 +16,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -24,7 +23,7 @@ extern "C" { #define asynFloat32ArraySyncIOType "asynFloat32ArraySyncIO" typedef struct asynFloat32ArraySyncIO { - asynStatus (*connect)(const char *port, int addr, + asynStatus (*connect)(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo); asynStatus (*disconnect)(asynUser *pasynUser); asynStatus (*write)(asynUser *pasynUser,epicsFloat32 *pvalue,size_t nelem,double timeout); @@ -34,7 +33,7 @@ typedef struct asynFloat32ArraySyncIO { asynStatus (*readOnce)(const char *port, int addr, epicsFloat32 *pvalue,size_t nelem,size_t *nIn,double timeout,const char *drvInfo); } asynFloat32ArraySyncIO; -epicsShareExtern asynFloat32ArraySyncIO *pasynFloat32ArraySyncIO; +ASYN_API extern asynFloat32ArraySyncIO *pasynFloat32ArraySyncIO; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynFloat64.h b/asyn/interfaces/asynFloat64.h index 4098eb3..62a7649 100644 --- a/asyn/interfaces/asynFloat64.h +++ b/asyn/interfaces/asynFloat64.h @@ -16,7 +16,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -53,7 +52,7 @@ typedef struct asynFloat64Base { asynStatus (*initialize)(const char *portName, asynInterface *pasynFloat64Interface); } asynFloat64Base; -epicsShareExtern asynFloat64Base *pasynFloat64Base; +ASYN_API extern asynFloat64Base *pasynFloat64Base; #ifdef __cplusplus diff --git a/asyn/interfaces/asynFloat64Array.h b/asyn/interfaces/asynFloat64Array.h index 67f81ed..c54cdef 100644 --- a/asyn/interfaces/asynFloat64Array.h +++ b/asyn/interfaces/asynFloat64Array.h @@ -16,7 +16,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -57,7 +56,7 @@ typedef struct asynFloat64ArrayBase { asynStatus (*initialize)(const char *portName, asynInterface *pfloat64ArrayInterface); } asynFloat64ArrayBase; -epicsShareExtern asynFloat64ArrayBase *pasynFloat64ArrayBase; +ASYN_API extern asynFloat64ArrayBase *pasynFloat64ArrayBase; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynFloat64ArrayBase.c b/asyn/interfaces/asynFloat64ArrayBase.c index eab9990..92e038c 100644 --- a/asyn/interfaces/asynFloat64ArrayBase.c +++ b/asyn/interfaces/asynFloat64ArrayBase.c @@ -15,13 +15,11 @@ #include #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynFloat64Array.h" #include "asynXXXArrayBase.h" - + ASYN_XXX_ARRAY_BASE_FUNCS(asynFloat64Array, asynFloat64ArrayType, asynFloat64ArrayBase, pasynFloat64ArrayBase, asynFloat64ArrayInterrupt, interruptCallbackFloat64Array, epicsFloat64) diff --git a/asyn/interfaces/asynFloat64ArraySyncIO.c b/asyn/interfaces/asynFloat64ArraySyncIO.c index 9e0a937..3a14337 100644 --- a/asyn/interfaces/asynFloat64ArraySyncIO.c +++ b/asyn/interfaces/asynFloat64ArraySyncIO.c @@ -19,8 +19,6 @@ #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynFloat64Array.h" #include "asynDrvUser.h" @@ -53,8 +51,8 @@ static asynFloat64ArraySyncIO interface = { writeOpOnce, readOpOnce }; -epicsShareDef asynFloat64ArraySyncIO *pasynFloat64ArraySyncIO = &interface; - +asynFloat64ArraySyncIO *pasynFloat64ArraySyncIO = &interface; + static asynStatus connect(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo) { @@ -67,7 +65,7 @@ static asynStatus connect(const char *port, int addr, pasynUser = pasynManager->createAsynUser(0,0); pasynUser->userPvt = pioPvt; *ppasynUser = pasynUser; - status = pasynManager->connectDevice(pasynUser, port, addr); + status = pasynManager->connectDevice(pasynUser, port, addr); if (status != asynSuccess) { return status; } @@ -106,7 +104,7 @@ static asynStatus connect(const char *port, int addr, } return asynSuccess ; } - + static asynStatus disconnect(asynUser *pasynUser) { ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; @@ -125,7 +123,7 @@ static asynStatus disconnect(asynUser *pasynUser) free(pioPvt); return asynSuccess; } - + static asynStatus writeOp(asynUser *pasynUser,epicsFloat64 *pvalue,size_t nelem,double timeout) { asynStatus status, unlockStatus; @@ -138,7 +136,7 @@ static asynStatus writeOp(asynUser *pasynUser,epicsFloat64 *pvalue,size_t nelem, } status = pPvt->pasynFloat64Array->write(pPvt->float64ArrayPvt, pasynUser,pvalue,nelem); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynFloat64ArraySyncIO wrote: %e\n", *pvalue); } @@ -161,7 +159,7 @@ static asynStatus readOp(asynUser *pasynUser,epicsFloat64 *pvalue,size_t nelem,s } status = pPvt->pasynFloat64Array->read(pPvt->float64ArrayPvt, pasynUser, pvalue, nelem, nIn); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynFloat64ArraySyncIO read: %e\n", *pvalue); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -170,7 +168,7 @@ static asynStatus readOp(asynUser *pasynUser,epicsFloat64 *pvalue,size_t nelem,s } return status; } - + static asynStatus writeOpOnce(const char *port, int addr, epicsFloat64 *pvalue,size_t nelem,double timeout,const char *drvInfo) { diff --git a/asyn/interfaces/asynFloat64ArraySyncIO.h b/asyn/interfaces/asynFloat64ArraySyncIO.h index ff3e384..5f89a08 100644 --- a/asyn/interfaces/asynFloat64ArraySyncIO.h +++ b/asyn/interfaces/asynFloat64ArraySyncIO.h @@ -16,7 +16,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -24,7 +23,7 @@ extern "C" { #define asynFloat64ArraySyncIOType "asynFloat64ArraySyncIO" typedef struct asynFloat64ArraySyncIO { - asynStatus (*connect)(const char *port, int addr, + asynStatus (*connect)(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo); asynStatus (*disconnect)(asynUser *pasynUser); asynStatus (*write)(asynUser *pasynUser,epicsFloat64 *pvalue,size_t nelem,double timeout); @@ -34,7 +33,7 @@ typedef struct asynFloat64ArraySyncIO { asynStatus (*readOnce)(const char *port, int addr, epicsFloat64 *pvalue,size_t nelem,size_t *nIn,double timeout,const char *drvInfo); } asynFloat64ArraySyncIO; -epicsShareExtern asynFloat64ArraySyncIO *pasynFloat64ArraySyncIO; +ASYN_API extern asynFloat64ArraySyncIO *pasynFloat64ArraySyncIO; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynFloat64Base.c b/asyn/interfaces/asynFloat64Base.c index 1a02197..f69d7cc 100644 --- a/asyn/interfaces/asynFloat64Base.c +++ b/asyn/interfaces/asynFloat64Base.c @@ -15,15 +15,13 @@ #include #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynFloat64.h" static asynStatus initialize(const char *portName, asynInterface *pfloat64Interface); static asynFloat64Base float64Base = {initialize}; -epicsShareDef asynFloat64Base *pasynFloat64Base = &float64Base; +asynFloat64Base *pasynFloat64Base = &float64Base; static asynStatus writeDefault(void *drvPvt, asynUser *pasynUser, epicsFloat64 value); @@ -33,7 +31,7 @@ static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, interruptCallbackFloat64 callback, void *userPvt, void **registrarPvt); static asynStatus cancelInterruptUser(void *drvPvt, asynUser *pasynUser, void *registrarPvt); - + static asynStatus initialize(const char *portName, asynInterface *pdriver) { asynFloat64 *pasynFloat64 = (asynFloat64 *)pdriver->pinterface;; @@ -53,7 +51,7 @@ static asynStatus writeDefault(void *drvPvt, asynUser *pasynUser, const char *portName; asynStatus status; int addr; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -71,7 +69,7 @@ static asynStatus readDefault(void *drvPvt, asynUser *pasynUser, const char *portName; asynStatus status; int addr; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -82,7 +80,7 @@ static asynStatus readDefault(void *drvPvt, asynUser *pasynUser, "%s %d read is not supported\n",portName,addr); return asynError; } - + static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, interruptCallbackFloat64 callback, void *userPvt, void **registrarPvt) { @@ -92,7 +90,7 @@ static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, interruptNode *pinterruptNode; void *pinterruptPvt; asynFloat64Interrupt *pasynFloat64Interrupt; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -122,7 +120,7 @@ static asynStatus cancelInterruptUser(void *drvPvt, asynUser *pasynUser, asynStatus status; const char *portName; int addr; - asynFloat64Interrupt *pasynFloat64Interrupt = + asynFloat64Interrupt *pasynFloat64Interrupt = (asynFloat64Interrupt *)pinterruptNode->drvPvt; status = pasynManager->getPortName(pasynUser,&portName); diff --git a/asyn/interfaces/asynFloat64SyncIO.c b/asyn/interfaces/asynFloat64SyncIO.c index 70a168b..4ff7d83 100644 --- a/asyn/interfaces/asynFloat64SyncIO.c +++ b/asyn/interfaces/asynFloat64SyncIO.c @@ -19,8 +19,6 @@ #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynFloat64.h" #include "asynDrvUser.h" @@ -53,8 +51,8 @@ static asynFloat64SyncIO interface = { writeOpOnce, readOpOnce }; -epicsShareDef asynFloat64SyncIO *pasynFloat64SyncIO = &interface; - +asynFloat64SyncIO *pasynFloat64SyncIO = &interface; + static asynStatus connect(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo) { @@ -67,7 +65,7 @@ static asynStatus connect(const char *port, int addr, pasynUser = pasynManager->createAsynUser(0,0); pasynUser->userPvt = pioPvt; *ppasynUser = pasynUser; - status = pasynManager->connectDevice(pasynUser, port, addr); + status = pasynManager->connectDevice(pasynUser, port, addr); if (status != asynSuccess) { return status; } @@ -106,7 +104,7 @@ static asynStatus connect(const char *port, int addr, } return asynSuccess ; } - + static asynStatus disconnect(asynUser *pasynUser) { ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; @@ -125,7 +123,7 @@ static asynStatus disconnect(asynUser *pasynUser) free(pioPvt); return asynSuccess; } - + static asynStatus writeOp(asynUser *pasynUser,epicsFloat64 value,double timeout) { asynStatus status, unlockStatus; @@ -138,7 +136,7 @@ static asynStatus writeOp(asynUser *pasynUser,epicsFloat64 value,double timeout) } status = pPvt->pasynFloat64->write(pPvt->float64Pvt, pasynUser,value); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynFloat64SyncIO wrote: %e\n", value); } @@ -161,7 +159,7 @@ static asynStatus readOp(asynUser *pasynUser,epicsFloat64 *pvalue,double timeout } status = pPvt->pasynFloat64->read(pPvt->float64Pvt, pasynUser, pvalue); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynFloat64SyncIO read: %e\n", *pvalue); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -170,7 +168,7 @@ static asynStatus readOp(asynUser *pasynUser,epicsFloat64 *pvalue,double timeout } return status; } - + static asynStatus writeOpOnce(const char *port, int addr, epicsFloat64 value,double timeout,const char *drvInfo) { diff --git a/asyn/interfaces/asynFloat64SyncIO.h b/asyn/interfaces/asynFloat64SyncIO.h index ad345f2..d313817 100644 --- a/asyn/interfaces/asynFloat64SyncIO.h +++ b/asyn/interfaces/asynFloat64SyncIO.h @@ -16,7 +16,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -24,7 +23,7 @@ extern "C" { #define asynFloat64SyncIOType "asynFloat64SyncIO" typedef struct asynFloat64SyncIO { - asynStatus (*connect)(const char *port, int addr, + asynStatus (*connect)(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo); asynStatus (*disconnect)(asynUser *pasynUser); asynStatus (*write)(asynUser *pasynUser,epicsFloat64 value,double timeout); @@ -34,7 +33,7 @@ typedef struct asynFloat64SyncIO { asynStatus (*readOnce)(const char *port, int addr, epicsFloat64 *pvalue,double timeout,const char *drvInfo); } asynFloat64SyncIO; -epicsShareExtern asynFloat64SyncIO *pasynFloat64SyncIO; +ASYN_API extern asynFloat64SyncIO *pasynFloat64SyncIO; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynGenericPointer.h b/asyn/interfaces/asynGenericPointer.h index a0cd839..571a43f 100644 --- a/asyn/interfaces/asynGenericPointer.h +++ b/asyn/interfaces/asynGenericPointer.h @@ -17,7 +17,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -25,7 +24,7 @@ extern "C" { typedef void (*interruptCallbackGenericPointer)(void *userPvt, asynUser *pasynUser, void *pointer); - + typedef struct asynGenericPointerInterrupt { asynUser *pasynUser; int addr; @@ -57,7 +56,7 @@ typedef struct asynGenericPointerBase { asynInterface *pasynGenericPointerInterface); } asynGenericPointerBase; -epicsShareExtern asynGenericPointerBase *pasynGenericPointerBase; +ASYN_API extern asynGenericPointerBase *pasynGenericPointerBase; #ifdef __cplusplus diff --git a/asyn/interfaces/asynGenericPointerBase.c b/asyn/interfaces/asynGenericPointerBase.c index 6f3aadf..ed1eba7 100644 --- a/asyn/interfaces/asynGenericPointerBase.c +++ b/asyn/interfaces/asynGenericPointerBase.c @@ -16,8 +16,6 @@ #include #include -#define epicsExportSharedSymbols -#include #include #include "asynGenericPointer.h" @@ -25,7 +23,7 @@ static asynStatus initialize(const char *portName, asynInterface *pGenericPointerInterface); static asynGenericPointerBase GenericPointerBase = {initialize}; -epicsShareDef asynGenericPointerBase *pasynGenericPointerBase = &GenericPointerBase; +asynGenericPointerBase *pasynGenericPointerBase = &GenericPointerBase; static asynStatus writeDefault(void *drvPvt, asynUser *pasynUser, void *pointer); static asynStatus readDefault(void *drvPvt, asynUser *pasynUser, void *pointer); @@ -33,7 +31,7 @@ static asynStatus registerInterruptUser(void *drvPvt, asynUser *pasynUser, interruptCallbackGenericPointer callback, void *userPvt, void **registrarPvt); static asynStatus cancelInterruptUser(void *drvPvt, asynUser *pasynUser, void *registrarPvt); - + static asynStatus initialize(const char *portName, asynInterface *pdriver) { @@ -53,7 +51,7 @@ static asynStatus writeDefault(void *drvPvt, asynUser *pasynUser, void *pointer) const char *portName; asynStatus status; int addr; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -70,7 +68,7 @@ static asynStatus readDefault(void *drvPvt, asynUser *pasynUser, void *pointer) const char *portName; asynStatus status; int addr; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -81,7 +79,7 @@ static asynStatus readDefault(void *drvPvt, asynUser *pasynUser, void *pointer) "%s %d read is not supported\n",portName,addr); return asynError; } - + static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, interruptCallbackGenericPointer callback, void *userPvt, void **registrarPvt) { @@ -91,7 +89,7 @@ static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, interruptNode *pinterruptNode; void *pinterruptPvt; asynGenericPointerInterrupt *pasynGenericPointerInterrupt; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -121,7 +119,7 @@ static asynStatus cancelInterruptUser(void *drvPvt, asynUser *pasynUser, asynStatus status; const char *portName; int addr; - asynGenericPointerInterrupt *pasynGenericPointerInterrupt = + asynGenericPointerInterrupt *pasynGenericPointerInterrupt = (asynGenericPointerInterrupt *)pinterruptNode->drvPvt; status = pasynManager->getPortName(pasynUser,&portName); diff --git a/asyn/interfaces/asynGenericPointerSyncIO.c b/asyn/interfaces/asynGenericPointerSyncIO.c index 421bf9b..a7aafec 100644 --- a/asyn/interfaces/asynGenericPointerSyncIO.c +++ b/asyn/interfaces/asynGenericPointerSyncIO.c @@ -19,8 +19,6 @@ #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynGenericPointer.h" #include "asynDrvUser.h" @@ -59,8 +57,8 @@ static asynGenericPointerSyncIO interface = { readOpOnce, writeReadOpOnce }; -epicsShareDef asynGenericPointerSyncIO *pasynGenericPointerSyncIO = &interface; - +asynGenericPointerSyncIO *pasynGenericPointerSyncIO = &interface; + static asynStatus connect(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo) { @@ -73,7 +71,7 @@ static asynStatus connect(const char *port, int addr, pasynUser = pasynManager->createAsynUser(0,0); pasynUser->userPvt = pioPvt; *ppasynUser = pasynUser; - status = pasynManager->connectDevice(pasynUser, port, addr); + status = pasynManager->connectDevice(pasynUser, port, addr); if (status != asynSuccess) { return status; } @@ -112,7 +110,7 @@ static asynStatus connect(const char *port, int addr, } return asynSuccess ; } - + static asynStatus disconnect(asynUser *pasynUser) { ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; @@ -131,7 +129,7 @@ static asynStatus disconnect(asynUser *pasynUser) free(pioPvt); return asynSuccess; } - + static asynStatus writeOp(asynUser *pasynUser,void *pvalue,double timeout) { asynStatus status, unlockStatus; @@ -144,7 +142,7 @@ static asynStatus writeOp(asynUser *pasynUser,void *pvalue,double timeout) } status = pPvt->pasynGenericPointer->write(pPvt->pointerPvt, pasynUser,pvalue); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynGenericPointerSyncIO wrote: %p\n", pvalue); } @@ -167,7 +165,7 @@ static asynStatus readOp(asynUser *pasynUser,void *pvalue,double timeout) } status = pPvt->pasynGenericPointer->read(pPvt->pointerPvt, pasynUser, pvalue); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynGenericPointerSyncIO read: %p\n", pvalue); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -214,7 +212,7 @@ static asynStatus writeReadOp(asynUser *pasynUser, } return status; } - + static asynStatus writeOpOnce(const char *port, int addr, void *pvalue,double timeout,const char *drvInfo) { diff --git a/asyn/interfaces/asynGenericPointerSyncIO.h b/asyn/interfaces/asynGenericPointerSyncIO.h index 1a9baa6..96d776e 100644 --- a/asyn/interfaces/asynGenericPointerSyncIO.h +++ b/asyn/interfaces/asynGenericPointerSyncIO.h @@ -16,7 +16,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -24,7 +23,7 @@ extern "C" { #define asynGenericPointerSyncIOType "asynGenericPointerSyncIO" typedef struct asynGenericPointerSyncIO { - asynStatus (*connect)(const char *port, int addr, + asynStatus (*connect)(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo); asynStatus (*disconnect)(asynUser *pasynUser); asynStatus (*write)(asynUser *pasynUser,void *pvalue,double timeout); @@ -37,7 +36,7 @@ typedef struct asynGenericPointerSyncIO { asynStatus (*writeReadOnce)(const char *port, int addr, void *pwrite_buffer,void *pread_buffer,double timeout,const char *drvInfo); } asynGenericPointerSyncIO; -epicsShareExtern asynGenericPointerSyncIO *pasynGenericPointerSyncIO; +ASYN_API extern asynGenericPointerSyncIO *pasynGenericPointerSyncIO; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynInt16Array.h b/asyn/interfaces/asynInt16Array.h index 636eae0..ba07a7b 100644 --- a/asyn/interfaces/asynInt16Array.h +++ b/asyn/interfaces/asynInt16Array.h @@ -17,7 +17,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -50,7 +49,7 @@ typedef struct asynInt16ArrayBase { asynStatus (*initialize)(const char *portName, asynInterface *pint16ArrayInterface); } asynInt16ArrayBase; -epicsShareExtern asynInt16ArrayBase *pasynInt16ArrayBase; +ASYN_API extern asynInt16ArrayBase *pasynInt16ArrayBase; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynInt16ArrayBase.c b/asyn/interfaces/asynInt16ArrayBase.c index ddd4d7f..c5ad48c 100644 --- a/asyn/interfaces/asynInt16ArrayBase.c +++ b/asyn/interfaces/asynInt16ArrayBase.c @@ -15,8 +15,6 @@ #include #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynInt16Array.h" diff --git a/asyn/interfaces/asynInt16ArraySyncIO.c b/asyn/interfaces/asynInt16ArraySyncIO.c index 0b7e788..8748f83 100644 --- a/asyn/interfaces/asynInt16ArraySyncIO.c +++ b/asyn/interfaces/asynInt16ArraySyncIO.c @@ -19,8 +19,6 @@ #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynInt16Array.h" #include "asynDrvUser.h" @@ -53,8 +51,8 @@ static asynInt16ArraySyncIO interface = { writeOpOnce, readOpOnce }; -epicsShareDef asynInt16ArraySyncIO *pasynInt16ArraySyncIO = &interface; - +asynInt16ArraySyncIO *pasynInt16ArraySyncIO = &interface; + static asynStatus connect(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo) { @@ -67,7 +65,7 @@ static asynStatus connect(const char *port, int addr, pasynUser = pasynManager->createAsynUser(0,0); pasynUser->userPvt = pioPvt; *ppasynUser = pasynUser; - status = pasynManager->connectDevice(pasynUser, port, addr); + status = pasynManager->connectDevice(pasynUser, port, addr); if (status != asynSuccess) { return status; } @@ -106,7 +104,7 @@ static asynStatus connect(const char *port, int addr, } return asynSuccess ; } - + static asynStatus disconnect(asynUser *pasynUser) { ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; @@ -125,7 +123,7 @@ static asynStatus disconnect(asynUser *pasynUser) free(pioPvt); return asynSuccess; } - + static asynStatus writeOp(asynUser *pasynUser,epicsInt16 *pvalue,size_t nelem,double timeout) { asynStatus status, unlockStatus; @@ -138,7 +136,7 @@ static asynStatus writeOp(asynUser *pasynUser,epicsInt16 *pvalue,size_t nelem,do } status = pPvt->pasynInt16Array->write(pPvt->int16ArrayPvt, pasynUser,pvalue,nelem); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynInt16ArraySyncIO wrote: %d\n", *pvalue); } @@ -161,7 +159,7 @@ static asynStatus readOp(asynUser *pasynUser,epicsInt16 *pvalue,size_t nelem,siz } status = pPvt->pasynInt16Array->read(pPvt->int16ArrayPvt, pasynUser, pvalue, nelem, nIn); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynInt16ArraySyncIO read: %d\n", *pvalue); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -170,7 +168,7 @@ static asynStatus readOp(asynUser *pasynUser,epicsInt16 *pvalue,size_t nelem,siz } return status; } - + static asynStatus writeOpOnce(const char *port, int addr, epicsInt16 *pvalue,size_t nelem,double timeout,const char *drvInfo) { diff --git a/asyn/interfaces/asynInt16ArraySyncIO.h b/asyn/interfaces/asynInt16ArraySyncIO.h index acefda1..c6e3cf4 100644 --- a/asyn/interfaces/asynInt16ArraySyncIO.h +++ b/asyn/interfaces/asynInt16ArraySyncIO.h @@ -16,7 +16,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -24,7 +23,7 @@ extern "C" { #define asynInt16ArraySyncIOType "asynInt16ArraySyncIO" typedef struct asynInt16ArraySyncIO { - asynStatus (*connect)(const char *port, int addr, + asynStatus (*connect)(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo); asynStatus (*disconnect)(asynUser *pasynUser); asynStatus (*write)(asynUser *pasynUser,epicsInt16 *pvalue,size_t nelem,double timeout); @@ -34,7 +33,7 @@ typedef struct asynInt16ArraySyncIO { asynStatus (*readOnce)(const char *port, int addr, epicsInt16 *pvalue,size_t nelem,size_t *nIn,double timeout,const char *drvInfo); } asynInt16ArraySyncIO; -epicsShareExtern asynInt16ArraySyncIO *pasynInt16ArraySyncIO; +ASYN_API extern asynInt16ArraySyncIO *pasynInt16ArraySyncIO; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynInt32.h b/asyn/interfaces/asynInt32.h index 8681b39..3a55107 100644 --- a/asyn/interfaces/asynInt32.h +++ b/asyn/interfaces/asynInt32.h @@ -16,13 +16,12 @@ #include #include -#include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -typedef void (*interruptCallbackInt32)(void *userPvt, asynUser *pasynUser, +typedef void (*interruptCallbackInt32)(void *userPvt, asynUser *pasynUser, epicsInt32 data); typedef struct asynInt32Interrupt { int addr; @@ -34,7 +33,7 @@ typedef struct asynInt32Interrupt { typedef struct asynInt32 { asynStatus (*write)(void *drvPvt, asynUser *pasynUser, epicsInt32 value); asynStatus (*read)(void *drvPvt, asynUser *pasynUser, epicsInt32 *value); - asynStatus (*getBounds)(void *drvPvt, asynUser *pasynUser, + asynStatus (*getBounds)(void *drvPvt, asynUser *pasynUser, epicsInt32 *low, epicsInt32 *high); asynStatus (*registerInterruptUser)(void *drvPvt,asynUser *pasynUser, interruptCallbackInt32 callback, void *userPvt, @@ -56,7 +55,7 @@ typedef struct asynInt32Base { asynStatus (*initialize)(const char *portName, asynInterface *pint32Interface); } asynInt32Base; -epicsShareExtern asynInt32Base *pasynInt32Base; +ASYN_API extern asynInt32Base *pasynInt32Base; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynInt32Array.h b/asyn/interfaces/asynInt32Array.h index 510d15c..188447c 100644 --- a/asyn/interfaces/asynInt32Array.h +++ b/asyn/interfaces/asynInt32Array.h @@ -17,7 +17,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -50,7 +49,7 @@ typedef struct asynInt32ArrayBase { asynStatus (*initialize)(const char *portName, asynInterface *pint32ArrayInterface); } asynInt32ArrayBase; -epicsShareExtern asynInt32ArrayBase *pasynInt32ArrayBase; +ASYN_API extern asynInt32ArrayBase *pasynInt32ArrayBase; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynInt32ArrayBase.c b/asyn/interfaces/asynInt32ArrayBase.c index a248165..556e6b5 100644 --- a/asyn/interfaces/asynInt32ArrayBase.c +++ b/asyn/interfaces/asynInt32ArrayBase.c @@ -15,13 +15,11 @@ #include #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynInt32Array.h" #include "asynXXXArrayBase.h" - + ASYN_XXX_ARRAY_BASE_FUNCS(asynInt32Array, asynInt32ArrayType, asynInt32ArrayBase, pasynInt32ArrayBase, asynInt32ArrayInterrupt, interruptCallbackInt32Array, epicsInt32) diff --git a/asyn/interfaces/asynInt32ArraySyncIO.c b/asyn/interfaces/asynInt32ArraySyncIO.c index e82308f..fff11df 100644 --- a/asyn/interfaces/asynInt32ArraySyncIO.c +++ b/asyn/interfaces/asynInt32ArraySyncIO.c @@ -19,8 +19,6 @@ #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynInt32Array.h" #include "asynDrvUser.h" @@ -53,8 +51,8 @@ static asynInt32ArraySyncIO interface = { writeOpOnce, readOpOnce }; -epicsShareDef asynInt32ArraySyncIO *pasynInt32ArraySyncIO = &interface; - +asynInt32ArraySyncIO *pasynInt32ArraySyncIO = &interface; + static asynStatus connect(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo) { @@ -67,7 +65,7 @@ static asynStatus connect(const char *port, int addr, pasynUser = pasynManager->createAsynUser(0,0); pasynUser->userPvt = pioPvt; *ppasynUser = pasynUser; - status = pasynManager->connectDevice(pasynUser, port, addr); + status = pasynManager->connectDevice(pasynUser, port, addr); if (status != asynSuccess) { return status; } @@ -106,7 +104,7 @@ static asynStatus connect(const char *port, int addr, } return asynSuccess ; } - + static asynStatus disconnect(asynUser *pasynUser) { ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; @@ -125,7 +123,7 @@ static asynStatus disconnect(asynUser *pasynUser) free(pioPvt); return asynSuccess; } - + static asynStatus writeOp(asynUser *pasynUser,epicsInt32 *pvalue,size_t nelem,double timeout) { asynStatus status, unlockStatus; @@ -138,7 +136,7 @@ static asynStatus writeOp(asynUser *pasynUser,epicsInt32 *pvalue,size_t nelem,do } status = pPvt->pasynInt32Array->write(pPvt->int32ArrayPvt, pasynUser,pvalue,nelem); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynInt32ArraySyncIO wrote: %d\n", *pvalue); } @@ -161,7 +159,7 @@ static asynStatus readOp(asynUser *pasynUser,epicsInt32 *pvalue,size_t nelem,siz } status = pPvt->pasynInt32Array->read(pPvt->int32ArrayPvt, pasynUser, pvalue, nelem, nIn); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynInt32ArraySyncIO read: %d\n", *pvalue); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -170,7 +168,7 @@ static asynStatus readOp(asynUser *pasynUser,epicsInt32 *pvalue,size_t nelem,siz } return status; } - + static asynStatus writeOpOnce(const char *port, int addr, epicsInt32 *pvalue,size_t nelem,double timeout,const char *drvInfo) { diff --git a/asyn/interfaces/asynInt32ArraySyncIO.h b/asyn/interfaces/asynInt32ArraySyncIO.h index ed4f04c..3060adf 100644 --- a/asyn/interfaces/asynInt32ArraySyncIO.h +++ b/asyn/interfaces/asynInt32ArraySyncIO.h @@ -16,7 +16,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -24,7 +23,7 @@ extern "C" { #define asynInt32ArraySyncIOType "asynInt32ArraySyncIO" typedef struct asynInt32ArraySyncIO { - asynStatus (*connect)(const char *port, int addr, + asynStatus (*connect)(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo); asynStatus (*disconnect)(asynUser *pasynUser); asynStatus (*write)(asynUser *pasynUser,epicsInt32 *pvalue,size_t nelem,double timeout); @@ -34,7 +33,7 @@ typedef struct asynInt32ArraySyncIO { asynStatus (*readOnce)(const char *port, int addr, epicsInt32 *pvalue,size_t nelem,size_t *nIn,double timeout,const char *drvInfo); } asynInt32ArraySyncIO; -epicsShareExtern asynInt32ArraySyncIO *pasynInt32ArraySyncIO; +ASYN_API extern asynInt32ArraySyncIO *pasynInt32ArraySyncIO; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynInt32Base.c b/asyn/interfaces/asynInt32Base.c index 87973c9..858979f 100644 --- a/asyn/interfaces/asynInt32Base.c +++ b/asyn/interfaces/asynInt32Base.c @@ -14,21 +14,19 @@ #include #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynInt32.h" static asynStatus initialize(const char *portName, asynInterface *pint32Interface); static asynInt32Base int32Base = {initialize}; -epicsShareDef asynInt32Base *pasynInt32Base = &int32Base; +asynInt32Base *pasynInt32Base = &int32Base; static asynStatus writeDefault(void *drvPvt, asynUser *pasynUser, epicsInt32 value); static asynStatus readDefault(void *drvPvt, asynUser *pasynUser, epicsInt32 *value); -static asynStatus getBounds(void *drvPvt, asynUser *pasynUser, +static asynStatus getBounds(void *drvPvt, asynUser *pasynUser, epicsInt32 *low, epicsInt32 *high); static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, interruptCallbackInt32 callback, void *userPvt, @@ -36,7 +34,7 @@ static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, static asynStatus cancelInterruptUser(void *drvPvt, asynUser *pasynUser, void *registrarPvt); - + asynStatus initialize(const char *portName, asynInterface *pdriver) { asynInt32 *pasynInt32 = (asynInt32 *)pdriver->pinterface; @@ -57,7 +55,7 @@ static asynStatus writeDefault(void *drvPvt, asynUser *pasynUser, const char *portName; asynStatus status; int addr; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -75,7 +73,7 @@ static asynStatus readDefault(void *drvPvt, asynUser *pasynUser, const char *portName; asynStatus status; int addr; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -87,13 +85,13 @@ static asynStatus readDefault(void *drvPvt, asynUser *pasynUser, return asynError; } -static asynStatus getBounds(void *drvPvt, asynUser *pasynUser, +static asynStatus getBounds(void *drvPvt, asynUser *pasynUser, epicsInt32 *low, epicsInt32 *high) { const char *portName; asynStatus status; int addr; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -103,7 +101,7 @@ static asynStatus getBounds(void *drvPvt, asynUser *pasynUser, "%s %d getBounds setting low=high=0\n",portName,addr); return asynSuccess; } - + static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, interruptCallbackInt32 callback, void *userPvt, void **registrarPvt) @@ -114,18 +112,18 @@ static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, interruptNode *pinterruptNode; void *pinterruptPvt; asynInt32Interrupt *pasynInt32Interrupt; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); if(status!=asynSuccess) return status; - status = pasynManager->getInterruptPvt(pasynUser, asynInt32Type, + status = pasynManager->getInterruptPvt(pasynUser, asynInt32Type, &pinterruptPvt); if(status!=asynSuccess) return status; pasynInt32Interrupt = pasynManager->memMalloc(sizeof(asynInt32Interrupt)); pinterruptNode = pasynManager->createInterruptNode(pinterruptPvt); pinterruptNode->drvPvt = pasynInt32Interrupt; - pasynInt32Interrupt->pasynUser = + pasynInt32Interrupt->pasynUser = pasynManager->duplicateAsynUser(pasynUser, NULL, NULL); pasynInt32Interrupt->addr = addr; pasynInt32Interrupt->callback = callback; @@ -140,12 +138,12 @@ static asynStatus cancelInterruptUser(void *drvPvt, asynUser *pasynUser, void *registrarPvt) { interruptNode *pinterruptNode = (interruptNode *)registrarPvt; - asynInt32Interrupt *pasynInt32Interrupt = + asynInt32Interrupt *pasynInt32Interrupt = (asynInt32Interrupt *)pinterruptNode->drvPvt; asynStatus status; const char *portName; int addr; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); diff --git a/asyn/interfaces/asynInt32SyncIO.c b/asyn/interfaces/asynInt32SyncIO.c index 370510c..1b39de0 100644 --- a/asyn/interfaces/asynInt32SyncIO.c +++ b/asyn/interfaces/asynInt32SyncIO.c @@ -19,8 +19,6 @@ #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynInt32.h" #include "asynDrvUser.h" @@ -59,8 +57,8 @@ static asynInt32SyncIO interface = { readOpOnce, getBoundsOnce }; -epicsShareDef asynInt32SyncIO *pasynInt32SyncIO = &interface; - +asynInt32SyncIO *pasynInt32SyncIO = &interface; + static asynStatus connect(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo) { @@ -73,7 +71,7 @@ static asynStatus connect(const char *port, int addr, pasynUser = pasynManager->createAsynUser(0,0); pasynUser->userPvt = pioPvt; *ppasynUser = pasynUser; - status = pasynManager->connectDevice(pasynUser, port, addr); + status = pasynManager->connectDevice(pasynUser, port, addr); if (status != asynSuccess) { return status; } @@ -112,7 +110,7 @@ static asynStatus connect(const char *port, int addr, } return asynSuccess ; } - + static asynStatus disconnect(asynUser *pasynUser) { ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; @@ -131,7 +129,7 @@ static asynStatus disconnect(asynUser *pasynUser) free(pioPvt); return asynSuccess; } - + static asynStatus writeOp(asynUser *pasynUser, epicsInt32 value,double timeout) { @@ -145,7 +143,7 @@ static asynStatus writeOp(asynUser *pasynUser, epicsInt32 value,double timeout) } status = pioPvt->pasynInt32->write(pioPvt->int32Pvt, pasynUser, value); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynInt32SyncIO wrote: %d\n", value); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -167,7 +165,7 @@ static asynStatus readOp(asynUser *pasynUser, epicsInt32 *pvalue, double timeout } status = pioPvt->pasynInt32->read(pioPvt->int32Pvt, pasynUser, pvalue); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynInt32SyncIO read: %d\n", *pvalue); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -176,7 +174,7 @@ static asynStatus readOp(asynUser *pasynUser, epicsInt32 *pvalue, double timeout } return(status); } - + static asynStatus getBounds(asynUser *pasynUser, epicsInt32 *plow, epicsInt32 *phigh) { @@ -188,7 +186,7 @@ static asynStatus getBounds(asynUser *pasynUser, return status; } status = pioPvt->pasynInt32->getBounds(pioPvt->int32Pvt,pasynUser,plow,phigh); - asynPrint(pasynUser, ASYN_TRACE_FLOW, + asynPrint(pasynUser, ASYN_TRACE_FLOW, "asynInt32SyncIO getBounds: status=%d low %d high %d\n", status, *plow,*phigh); unlockStatus = pasynManager->queueUnlockPort(pasynUser); diff --git a/asyn/interfaces/asynInt32SyncIO.h b/asyn/interfaces/asynInt32SyncIO.h index e63ff76..32d996f 100644 --- a/asyn/interfaces/asynInt32SyncIO.h +++ b/asyn/interfaces/asynInt32SyncIO.h @@ -16,7 +16,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -24,12 +23,12 @@ extern "C" { #define asynInt32SyncIOType "asynInt32SyncIO" typedef struct asynInt32SyncIO { - asynStatus (*connect)(const char *port, int addr, + asynStatus (*connect)(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo); asynStatus (*disconnect)(asynUser *pasynUser); asynStatus (*write)(asynUser *pasynUser, epicsInt32 value,double timeout); asynStatus (*read)(asynUser *pasynUser, epicsInt32 *pvalue,double timeout); - asynStatus (*getBounds)(asynUser *pasynUser, + asynStatus (*getBounds)(asynUser *pasynUser, epicsInt32 *plow, epicsInt32 *phigh); asynStatus (*writeOnce)(const char *port, int addr, epicsInt32 value,double timeout, const char *drvInfo); @@ -38,7 +37,7 @@ typedef struct asynInt32SyncIO { asynStatus (*getBoundsOnce)(const char *port, int addr, epicsInt32 *plow, epicsInt32 *phigh,const char *drvInfo); } asynInt32SyncIO; -epicsShareExtern asynInt32SyncIO *pasynInt32SyncIO; +ASYN_API extern asynInt32SyncIO *pasynInt32SyncIO; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynInt64.h b/asyn/interfaces/asynInt64.h new file mode 100644 index 0000000..c8333bc --- /dev/null +++ b/asyn/interfaces/asynInt64.h @@ -0,0 +1,64 @@ +/* asynInt64.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. +***********************************************************************/ + +/* 28-June-2004 Mark Rivers +*/ + +#ifndef asynInt64H +#define asynInt64H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef void (*interruptCallbackInt64)(void *userPvt, asynUser *pasynUser, + epicsInt64 data); +typedef struct asynInt64Interrupt { + int addr; + asynUser *pasynUser; + interruptCallbackInt64 callback; + void *userPvt; +} asynInt64Interrupt; +#define asynInt64Type "asynInt64" +typedef struct asynInt64 { + asynStatus (*write)(void *drvPvt, asynUser *pasynUser, epicsInt64 value); + asynStatus (*read)(void *drvPvt, asynUser *pasynUser, epicsInt64 *value); + asynStatus (*getBounds)(void *drvPvt, asynUser *pasynUser, + epicsInt64 *low, epicsInt64 *high); + asynStatus (*registerInterruptUser)(void *drvPvt,asynUser *pasynUser, + interruptCallbackInt64 callback, void *userPvt, + void **registrarPvt); + asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser, + void *registrarPvt); +} asynInt64; + +/* asynInt64Base does the following: + calls registerInterface for asynInt64. + Implements registerInterruptUser and cancelInterruptUser + Provides default implementations of all methods. + registerInterruptUser and cancelInterruptUser can be called + directly rather than via queueRequest. +*/ + +#define asynInt64BaseType "asynInt64Base" +typedef struct asynInt64Base { + asynStatus (*initialize)(const char *portName, + asynInterface *pint64Interface); +} asynInt64Base; +ASYN_API extern asynInt64Base *pasynInt64Base; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* asynInt64H */ diff --git a/asyn/interfaces/asynInt64Array.h b/asyn/interfaces/asynInt64Array.h new file mode 100644 index 0000000..e765ddc --- /dev/null +++ b/asyn/interfaces/asynInt64Array.h @@ -0,0 +1,58 @@ +/* asynInt64Array.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. +***********************************************************************/ + +/* 28-June-2004 Mark Rivers + +*/ + +#ifndef asynInt64ArrayH +#define asynInt64ArrayH + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef void (*interruptCallbackInt64Array)( + void *userPvt, asynUser *pasynUser, + epicsInt64 *value, size_t nelements); +typedef struct asynInt64ArrayInterrupt { + asynUser *pasynUser; + int addr; + interruptCallbackInt64Array callback; + void *userPvt; +} asynInt64ArrayInterrupt; +#define asynInt64ArrayType "asynInt64Array" +typedef struct asynInt64Array { + asynStatus (*write)(void *drvPvt, asynUser *pasynUser, + epicsInt64 *value, size_t nelements); + asynStatus (*read)(void *drvPvt, asynUser *pasynUser, + epicsInt64 *value, size_t nelements, size_t *nIn); + asynStatus (*registerInterruptUser)(void *drvPvt, asynUser *pasynUser, + interruptCallbackInt64Array callback, void *userPvt, + void **registrarPvt); + asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser, + void *registrarPvt); +} asynInt64Array; + +#define asynInt64ArrayBaseType "asynInt64ArrayBase" +typedef struct asynInt64ArrayBase { + asynStatus (*initialize)(const char *portName, + asynInterface *pint64ArrayInterface); +} asynInt64ArrayBase; +ASYN_API extern asynInt64ArrayBase *pasynInt64ArrayBase; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* asynInt64ArrayH */ diff --git a/asyn/interfaces/asynInt64ArrayBase.c b/asyn/interfaces/asynInt64ArrayBase.c new file mode 100644 index 0000000..a9a9152 --- /dev/null +++ b/asyn/interfaces/asynInt64ArrayBase.c @@ -0,0 +1,25 @@ +/* asynInt64ArrayBase.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. +***********************************************************************/ + +/* 11-OCT-2004 Marty Kraimer + * 26-MAR-2008 Mark Rivers, converted to use macro +*/ + +#include +#include + +#include "asynDriver.h" +#include "asynInt64Array.h" + +#include "asynXXXArrayBase.h" + +ASYN_XXX_ARRAY_BASE_FUNCS(asynInt64Array, asynInt64ArrayType, asynInt64ArrayBase, pasynInt64ArrayBase, + asynInt64ArrayInterrupt, interruptCallbackInt64Array, epicsInt64) + diff --git a/asyn/interfaces/asynInt64ArraySyncIO.c b/asyn/interfaces/asynInt64ArraySyncIO.c new file mode 100644 index 0000000..9fc53a5 --- /dev/null +++ b/asyn/interfaces/asynInt64ArraySyncIO.c @@ -0,0 +1,216 @@ +/*asynInt64ArraySyncIO.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. +***********************************************************************/ +/* + * This package provide a simple, synchronous interface to asynInt64Array + * Author: Mark Rivers + * Created: 13APR2008 + */ + +#include +#include +#include + +#include + +#include "asynDriver.h" +#include "asynInt64Array.h" +#include "asynDrvUser.h" +#include "asynInt64ArraySyncIO.h" + +typedef struct ioPvt{ + asynCommon *pasynCommon; + void *pcommonPvt; + asynInt64Array *pasynInt64Array; + void *int64ArrayPvt; + asynDrvUser *pasynDrvUser; + void *drvUserPvt; +}ioPvt; + +/*asynInt64ArraySyncIO methods*/ +static asynStatus connect(const char *port, int addr, + asynUser **ppasynUser, const char *drvInfo); +static asynStatus disconnect(asynUser *pasynUser); +static asynStatus writeOp(asynUser *pasynUser,epicsInt64 *pvalue,size_t nelem,double timeout); +static asynStatus readOp(asynUser *pasynUser,epicsInt64 *pvalue,size_t nelem,size_t *nIn,double timeout); +static asynStatus writeOpOnce(const char *port, int addr, + epicsInt64 *pvalue, size_t nelem, double timeout, const char *drvInfo); +static asynStatus readOpOnce(const char *port, int addr, + epicsInt64 *pvalue,size_t nelem, size_t *nIn, double timeout, const char *drvInfo); +static asynInt64ArraySyncIO interface = { + connect, + disconnect, + writeOp, + readOp, + writeOpOnce, + readOpOnce +}; +asynInt64ArraySyncIO *pasynInt64ArraySyncIO = &interface; + +static asynStatus connect(const char *port, int addr, + asynUser **ppasynUser, const char *drvInfo) +{ + ioPvt *pioPvt; + asynUser *pasynUser; + asynStatus status; + asynInterface *pasynInterface; + + pioPvt = (ioPvt *)callocMustSucceed(1, sizeof(ioPvt),"asynInt64ArraySyncIO"); + pasynUser = pasynManager->createAsynUser(0,0); + pasynUser->userPvt = pioPvt; + *ppasynUser = pasynUser; + status = pasynManager->connectDevice(pasynUser, port, addr); + if (status != asynSuccess) { + return status; + } + pasynInterface = pasynManager->findInterface(pasynUser, asynCommonType, 1); + if (!pasynInterface) { + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "interface %s is not supported by port",asynCommonType); + return asynError; + } + pioPvt->pasynCommon = (asynCommon *)pasynInterface->pinterface; + pioPvt->pcommonPvt = pasynInterface->drvPvt; + pasynInterface = pasynManager->findInterface(pasynUser, asynInt64ArrayType, 1); + if (!pasynInterface) { + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "interface %s is not supported by port",asynInt64ArrayType); + return asynError; + } + pioPvt->pasynInt64Array = (asynInt64Array *)pasynInterface->pinterface; + pioPvt->int64ArrayPvt = pasynInterface->drvPvt; + if(drvInfo) { + /* Check for asynDrvUser interface */ + pasynInterface = pasynManager->findInterface(pasynUser,asynDrvUserType,1); + if(pasynInterface) { + asynDrvUser *pasynDrvUser; + void *drvPvt; + pasynDrvUser = (asynDrvUser *)pasynInterface->pinterface; + drvPvt = pasynInterface->drvPvt; + status = pasynDrvUser->create(drvPvt,pasynUser,drvInfo,0,0); + if(status==asynSuccess) { + pioPvt->pasynDrvUser = pasynDrvUser; + pioPvt->drvUserPvt = drvPvt; + } else { + return status; + } + } + } + return asynSuccess ; +} + +static asynStatus disconnect(asynUser *pasynUser) +{ + ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; + asynStatus status; + + if(pioPvt->pasynDrvUser) { + status = pioPvt->pasynDrvUser->destroy(pioPvt->drvUserPvt,pasynUser); + if(status!=asynSuccess) { + return status; + } + } + status = pasynManager->freeAsynUser(pasynUser); + if(status!=asynSuccess) { + return status; + } + free(pioPvt); + return asynSuccess; +} + +static asynStatus writeOp(asynUser *pasynUser,epicsInt64 *pvalue,size_t nelem,double timeout) +{ + asynStatus status, unlockStatus; + ioPvt *pPvt = (ioPvt *)pasynUser->userPvt; + + pasynUser->timeout = timeout; + status = pasynManager->queueLockPort(pasynUser); + if(status!=asynSuccess) { + return status; + } + status = pPvt->pasynInt64Array->write(pPvt->int64ArrayPvt, pasynUser,pvalue,nelem); + if (status==asynSuccess) { + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + "asynInt64ArraySyncIO wrote: %lld\n", + *pvalue); + } + unlockStatus = pasynManager->queueUnlockPort(pasynUser); + if (unlockStatus != asynSuccess) { + return unlockStatus; + } + return status; +} + +static asynStatus readOp(asynUser *pasynUser,epicsInt64 *pvalue,size_t nelem,size_t *nIn,double timeout) +{ + ioPvt *pPvt = (ioPvt *)pasynUser->userPvt; + asynStatus status, unlockStatus; + + pasynUser->timeout = timeout; + status = pasynManager->queueLockPort(pasynUser); + if(status!=asynSuccess) { + return status; + } + status = pPvt->pasynInt64Array->read(pPvt->int64ArrayPvt, pasynUser, pvalue, nelem, nIn); + if (status==asynSuccess) { + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + "asynInt64ArraySyncIO read: %lld\n", *pvalue); + } + unlockStatus = pasynManager->queueUnlockPort(pasynUser); + if (unlockStatus != asynSuccess) { + return unlockStatus; + } + return status; +} + +static asynStatus writeOpOnce(const char *port, int addr, + epicsInt64 *pvalue,size_t nelem,double timeout,const char *drvInfo) +{ + asynStatus status; + asynUser *pasynUser; + + status = connect(port,addr,&pasynUser,drvInfo); + if(status!=asynSuccess) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, + "asynInt64ArraySyncIO connect failed %s\n", + pasynUser->errorMessage); + disconnect(pasynUser); + return status; + } + status = writeOp(pasynUser,pvalue,nelem,timeout); + if(status!=asynSuccess) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, + "asynInt64ArraySyncIO writeOp failed %s\n",pasynUser->errorMessage); + } + disconnect(pasynUser); + return status; +} + +static asynStatus readOpOnce(const char *port, int addr, + epicsInt64 *pvalue,size_t nelem,size_t *nIn,double timeout,const char *drvInfo) +{ + asynStatus status; + asynUser *pasynUser; + + status = connect(port,addr,&pasynUser,drvInfo); + if(status!=asynSuccess) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, + "asynInt64ArraySyncIO connect failed %s\n", + pasynUser->errorMessage); + disconnect(pasynUser); + return status; + } + status = readOp(pasynUser,pvalue,nelem,nIn,timeout); + if(status!=asynSuccess) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, + "asynInt64ArraySyncIO readOp failed %s\n",pasynUser->errorMessage); + } + disconnect(pasynUser); + return status; +} diff --git a/asyn/interfaces/asynInt64ArraySyncIO.h b/asyn/interfaces/asynInt64ArraySyncIO.h new file mode 100644 index 0000000..d256fbb --- /dev/null +++ b/asyn/interfaces/asynInt64ArraySyncIO.h @@ -0,0 +1,42 @@ +/* asynInt64ArraySyncIO.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. +***********************************************************************/ + +/* 28-June-2004 Mark Rivers +*/ + +#ifndef asynInt64ArraySyncIOH +#define asynInt64ArraySyncIOH + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define asynInt64ArraySyncIOType "asynInt64ArraySyncIO" +typedef struct asynInt64ArraySyncIO { + asynStatus (*connect)(const char *port, int addr, + asynUser **ppasynUser, const char *drvInfo); + asynStatus (*disconnect)(asynUser *pasynUser); + asynStatus (*write)(asynUser *pasynUser,epicsInt64 *pvalue,size_t nelem,double timeout); + asynStatus (*read)(asynUser *pasynUser,epicsInt64 *pvalue,size_t nelem,size_t *Nin,double timeout); + asynStatus (*writeOnce)(const char *port, int addr, + epicsInt64 *pvalue,size_t nelem,double timeout,const char *drvInfo); + asynStatus (*readOnce)(const char *port, int addr, + epicsInt64 *pvalue,size_t nelem,size_t *nIn,double timeout,const char *drvInfo); +} asynInt64ArraySyncIO; +ASYN_API extern asynInt64ArraySyncIO *pasynInt64ArraySyncIO; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* asynInt64ArraySyncIOH */ diff --git a/asyn/interfaces/asynInt64Base.c b/asyn/interfaces/asynInt64Base.c new file mode 100644 index 0000000..84762b9 --- /dev/null +++ b/asyn/interfaces/asynInt64Base.c @@ -0,0 +1,159 @@ +/* asynInt64Base.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. +***********************************************************************/ + +/* 11-OCT-2004 Marty Kraimer +*/ + +#include +#include + +#include "asynDriver.h" +#include "asynInt64.h" + +static asynStatus initialize(const char *portName, asynInterface *pint64Interface); + +static asynInt64Base int64Base = {initialize}; +asynInt64Base *pasynInt64Base = &int64Base; + +static asynStatus writeDefault(void *drvPvt, asynUser *pasynUser, + epicsInt64 value); +static asynStatus readDefault(void *drvPvt, asynUser *pasynUser, + epicsInt64 *value); +static asynStatus getBounds(void *drvPvt, asynUser *pasynUser, + epicsInt64 *low, epicsInt64 *high); +static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, + interruptCallbackInt64 callback, void *userPvt, + void **registrarPvt); +static asynStatus cancelInterruptUser(void *drvPvt, asynUser *pasynUser, + void *registrarPvt); + + +asynStatus initialize(const char *portName, asynInterface *pdriver) +{ + asynInt64 *pasynInt64 = (asynInt64 *)pdriver->pinterface; + + if(!pasynInt64->write) pasynInt64->write = writeDefault; + if(!pasynInt64->read) pasynInt64->read = readDefault; + if(!pasynInt64->getBounds) pasynInt64->getBounds = getBounds; + if(!pasynInt64->registerInterruptUser) + pasynInt64->registerInterruptUser = registerInterruptUser; + if(!pasynInt64->cancelInterruptUser) + pasynInt64->cancelInterruptUser = cancelInterruptUser; + return pasynManager->registerInterface(portName,pdriver); +} + +static asynStatus writeDefault(void *drvPvt, asynUser *pasynUser, + epicsInt64 value) +{ + const char *portName; + asynStatus status; + int addr; + + status = pasynManager->getPortName(pasynUser,&portName); + if(status!=asynSuccess) return status; + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "write is not supported"); + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s %d write is not supported\n",portName,addr); + return asynError; +} + +static asynStatus readDefault(void *drvPvt, asynUser *pasynUser, + epicsInt64 *value) +{ + const char *portName; + asynStatus status; + int addr; + + status = pasynManager->getPortName(pasynUser,&portName); + if(status!=asynSuccess) return status; + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "write is not supported"); + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s %d read is not supported\n",portName,addr); + return asynError; +} + +static asynStatus getBounds(void *drvPvt, asynUser *pasynUser, + epicsInt64 *low, epicsInt64 *high) +{ + const char *portName; + asynStatus status; + int addr; + + status = pasynManager->getPortName(pasynUser,&portName); + if(status!=asynSuccess) return status; + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + *low = *high = 0; + asynPrint(pasynUser,ASYN_TRACE_FLOW, + "%s %d getBounds setting low=high=0\n",portName,addr); + return asynSuccess; +} + +static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, + interruptCallbackInt64 callback, void *userPvt, + void **registrarPvt) +{ + const char *portName; + asynStatus status; + int addr; + interruptNode *pinterruptNode; + void *pinterruptPvt; + asynInt64Interrupt *pasynInt64Interrupt; + + status = pasynManager->getPortName(pasynUser,&portName); + if(status!=asynSuccess) return status; + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + status = pasynManager->getInterruptPvt(pasynUser, asynInt64Type, + &pinterruptPvt); + if(status!=asynSuccess) return status; + pasynInt64Interrupt = pasynManager->memMalloc(sizeof(asynInt64Interrupt)); + pinterruptNode = pasynManager->createInterruptNode(pinterruptPvt); + pinterruptNode->drvPvt = pasynInt64Interrupt; + pasynInt64Interrupt->pasynUser = + pasynManager->duplicateAsynUser(pasynUser, NULL, NULL); + pasynInt64Interrupt->addr = addr; + pasynInt64Interrupt->callback = callback; + pasynInt64Interrupt->userPvt = userPvt; + *registrarPvt = pinterruptNode; + asynPrint(pasynUser,ASYN_TRACE_FLOW, + "%s %d registerInterruptUser\n",portName,addr); + return pasynManager->addInterruptUser(pasynUser,pinterruptNode); +} + +static asynStatus cancelInterruptUser(void *drvPvt, asynUser *pasynUser, + void *registrarPvt) +{ + interruptNode *pinterruptNode = (interruptNode *)registrarPvt; + asynInt64Interrupt *pasynInt64Interrupt = + (asynInt64Interrupt *)pinterruptNode->drvPvt; + asynStatus status; + const char *portName; + int addr; + + status = pasynManager->getPortName(pasynUser,&portName); + if(status!=asynSuccess) return status; + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + asynPrint(pasynUser,ASYN_TRACE_FLOW, + "%s %d cancelInterruptUser\n",portName,addr); + status = pasynManager->removeInterruptUser(pasynUser,pinterruptNode); + if(status==asynSuccess) + pasynManager->freeInterruptNode(pasynUser, pinterruptNode); + pasynManager->freeAsynUser(pasynInt64Interrupt->pasynUser); + pasynManager->memFree(pasynInt64Interrupt, sizeof(asynInt64Interrupt)); + return status; +} diff --git a/asyn/interfaces/asynInt64SyncIO.c b/asyn/interfaces/asynInt64SyncIO.c new file mode 100644 index 0000000..186541c --- /dev/null +++ b/asyn/interfaces/asynInt64SyncIO.c @@ -0,0 +1,266 @@ +/*asynInt64SyncIO.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. +***********************************************************************/ +/* + * This package provide a simple, synchronous interface to asynInt64 + * Author: Marty Kraimer + * Created: 12OCT2004 + */ + +#include +#include +#include + +#include + +#include "asynDriver.h" +#include "asynInt64.h" +#include "asynDrvUser.h" +#include "asynInt64SyncIO.h" + +typedef struct ioPvt{ + asynCommon *pasynCommon; + void *pcommonPvt; + asynInt64 *pasynInt64; + void *int64Pvt; + asynDrvUser *pasynDrvUser; + void *drvUserPvt; +}ioPvt; + +/*asynInt64SyncIO methods*/ +static asynStatus connect(const char *port, int addr, + asynUser **ppasynUser, const char *drvInfo); +static asynStatus disconnect(asynUser *pasynUser); +static asynStatus writeOp(asynUser *pasynUser, epicsInt64 value,double timeout); +static asynStatus readOp(asynUser *pasynUser,epicsInt64 *pvalue,double timeout); +static asynStatus getBounds(asynUser *pasynUser, + epicsInt64 *plow, epicsInt64 *phigh); +static asynStatus writeOpOnce(const char *port, int addr, + epicsInt64 value,double timeout,const char *drvInfo); +static asynStatus readOpOnce(const char *port, int addr, + epicsInt64 *pvalue,double timeout,const char *drvInfo); +static asynStatus getBoundsOnce(const char *port, int addr, + epicsInt64 *plow, epicsInt64 *phigh,const char *drvInfo); +static asynInt64SyncIO interface = { + connect, + disconnect, + writeOp, + readOp, + getBounds, + writeOpOnce, + readOpOnce, + getBoundsOnce +}; +asynInt64SyncIO *pasynInt64SyncIO = &interface; + +static asynStatus connect(const char *port, int addr, + asynUser **ppasynUser, const char *drvInfo) +{ + ioPvt *pioPvt; + asynUser *pasynUser; + asynStatus status; + asynInterface *pasynInterface; + + pioPvt = (ioPvt *)callocMustSucceed(1, sizeof(ioPvt),"asynInt64SyncIO"); + pasynUser = pasynManager->createAsynUser(0,0); + pasynUser->userPvt = pioPvt; + *ppasynUser = pasynUser; + status = pasynManager->connectDevice(pasynUser, port, addr); + if (status != asynSuccess) { + return status; + } + pasynInterface = pasynManager->findInterface(pasynUser, asynCommonType, 1); + if (!pasynInterface) { + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "port does not implement interface %s",asynCommonType); + return asynError; + } + pioPvt->pasynCommon = (asynCommon *)pasynInterface->pinterface; + pioPvt->pcommonPvt = pasynInterface->drvPvt; + pasynInterface = pasynManager->findInterface(pasynUser, asynInt64Type, 1); + if (!pasynInterface) { + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "port does not implement interface %s",asynInt64Type); + return asynError; + } + pioPvt->pasynInt64 = (asynInt64 *)pasynInterface->pinterface; + pioPvt->int64Pvt = pasynInterface->drvPvt; + if(drvInfo) { + /* Check for asynDrvUser interface */ + pasynInterface = pasynManager->findInterface(pasynUser,asynDrvUserType,1); + if(pasynInterface) { + asynDrvUser *pasynDrvUser; + void *drvPvt; + pasynDrvUser = (asynDrvUser *)pasynInterface->pinterface; + drvPvt = pasynInterface->drvPvt; + status = pasynDrvUser->create(drvPvt,pasynUser,drvInfo,0,0); + if(status==asynSuccess) { + pioPvt->pasynDrvUser = pasynDrvUser; + pioPvt->drvUserPvt = drvPvt; + } else { + return status; + } + } + } + return asynSuccess ; +} + +static asynStatus disconnect(asynUser *pasynUser) +{ + ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; + asynStatus status; + + if(pioPvt->pasynDrvUser) { + status = pioPvt->pasynDrvUser->destroy(pioPvt->drvUserPvt,pasynUser); + if(status!=asynSuccess) { + return status; + } + } + status = pasynManager->freeAsynUser(pasynUser); + if(status!=asynSuccess) { + return status; + } + free(pioPvt); + return asynSuccess; +} + + +static asynStatus writeOp(asynUser *pasynUser, epicsInt64 value,double timeout) +{ + asynStatus status, unlockStatus; + ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; + + pasynUser->timeout = timeout; + status = pasynManager->queueLockPort(pasynUser); + if(status!=asynSuccess) { + return status; + } + status = pioPvt->pasynInt64->write(pioPvt->int64Pvt, pasynUser, value); + if (status==asynSuccess) { + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + "asynInt64SyncIO wrote: %lld\n", value); + } + unlockStatus = pasynManager->queueUnlockPort(pasynUser); + if (unlockStatus != asynSuccess) { + return unlockStatus; + } + return(status); +} + +static asynStatus readOp(asynUser *pasynUser, epicsInt64 *pvalue, double timeout) +{ + ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; + asynStatus status, unlockStatus; + + pasynUser->timeout = timeout; + status = pasynManager->queueLockPort(pasynUser); + if(status!=asynSuccess) { + return status; + } + status = pioPvt->pasynInt64->read(pioPvt->int64Pvt, pasynUser, pvalue); + if (status==asynSuccess) { + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + "asynInt64SyncIO read: %lld\n", *pvalue); + } + unlockStatus = pasynManager->queueUnlockPort(pasynUser); + if (unlockStatus != asynSuccess) { + return unlockStatus; + } + return(status); +} + +static asynStatus getBounds(asynUser *pasynUser, + epicsInt64 *plow, epicsInt64 *phigh) +{ + ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; + asynStatus status, unlockStatus; + + status = pasynManager->queueLockPort(pasynUser); + if(status!=asynSuccess) { + return status; + } + status = pioPvt->pasynInt64->getBounds(pioPvt->int64Pvt,pasynUser,plow,phigh); + asynPrint(pasynUser, ASYN_TRACE_FLOW, + "asynInt64SyncIO getBounds: status=%d low %lld high %lld\n", + status, *plow,*phigh); + unlockStatus = pasynManager->queueUnlockPort(pasynUser); + if (unlockStatus != asynSuccess) { + return unlockStatus; + } + return(status); +} + +static asynStatus writeOpOnce(const char *port, int addr, + epicsInt64 value,double timeout,const char *drvInfo) +{ + asynStatus status; + asynUser *pasynUser; + + status = connect(port,addr,&pasynUser,drvInfo); + if(status!=asynSuccess) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, + "asynInt64SyncIO connect failed %s\n", + pasynUser->errorMessage); + disconnect(pasynUser); + return status; + } + status = writeOp(pasynUser,value,timeout); + if(status!=asynSuccess) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, + "asynInt64SyncIO writeOp failed %s\n",pasynUser->errorMessage); + } + disconnect(pasynUser); + return status; +} + +static asynStatus readOpOnce(const char *port, int addr, + epicsInt64 *pvalue,double timeout,const char *drvInfo) +{ + asynStatus status; + asynUser *pasynUser; + + status = connect(port,addr,&pasynUser,drvInfo); + if(status!=asynSuccess) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, + "asynInt64SyncIO connect failed %s\n", + pasynUser->errorMessage); + disconnect(pasynUser); + return status; + } + status = readOp(pasynUser,pvalue,timeout); + if(status!=asynSuccess) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, + "asynInt64SyncIO readOp failed %s\n",pasynUser->errorMessage); + } + disconnect(pasynUser); + return status; +} + +static asynStatus getBoundsOnce(const char *port, int addr, + epicsInt64 *plow, epicsInt64 *phigh,const char *drvInfo) +{ + asynStatus status; + asynUser *pasynUser; + + status = connect(port,addr,&pasynUser,drvInfo); + if(status!=asynSuccess) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, + "asynInt64SyncIO connect failed %s\n", + pasynUser->errorMessage); + disconnect(pasynUser); + return status; + } + status = getBounds(pasynUser,plow,phigh); + if(status!=asynSuccess) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, + "asynInt64SyncIO getBounds failed %s\n",pasynUser->errorMessage); + } + disconnect(pasynUser); + return(status); +} diff --git a/asyn/interfaces/asynInt64SyncIO.h b/asyn/interfaces/asynInt64SyncIO.h new file mode 100644 index 0000000..de262ea --- /dev/null +++ b/asyn/interfaces/asynInt64SyncIO.h @@ -0,0 +1,46 @@ +/* asynInt64SyncIO.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. +***********************************************************************/ + +/* 28-June-2004 Mark Rivers +*/ + +#ifndef asynInt64SyncIOH +#define asynInt64SyncIOH + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define asynInt64SyncIOType "asynInt64SyncIO" +typedef struct asynInt64SyncIO { + asynStatus (*connect)(const char *port, int addr, + asynUser **ppasynUser, const char *drvInfo); + asynStatus (*disconnect)(asynUser *pasynUser); + asynStatus (*write)(asynUser *pasynUser, epicsInt64 value,double timeout); + asynStatus (*read)(asynUser *pasynUser, epicsInt64 *pvalue,double timeout); + asynStatus (*getBounds)(asynUser *pasynUser, + epicsInt64 *plow, epicsInt64 *phigh); + asynStatus (*writeOnce)(const char *port, int addr, + epicsInt64 value,double timeout, const char *drvInfo); + asynStatus (*readOnce)(const char *port, int addr, + epicsInt64 *pvalue,double timeout, const char *drvInfo); + asynStatus (*getBoundsOnce)(const char *port, int addr, + epicsInt64 *plow, epicsInt64 *phigh,const char *drvInfo); +} asynInt64SyncIO; +ASYN_API extern asynInt64SyncIO *pasynInt64SyncIO; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* asynInt64SyncIOH */ diff --git a/asyn/interfaces/asynInt8Array.h b/asyn/interfaces/asynInt8Array.h index 9489eb2..06bdce7 100644 --- a/asyn/interfaces/asynInt8Array.h +++ b/asyn/interfaces/asynInt8Array.h @@ -17,7 +17,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -50,7 +49,7 @@ typedef struct asynInt8ArrayBase { asynStatus (*initialize)(const char *portName, asynInterface *pint8ArrayInterface); } asynInt8ArrayBase; -epicsShareExtern asynInt8ArrayBase *pasynInt8ArrayBase; +ASYN_API extern asynInt8ArrayBase *pasynInt8ArrayBase; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynInt8ArrayBase.c b/asyn/interfaces/asynInt8ArrayBase.c index a43f707..9e51583 100644 --- a/asyn/interfaces/asynInt8ArrayBase.c +++ b/asyn/interfaces/asynInt8ArrayBase.c @@ -15,13 +15,11 @@ #include #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynInt8Array.h" #include "asynXXXArrayBase.h" - + ASYN_XXX_ARRAY_BASE_FUNCS(asynInt8Array, asynInt8ArrayType, asynInt8ArrayBase, pasynInt8ArrayBase, asynInt8ArrayInterrupt, interruptCallbackInt8Array, epicsInt8) diff --git a/asyn/interfaces/asynInt8ArraySyncIO.c b/asyn/interfaces/asynInt8ArraySyncIO.c index dc95931..449aabd 100644 --- a/asyn/interfaces/asynInt8ArraySyncIO.c +++ b/asyn/interfaces/asynInt8ArraySyncIO.c @@ -19,8 +19,6 @@ #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynInt8Array.h" #include "asynDrvUser.h" @@ -53,8 +51,8 @@ static asynInt8ArraySyncIO interface = { writeOpOnce, readOpOnce }; -epicsShareDef asynInt8ArraySyncIO *pasynInt8ArraySyncIO = &interface; - +asynInt8ArraySyncIO *pasynInt8ArraySyncIO = &interface; + static asynStatus connect(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo) { @@ -67,7 +65,7 @@ static asynStatus connect(const char *port, int addr, pasynUser = pasynManager->createAsynUser(0,0); pasynUser->userPvt = pioPvt; *ppasynUser = pasynUser; - status = pasynManager->connectDevice(pasynUser, port, addr); + status = pasynManager->connectDevice(pasynUser, port, addr); if (status != asynSuccess) { return status; } @@ -106,7 +104,7 @@ static asynStatus connect(const char *port, int addr, } return asynSuccess ; } - + static asynStatus disconnect(asynUser *pasynUser) { ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; @@ -125,7 +123,7 @@ static asynStatus disconnect(asynUser *pasynUser) free(pioPvt); return asynSuccess; } - + static asynStatus writeOp(asynUser *pasynUser,epicsInt8 *pvalue,size_t nelem,double timeout) { asynStatus status, unlockStatus; @@ -138,7 +136,7 @@ static asynStatus writeOp(asynUser *pasynUser,epicsInt8 *pvalue,size_t nelem,dou } status = pPvt->pasynInt8Array->write(pPvt->int8ArrayPvt, pasynUser,pvalue,nelem); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynInt8ArraySyncIO wrote: %d\n", *pvalue); } @@ -161,7 +159,7 @@ static asynStatus readOp(asynUser *pasynUser,epicsInt8 *pvalue,size_t nelem,size } status = pPvt->pasynInt8Array->read(pPvt->int8ArrayPvt, pasynUser, pvalue, nelem, nIn); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynInt8ArraySyncIO read: %d\n", *pvalue); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -170,7 +168,7 @@ static asynStatus readOp(asynUser *pasynUser,epicsInt8 *pvalue,size_t nelem,size } return status; } - + static asynStatus writeOpOnce(const char *port, int addr, epicsInt8 *pvalue,size_t nelem,double timeout,const char *drvInfo) { diff --git a/asyn/interfaces/asynInt8ArraySyncIO.h b/asyn/interfaces/asynInt8ArraySyncIO.h index ff5791e..3f8fb68 100644 --- a/asyn/interfaces/asynInt8ArraySyncIO.h +++ b/asyn/interfaces/asynInt8ArraySyncIO.h @@ -16,7 +16,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -24,7 +23,7 @@ extern "C" { #define asynInt8ArraySyncIOType "asynInt8ArraySyncIO" typedef struct asynInt8ArraySyncIO { - asynStatus (*connect)(const char *port, int addr, + asynStatus (*connect)(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo); asynStatus (*disconnect)(asynUser *pasynUser); asynStatus (*write)(asynUser *pasynUser,epicsInt8 *pvalue,size_t nelem,double timeout); @@ -34,7 +33,7 @@ typedef struct asynInt8ArraySyncIO { asynStatus (*readOnce)(const char *port, int addr, epicsInt8 *pvalue,size_t nelem,size_t *nIn,double timeout,const char *drvInfo); } asynInt8ArraySyncIO; -epicsShareExtern asynInt8ArraySyncIO *pasynInt8ArraySyncIO; +ASYN_API extern asynInt8ArraySyncIO *pasynInt8ArraySyncIO; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynOctet.h b/asyn/interfaces/asynOctet.h index fcbaa6d..d8d3f25 100644 --- a/asyn/interfaces/asynOctet.h +++ b/asyn/interfaces/asynOctet.h @@ -11,7 +11,6 @@ #ifndef asynOctetH #define asynOctetH -#include #ifdef __cplusplus extern "C" { @@ -54,7 +53,7 @@ typedef struct asynOctet{ asynStatus (*getOutputEos)(void *drvPvt,asynUser *pasynUser, char *eos, int eossize, int *eoslen); }asynOctet; - + /* asynOctetBase does the following: calls registerInterface for asynOctet. Implements registerInterruptUser and cancelInterruptUser @@ -71,7 +70,7 @@ typedef struct asynOctetBase { void (*callInterruptUsers)(asynUser *pasynUser,void *pasynPvt, char *data,size_t *nbytesTransfered,int *eomReason); } asynOctetBase; -epicsShareExtern asynOctetBase *pasynOctetBase; +ASYN_API extern asynOctetBase *pasynOctetBase; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynOctetBase.c b/asyn/interfaces/asynOctetBase.c index e8cd71a..57cfc9f 100644 --- a/asyn/interfaces/asynOctetBase.c +++ b/asyn/interfaces/asynOctetBase.c @@ -21,8 +21,6 @@ #include #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynInterposeEos.h" #include "asynOctet.h" @@ -41,7 +39,7 @@ typedef struct octetPvt { void *pasynPvt; /*For registerInterruptSource*/ int interruptProcess; }octetPvt; - + static void initOverride(octetPvt *poctetPvt, asynOctet *pasynOctet); static asynStatus initialize(const char *portName, @@ -52,7 +50,7 @@ static void callInterruptUsers(asynUser *pasynUser,void *pasynPvt, char *data,size_t *nbytesTransfered,int *eomReason); static asynOctetBase octetBase = {initialize,callInterruptUsers}; -epicsShareDef asynOctetBase *pasynOctetBase = &octetBase; +asynOctetBase *pasynOctetBase = &octetBase; static asynStatus writeIt(void *drvPvt, asynUser *pasynUser, const char *data,size_t numchars,size_t *nbytesTransfered); @@ -95,7 +93,7 @@ static asynStatus setOutputEosFail(void *drvPvt,asynUser *pasynUser, const char *eos,int eoslen); static asynStatus getOutputEosFail(void *drvPvt,asynUser *pasynUser, char *eos, int eossize, int *eoslen); - + static void initOverride(octetPvt *poctetPvt, asynOctet *pasynOctet) { int override = 0; @@ -120,7 +118,7 @@ static void initOverride(octetPvt *poctetPvt, asynOctet *pasynOctet) if(!pasynOctet->getOutputEos) pasynOctet->getOutputEos = getOutputEosFail; poctetPvt->override = override; } - + static asynStatus initialize(const char *portName, asynInterface *pdriver, int processEosIn,int processEosOut, @@ -174,7 +172,7 @@ static asynStatus initialize(const char *portName, } return asynSuccess; } - + static void callInterruptUsers(asynUser *pasynUser,void *pasynPvt, char *data,size_t *nbytesTransfered,int *eomReason) { @@ -188,7 +186,7 @@ static void callInterruptUsers(asynUser *pasynUser,void *pasynPvt, status = pasynManager->getAddr(pasynUser,&addr); if(status==asynSuccess) status = pasynManager->getPortName(pasynUser,&portName); - if(status==asynSuccess) + if(status==asynSuccess) status = pasynManager->interruptStart(pasynPvt,&plist); if(status!=asynSuccess) { asynPrint(pasynUser,ASYN_TRACE_ERROR, @@ -222,7 +220,7 @@ static asynStatus writeIt(void *drvPvt, asynUser *pasynUser, return pasynOctet->write(poctetPvt->drvPvt,pasynUser, data,numchars,nbytesTransfered); } - + static asynStatus readIt(void *drvPvt, asynUser *pasynUser, char *data,size_t maxchars,size_t *nbytesTransfered,int *eomReason) { @@ -244,7 +242,7 @@ static asynStatus flushIt(void *drvPvt,asynUser *pasynUser) octetPvt *poctetPvt = (octetPvt *)drvPvt; asynOctet *pasynOctet = poctetPvt->pasynOctet; double savetimeout = pasynUser->timeout; - char buffer[100]; + char buffer[100]; size_t nbytesTransfered; @@ -263,7 +261,7 @@ static asynStatus flushIt(void *drvPvt,asynUser *pasynUser) pasynUser->timeout = savetimeout; return asynSuccess; } - + static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, interruptCallbackOctet callback, void *userPvt, void **registrarPvt) { @@ -275,7 +273,7 @@ static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, interruptNode *pinterruptNode; asynOctetInterrupt *pasynOctetInterrupt; void *pinterruptPvt; - + if(!(poctetPvt->override&overrideRegisterInterruptUser)) { return pasynOctet->registerInterruptUser(poctetPvt->drvPvt,pasynUser, callback,userPvt,registrarPvt); @@ -312,7 +310,7 @@ static asynStatus cancelInterruptUser(void *drvPvt, asynUser *pasynUser, asynStatus status; const char *portName; int addr; - + if(!(poctetPvt->override&overrideCancelInterruptUser)) { return pasynOctet->cancelInterruptUser(poctetPvt->drvPvt,pasynUser, registrarPvt); @@ -330,7 +328,7 @@ static asynStatus cancelInterruptUser(void *drvPvt, asynUser *pasynUser, pasynManager->memFree(pinterrupt,sizeof(asynOctetInterrupt)); return status; } - + static asynStatus setInputEos(void *drvPvt,asynUser *pasynUser, const char *eos,int eoslen) { @@ -368,12 +366,12 @@ static asynStatus getOutputEos(void *drvPvt,asynUser *pasynUser, return pasynOctet->getOutputEos(poctetPvt->drvPvt,pasynUser, eos,eossize,eoslen); } - + static asynStatus showFailure(asynUser *pasynUser,const char *method) { const char *portName; asynStatus status; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, diff --git a/asyn/interfaces/asynOctetSyncIO.c b/asyn/interfaces/asynOctetSyncIO.c index 3d9e4f0..80c9be3 100644 --- a/asyn/interfaces/asynOctetSyncIO.c +++ b/asyn/interfaces/asynOctetSyncIO.c @@ -8,11 +8,11 @@ * found in file LICENSE that is included with this distribution. ***********************************************************************/ /* - * This package provide a simple, synchronous interface to the "asyn" package. - * It will work with any device that asyn supports, e.g. serial, GPIB, and - * TCP/IP sockets. It hides the details of asyn. It is intended for use - * by applications which do simple synchronous reads, writes and write/reads. - * It does not support port-specific control, e.g. baud rates, + * This package provide a simple, synchronous interface to the "asyn" package. + * It will work with any device that asyn supports, e.g. serial, GPIB, and + * TCP/IP sockets. It hides the details of asyn. It is intended for use + * by applications which do simple synchronous reads, writes and write/reads. + * It does not support port-specific control, e.g. baud rates, * GPIB Universal Commands, etc. * * Author: Mark Rivers @@ -25,8 +25,6 @@ #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynOctet.h" #include "asynDrvUser.h" @@ -47,9 +45,9 @@ static asynStatus connect(const char *port, int addr, static asynStatus disconnect(asynUser *pasynUser); static asynStatus writeIt(asynUser *pasynUser, char const *buffer, size_t buffer_len, double timeout,size_t *nbytesTransfered); -static asynStatus readIt(asynUser *pasynUser, char *buffer, size_t buffer_len, +static asynStatus readIt(asynUser *pasynUser, char *buffer, size_t buffer_len, double timeout, size_t *nbytesTransfered,int *eomReason); -static asynStatus writeRead(asynUser *pasynUser, +static asynStatus writeRead(asynUser *pasynUser, const char *write_buffer, size_t write_buffer_len, char *read_buffer, size_t read_buffer_len, double timeout, @@ -67,7 +65,7 @@ static asynStatus writeOnce(const char *port, int addr, char const *buffer, size_t buffer_len, double timeout, size_t *nbytesTransfered, const char *drvInfo); static asynStatus readOnce(const char *port, int addr, - char *buffer, size_t buffer_len, + char *buffer, size_t buffer_len, double timeout, size_t *nbytesTransfered,int *eomReason, const char *drvInfo); static asynStatus writeReadOnce(const char *port, int addr, @@ -106,8 +104,8 @@ static asynOctetSyncIO asynOctetSyncIOManager = { setOutputEosOnce, getOutputEosOnce }; -epicsShareDef asynOctetSyncIO *pasynOctetSyncIO = &asynOctetSyncIOManager; - +asynOctetSyncIO *pasynOctetSyncIO = &asynOctetSyncIOManager; + static asynStatus connect(const char *port, int addr, asynUser **ppasynUser,const char *drvInfo) { @@ -159,7 +157,7 @@ static asynStatus connect(const char *port, int addr, } return asynSuccess ; } - + static asynStatus disconnect(asynUser *pasynUser) { ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; @@ -179,7 +177,7 @@ static asynStatus disconnect(asynUser *pasynUser) return asynSuccess; } - + static asynStatus writeIt(asynUser *pasynUser, char const *buffer, size_t buffer_len, double timeout,size_t *nbytesTransfered) { @@ -197,7 +195,7 @@ static asynStatus writeIt(asynUser *pasynUser, asynPrintIO(pasynUser, ASYN_TRACEIO_DEVICE, buffer,buffer_len,"asynOctetSyncIO wrote:\n"); } - unlockStatus = pasynManager->queueUnlockPort(pasynUser); + unlockStatus = pasynManager->queueUnlockPort(pasynUser); if (unlockStatus != asynSuccess) { return unlockStatus; } @@ -205,7 +203,7 @@ static asynStatus writeIt(asynUser *pasynUser, } static asynStatus readIt(asynUser *pasynUser, - char *buffer, size_t buffer_len, + char *buffer, size_t buffer_len, double timeout, size_t *nbytesTransfered,int *eomReason) { @@ -230,7 +228,7 @@ static asynStatus readIt(asynUser *pasynUser, return status; } -static asynStatus writeRead(asynUser *pasynUser, +static asynStatus writeRead(asynUser *pasynUser, const char *write_buffer, size_t write_buffer_len, char *read_buffer, size_t read_buffer_len, double timeout, @@ -238,7 +236,7 @@ static asynStatus writeRead(asynUser *pasynUser, { asynStatus status, unlockStatus; ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; - + /* Set outputs to 0 in case we get an error */ *nbytesOut = 0; *nbytesIn = 0; @@ -298,7 +296,7 @@ static asynStatus } return status; } - + static asynStatus setInputEos(asynUser *pasynUser, const char *eos,int eoslen) { @@ -390,7 +388,7 @@ static asynStatus getOutputEos(asynUser *pasynUser, } return status; } - + static asynStatus writeOnce(const char *port, int addr, char const *buffer, size_t buffer_len, double timeout, size_t *nbytesTransfered,const char *drvInfo) @@ -415,7 +413,7 @@ static asynStatus writeOnce(const char *port, int addr, } static asynStatus readOnce(const char *port, int addr, - char *buffer, size_t buffer_len, + char *buffer, size_t buffer_len, double timeout, size_t *nbytesTransfered,int *eomReason,const char *drvInfo) { diff --git a/asyn/interfaces/asynOctetSyncIO.h b/asyn/interfaces/asynOctetSyncIO.h index d58cc07..68c49ff 100644 --- a/asyn/interfaces/asynOctetSyncIO.h +++ b/asyn/interfaces/asynOctetSyncIO.h @@ -19,20 +19,19 @@ #ifndef INCasynOctetSyncIOh #define INCasynOctetSyncIOh 1 -#include #include "asynDriver.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ - + typedef struct asynOctetSyncIO { asynStatus (*connect)(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo); asynStatus (*disconnect)(asynUser *pasynUser); asynStatus (*write)(asynUser *pasynUser, char const *buffer, size_t buffer_len, double timeout,size_t *nbytesTransfered); - asynStatus (*read)(asynUser *pasynUser, char *buffer, size_t buffer_len, + asynStatus (*read)(asynUser *pasynUser, char *buffer, size_t buffer_len, double timeout, size_t *nbytesTransfered,int *eomReason); asynStatus (*writeRead)(asynUser *pasynUser, const char *write_buffer, size_t write_buffer_len, @@ -70,7 +69,7 @@ typedef struct asynOctetSyncIO { asynStatus (*getOutputEosOnce)(const char *port, int addr, char *eos, int eossize, int *eoslen,const char *drvInfo); } asynOctetSyncIO; -epicsShareExtern asynOctetSyncIO *pasynOctetSyncIO; +ASYN_API extern asynOctetSyncIO *pasynOctetSyncIO; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynOption.h b/asyn/interfaces/asynOption.h index 50314a9..01b1290 100644 --- a/asyn/interfaces/asynOption.h +++ b/asyn/interfaces/asynOption.h @@ -10,7 +10,6 @@ #ifndef asynOptionH #define asynOptionH -#include #ifdef __cplusplus extern "C" { diff --git a/asyn/interfaces/asynOptionSyncIO.c b/asyn/interfaces/asynOptionSyncIO.c index 86c2f27..4ac0e57 100644 --- a/asyn/interfaces/asynOptionSyncIO.c +++ b/asyn/interfaces/asynOptionSyncIO.c @@ -19,8 +19,6 @@ #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynOption.h" #include "asynDrvUser.h" @@ -53,8 +51,8 @@ static asynOptionSyncIO interface = { setOptionOnce, getOptionOnce, }; -epicsShareDef asynOptionSyncIO *pasynOptionSyncIO = &interface; - +asynOptionSyncIO *pasynOptionSyncIO = &interface; + static asynStatus connect(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo) { @@ -67,7 +65,7 @@ static asynStatus connect(const char *port, int addr, pasynUser = pasynManager->createAsynUser(0,0); pasynUser->userPvt = pioPvt; *ppasynUser = pasynUser; - status = pasynManager->connectDevice(pasynUser, port, addr); + status = pasynManager->connectDevice(pasynUser, port, addr); if (status != asynSuccess) { return status; } @@ -106,7 +104,7 @@ static asynStatus connect(const char *port, int addr, } return asynSuccess ; } - + static asynStatus disconnect(asynUser *pasynUser) { ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; @@ -125,7 +123,7 @@ static asynStatus disconnect(asynUser *pasynUser) free(pioPvt); return asynSuccess; } - + static asynStatus setOption(asynUser *pasynUser, const char *key, const char *val, double timeout) { @@ -139,7 +137,7 @@ static asynStatus setOption(asynUser *pasynUser, const char *key, const char *va } status = pioPvt->pasynOption->setOption(pioPvt->OptionPvt, pasynUser, key, val); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynOptionSyncIO wrote: key=%s, val=%s\n",key, val); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -161,7 +159,7 @@ static asynStatus getOption(asynUser *pasynUser, const char *key, char *val, int } status = pioPvt->pasynOption->getOption(pioPvt->OptionPvt, pasynUser, key, val, sizeval); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynOptionSyncIO read: key=%s, val=%s\n", key, val); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -170,7 +168,7 @@ static asynStatus getOption(asynUser *pasynUser, const char *key, char *val, int } return(status); } - + static asynStatus setOptionOnce(const char *port, int addr, const char *key, const char *val, double timeout, const char *drvInfo) { diff --git a/asyn/interfaces/asynOptionSyncIO.h b/asyn/interfaces/asynOptionSyncIO.h index 15a67e5..b5930ed 100644 --- a/asyn/interfaces/asynOptionSyncIO.h +++ b/asyn/interfaces/asynOptionSyncIO.h @@ -16,7 +16,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -24,7 +23,7 @@ extern "C" { #define asynOptionSyncIOType "asynOptionSyncIO" typedef struct asynOptionSyncIO { - asynStatus (*connect)(const char *port, int addr, + asynStatus (*connect)(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo); asynStatus (*disconnect)(asynUser *pasynUser); asynStatus (*setOption)(asynUser *pasynUser, const char *key, const char *val, double timeout); @@ -34,7 +33,7 @@ typedef struct asynOptionSyncIO { asynStatus (*getOptionOnce)(const char *port, int addr, const char *key, char *val, int sizeval, double timeout, const char *drvInfo); } asynOptionSyncIO; -epicsShareExtern asynOptionSyncIO *pasynOptionSyncIO; +ASYN_API extern asynOptionSyncIO *pasynOptionSyncIO; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynStandardInterfaces.h b/asyn/interfaces/asynStandardInterfaces.h index be0d72a..0b722b3 100644 --- a/asyn/interfaces/asynStandardInterfaces.h +++ b/asyn/interfaces/asynStandardInterfaces.h @@ -20,9 +20,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -58,6 +60,10 @@ typedef struct asynStandardInterfaces { int int32CanInterrupt; void *int32InterruptPvt; + asynInterface int64; + int int64CanInterrupt; + void *int64InterruptPvt; + asynInterface float64; int float64CanInterrupt; void *float64InterruptPvt; @@ -74,6 +80,10 @@ typedef struct asynStandardInterfaces { int int32ArrayCanInterrupt; void *int32ArrayInterruptPvt; + asynInterface int64Array; + int int64ArrayCanInterrupt; + void *int64ArrayInterruptPvt; + asynInterface float32Array; int float32ArrayCanInterrupt; void *float32ArrayInterruptPvt; @@ -93,11 +103,11 @@ typedef struct asynStandardInterfaces { } asynStandardInterfaces; typedef struct asynStandardInterfacesBase { - asynStatus (*initialize)(const char *portName, asynStandardInterfaces *pInterfaces, + asynStatus (*initialize)(const char *portName, asynStandardInterfaces *pInterfaces, asynUser *pasynUser, void *pPvt); } asynStandardInterfacesBase; -epicsShareExtern asynStandardInterfacesBase *pasynStandardInterfacesBase; +ASYN_API extern asynStandardInterfacesBase *pasynStandardInterfacesBase; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynStandardInterfacesBase.c b/asyn/interfaces/asynStandardInterfacesBase.c index 8aa8008..7c58d0a 100644 --- a/asyn/interfaces/asynStandardInterfacesBase.c +++ b/asyn/interfaces/asynStandardInterfacesBase.c @@ -17,23 +17,21 @@ #include #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynStandardInterfaces.h" -static asynStatus initialize(const char *portName, asynStandardInterfaces *pInterfaces, +static asynStatus initialize(const char *portName, asynStandardInterfaces *pInterfaces, asynUser *pasynUser, void *pPvt) { asynStatus status; - + if (pInterfaces->common.pinterface) { pInterfaces->common.interfaceType = asynCommonType; pInterfaces->common.drvPvt = pPvt; status = pasynManager->registerInterface(portName, &pInterfaces->common); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register common"); return(asynError); } @@ -44,7 +42,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte pInterfaces->drvUser.drvPvt = pPvt; status = pasynManager->registerInterface(portName, &pInterfaces->drvUser); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register drvUser"); return(asynError); } @@ -55,7 +53,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte pInterfaces->option.drvPvt = pPvt; status = pasynManager->registerInterface(portName, &pInterfaces->option); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register option"); return(asynError); } @@ -64,12 +62,12 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte if (pInterfaces->octet.pinterface) { pInterfaces->octet.interfaceType = asynOctetType; pInterfaces->octet.drvPvt = pPvt; - status = pasynOctetBase->initialize(portName, &pInterfaces->octet, - pInterfaces->octetProcessEosIn, + status = pasynOctetBase->initialize(portName, &pInterfaces->octet, + pInterfaces->octetProcessEosIn, pInterfaces->octetProcessEosIn, pInterfaces->octetInterruptProcess); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register octet"); return(asynError); } @@ -77,7 +75,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte status = pasynManager->registerInterruptSource(portName, &pInterfaces->octet, &pInterfaces->octetInterruptPvt); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register octet interrupt"); return(asynError); } @@ -89,7 +87,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte pInterfaces->uInt32Digital.drvPvt = pPvt; status = pasynUInt32DigitalBase->initialize(portName, &pInterfaces->uInt32Digital); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register uInt32Digital"); return(asynError); } @@ -97,7 +95,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte status = pasynManager->registerInterruptSource(portName, &pInterfaces->uInt32Digital, &pInterfaces->uInt32DigitalInterruptPvt); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register uInt32Digital interrupt"); return(asynError); } @@ -109,7 +107,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte pInterfaces->int32.drvPvt = pPvt; status = pasynInt32Base->initialize(portName, &pInterfaces->int32); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register int32"); return(asynError); } @@ -117,19 +115,39 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte status = pasynManager->registerInterruptSource(portName, &pInterfaces->int32, &pInterfaces->int32InterruptPvt); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register int32 interrupt"); return(asynError); } } } + if (pInterfaces->int64.pinterface) { + pInterfaces->int64.interfaceType = asynInt64Type; + pInterfaces->int64.drvPvt = pPvt; + status = pasynInt64Base->initialize(portName, &pInterfaces->int64); + if (status != asynSuccess) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Can't register int64"); + return(asynError); + } + if (pInterfaces->int64CanInterrupt) { + status = pasynManager->registerInterruptSource(portName, &pInterfaces->int64, + &pInterfaces->int64InterruptPvt); + if (status != asynSuccess) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Can't register int64 interrupt"); + return(asynError); + } + } + } + if (pInterfaces->float64.pinterface) { pInterfaces->float64.interfaceType = asynFloat64Type; pInterfaces->float64.drvPvt = pPvt; status = pasynFloat64Base->initialize(portName, &pInterfaces->float64); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register float64"); return(asynError); } @@ -137,7 +155,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte status = pasynManager->registerInterruptSource(portName, &pInterfaces->float64, &pInterfaces->float64InterruptPvt); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register float64 interrupt"); return(asynError); } @@ -149,7 +167,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte pInterfaces->int8Array.drvPvt = pPvt; status = pasynInt8ArrayBase->initialize(portName, &pInterfaces->int8Array); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register int8Array"); return(asynError); } @@ -157,7 +175,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte status = pasynManager->registerInterruptSource(portName, &pInterfaces->int8Array, &pInterfaces->int8ArrayInterruptPvt); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register int8Array interrupt"); return(asynError); } @@ -169,7 +187,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte pInterfaces->int16Array.drvPvt = pPvt; status = pasynInt16ArrayBase->initialize(portName, &pInterfaces->int16Array); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register int16Array"); return(asynError); } @@ -177,7 +195,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte status = pasynManager->registerInterruptSource(portName, &pInterfaces->int16Array, &pInterfaces->int16ArrayInterruptPvt); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register int16Array interrupt"); return(asynError); } @@ -189,7 +207,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte pInterfaces->int32Array.drvPvt = pPvt; status = pasynInt32ArrayBase->initialize(portName, &pInterfaces->int32Array); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register int32Array"); return(asynError); } @@ -197,19 +215,39 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte status = pasynManager->registerInterruptSource(portName, &pInterfaces->int32Array, &pInterfaces->int32ArrayInterruptPvt); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register int32Array interrupt"); return(asynError); } } } + if (pInterfaces->int64Array.pinterface) { + pInterfaces->int64Array.interfaceType = asynInt64ArrayType; + pInterfaces->int64Array.drvPvt = pPvt; + status = pasynInt64ArrayBase->initialize(portName, &pInterfaces->int64Array); + if (status != asynSuccess) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Can't register int64Array"); + return(asynError); + } + if (pInterfaces->int64ArrayCanInterrupt) { + status = pasynManager->registerInterruptSource(portName, &pInterfaces->int64Array, + &pInterfaces->int64ArrayInterruptPvt); + if (status != asynSuccess) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Can't register int64Array interrupt"); + return(asynError); + } + } + } + if (pInterfaces->float32Array.pinterface) { pInterfaces->float32Array.interfaceType = asynFloat32ArrayType; pInterfaces->float32Array.drvPvt = pPvt; status = pasynFloat32ArrayBase->initialize(portName, &pInterfaces->float32Array); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register float32Array"); return(asynError); } @@ -217,7 +255,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte status = pasynManager->registerInterruptSource(portName, &pInterfaces->float32Array, &pInterfaces->float32ArrayInterruptPvt); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register float32Array interrupt"); return(asynError); } @@ -229,7 +267,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte pInterfaces->float64Array.drvPvt = pPvt; status = pasynFloat64ArrayBase->initialize(portName, &pInterfaces->float64Array); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register float64Array"); return(asynError); } @@ -237,7 +275,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte status = pasynManager->registerInterruptSource(portName, &pInterfaces->float64Array, &pInterfaces->float64ArrayInterruptPvt); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register float64Array interrupt"); return(asynError); } @@ -249,7 +287,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte pInterfaces->genericPointer.drvPvt = pPvt; status = pasynGenericPointerBase->initialize(portName, &pInterfaces->genericPointer); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register genericPointer"); return(asynError); } @@ -257,7 +295,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte status = pasynManager->registerInterruptSource(portName, &pInterfaces->genericPointer, &pInterfaces->genericPointerInterruptPvt); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register genericPointer interrupt"); return(asynError); } @@ -269,7 +307,7 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte pInterfaces->Enum.drvPvt = pPvt; status = pasynEnumBase->initialize(portName, &pInterfaces->Enum); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register enum"); return(asynError); } @@ -277,17 +315,17 @@ static asynStatus initialize(const char *portName, asynStandardInterfaces *pInte status = pasynManager->registerInterruptSource(portName, &pInterfaces->Enum, &pInterfaces->enumInterruptPvt); if (status != asynSuccess) { - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Can't register enum interrupt"); return(asynError); } } } - + return(asynSuccess); } static asynStandardInterfacesBase standardInterfacesBase = {initialize}; -epicsShareDef asynStandardInterfacesBase *pasynStandardInterfacesBase = &standardInterfacesBase; +asynStandardInterfacesBase *pasynStandardInterfacesBase = &standardInterfacesBase; diff --git a/asyn/interfaces/asynUInt32Digital.h b/asyn/interfaces/asynUInt32Digital.h index 1c5e703..00e0125 100644 --- a/asyn/interfaces/asynUInt32Digital.h +++ b/asyn/interfaces/asynUInt32Digital.h @@ -17,7 +17,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -27,7 +26,7 @@ typedef enum { interruptOnZeroToOne, interruptOnOneToZero, interruptOnBoth } interruptReason; -typedef void (*interruptCallbackUInt32Digital)(void *userPvt, +typedef void (*interruptCallbackUInt32Digital)(void *userPvt, asynUser *pasynUser, epicsUInt32 data); typedef struct asynUInt32DigitalInterrupt { epicsUInt32 mask; @@ -68,7 +67,7 @@ typedef struct asynUInt32DigitalBase { asynStatus (*initialize)(const char *portName, asynInterface *pasynUInt32DigitalInterface); } asynUInt32DigitalBase; -epicsShareExtern asynUInt32DigitalBase *pasynUInt32DigitalBase; +ASYN_API extern asynUInt32DigitalBase *pasynUInt32DigitalBase; #ifdef __cplusplus diff --git a/asyn/interfaces/asynUInt32DigitalBase.c b/asyn/interfaces/asynUInt32DigitalBase.c index 39372d2..cf3e23f 100644 --- a/asyn/interfaces/asynUInt32DigitalBase.c +++ b/asyn/interfaces/asynUInt32DigitalBase.c @@ -14,14 +14,12 @@ #include #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynUInt32Digital.h" static asynStatus initialize(const char *portName, asynInterface *pasynUInt32DigitalInterface); static asynUInt32DigitalBase uint32Base = {initialize}; -epicsShareDef asynUInt32DigitalBase *pasynUInt32DigitalBase = &uint32Base; +asynUInt32DigitalBase *pasynUInt32DigitalBase = &uint32Base; static asynStatus writeDefault(void *drvPvt, asynUser *pasynUser, epicsUInt32 value, epicsUInt32 mask); @@ -39,7 +37,7 @@ static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, static asynStatus cancelInterruptUser(void *drvPvt, asynUser *pasynUser, void *registrarPvt); - + static asynStatus initialize(const char *portName,asynInterface *pdriver) { asynUInt32Digital *pasynUInt32Digital = @@ -66,7 +64,7 @@ static asynStatus writeDefault(void *drvPvt, asynUser *pasynUser, const char *portName; asynStatus status; int addr; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -84,7 +82,7 @@ static asynStatus readDefault(void *drvPvt, asynUser *pasynUser, const char *portName; asynStatus status; int addr; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -95,14 +93,14 @@ static asynStatus readDefault(void *drvPvt, asynUser *pasynUser, "%s %d read is not supported\n",portName,addr); return asynError; } - + static asynStatus setInterrupt(void *drvPvt, asynUser *pasynUser, epicsUInt32 mask, interruptReason reason) { const char *portName; asynStatus status; int addr; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -120,7 +118,7 @@ static asynStatus clearInterrupt(void *drvPvt, asynUser *pasynUser, const char *portName; asynStatus status; int addr; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -138,7 +136,7 @@ static asynStatus getInterrupt(void *drvPvt, asynUser *pasynUser, const char *portName; asynStatus status; int addr; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -149,7 +147,7 @@ static asynStatus getInterrupt(void *drvPvt, asynUser *pasynUser, "%s %d getInterrupt is not supported\n",portName,addr); return asynError; } - + static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, interruptCallbackUInt32Digital callback, void *userPvt,epicsUInt32 mask, void **registrarPvt) @@ -160,7 +158,7 @@ static asynStatus registerInterruptUser(void *drvPvt,asynUser *pasynUser, interruptNode *pinterruptNode; void *pinterruptPvt; asynUInt32DigitalInterrupt *pasynUInt32DigitalInterrupt; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -194,7 +192,7 @@ static asynStatus cancelInterruptUser(void *drvPvt, asynUser *pasynUser, int addr; asynUInt32DigitalInterrupt *pasynUInt32DigitalInterrupt = (asynUInt32DigitalInterrupt *)pinterruptNode->drvPvt; - + status = pasynManager->getPortName(pasynUser,&portName); if(status!=asynSuccess) return status; status = pasynManager->getAddr(pasynUser,&addr); @@ -205,7 +203,7 @@ static asynStatus cancelInterruptUser(void *drvPvt, asynUser *pasynUser, if(status==asynSuccess) pasynManager->freeInterruptNode(pasynUser,pinterruptNode); pasynManager->freeAsynUser(pasynUInt32DigitalInterrupt->pasynUser); - pasynManager->memFree(pasynUInt32DigitalInterrupt, + pasynManager->memFree(pasynUInt32DigitalInterrupt, sizeof(asynUInt32DigitalInterrupt)); return status; } diff --git a/asyn/interfaces/asynUInt32DigitalSyncIO.c b/asyn/interfaces/asynUInt32DigitalSyncIO.c index 79aaea7..686754d 100644 --- a/asyn/interfaces/asynUInt32DigitalSyncIO.c +++ b/asyn/interfaces/asynUInt32DigitalSyncIO.c @@ -19,8 +19,6 @@ #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynUInt32Digital.h" #include "asynDrvUser.h" @@ -77,8 +75,8 @@ static asynUInt32DigitalSyncIO interface = { clearInterruptOnce, getInterruptOnce }; -epicsShareDef asynUInt32DigitalSyncIO *pasynUInt32DigitalSyncIO = &interface; - +asynUInt32DigitalSyncIO *pasynUInt32DigitalSyncIO = &interface; + static asynStatus connect(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo) { @@ -92,7 +90,7 @@ static asynStatus connect(const char *port, int addr, pasynUser = pasynManager->createAsynUser(0,0); pasynUser->userPvt = pioPvt; *ppasynUser = pasynUser; - status = pasynManager->connectDevice(pasynUser, port, addr); + status = pasynManager->connectDevice(pasynUser, port, addr); if (status != asynSuccess) { return status; } @@ -131,7 +129,7 @@ static asynStatus connect(const char *port, int addr, } return asynSuccess ; } - + static asynStatus disconnect(asynUser *pasynUser) { ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; @@ -150,7 +148,7 @@ static asynStatus disconnect(asynUser *pasynUser) free(pioPvt); return asynSuccess; } - + static asynStatus writeOp(asynUser *pasynUser, epicsUInt32 value,epicsUInt32 mask,double timeout) @@ -166,7 +164,7 @@ static asynStatus writeOp(asynUser *pasynUser, status = pioPvt->pasynUInt32Digital->write( pioPvt->uint32DigitalPvt, pasynUser, value,mask); if(status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynUInt32DigitalSyncIO wrote: 0x%x\n",value); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -190,7 +188,7 @@ static asynStatus readOp(asynUser *pasynUser, status = pioPvt->pasynUInt32Digital->read( pioPvt->uint32DigitalPvt, pasynUser,pvalue,mask); if(status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynUInt32DigitalSyncIO read: 0x%x\n",*pvalue); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -199,7 +197,7 @@ static asynStatus readOp(asynUser *pasynUser, } return status; } - + static asynStatus setInterrupt(asynUser *pasynUser, epicsUInt32 mask, interruptReason reason,double timeout) { @@ -214,7 +212,7 @@ static asynStatus setInterrupt(asynUser *pasynUser, status = pioPvt->pasynUInt32Digital->setInterrupt( pioPvt->uint32DigitalPvt, pasynUser,mask,reason); if(status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynUInt32DigitalSyncIO setInterrupt: 0x%x\n",mask); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -238,7 +236,7 @@ static asynStatus clearInterrupt(asynUser *pasynUser, status = pioPvt->pasynUInt32Digital->clearInterrupt( pioPvt->uint32DigitalPvt, pasynUser,mask); if(status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynUInt32DigitalSyncIO clearInterrupt: 0x%x\n",mask); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -262,7 +260,7 @@ static asynStatus getInterrupt(asynUser *pasynUser, status = pioPvt->pasynUInt32Digital->getInterrupt( pioPvt->uint32DigitalPvt, pasynUser,mask,reason); if(status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynUInt32DigitalSyncIO getInterrupt: 0x%x\n", *mask); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -271,7 +269,7 @@ static asynStatus getInterrupt(asynUser *pasynUser, } return status; } - + static asynStatus writeOpOnce(const char *port, int addr, epicsUInt32 value,epicsUInt32 mask,double timeout,const char *drvInfo) { diff --git a/asyn/interfaces/asynUInt32DigitalSyncIO.h b/asyn/interfaces/asynUInt32DigitalSyncIO.h index 0985fe9..e57416f 100644 --- a/asyn/interfaces/asynUInt32DigitalSyncIO.h +++ b/asyn/interfaces/asynUInt32DigitalSyncIO.h @@ -16,7 +16,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -24,7 +23,7 @@ extern "C" { #define asynUInt32DigitalSyncIOType "asynUInt32DigitalSyncIO" typedef struct asynUInt32DigitalSyncIO { - asynStatus (*connect)(const char *port, int addr, + asynStatus (*connect)(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo); asynStatus (*disconnect)(asynUser *pasynUser); asynStatus (*write)(asynUser *pasynUser, @@ -52,7 +51,7 @@ typedef struct asynUInt32DigitalSyncIO { epicsUInt32 *mask, interruptReason reason,double timeout, const char *drvInfo); } asynUInt32DigitalSyncIO; -epicsShareExtern asynUInt32DigitalSyncIO *pasynUInt32DigitalSyncIO; +ASYN_API extern asynUInt32DigitalSyncIO *pasynUInt32DigitalSyncIO; #ifdef __cplusplus } diff --git a/asyn/interfaces/asynXXXArrayBase.h b/asyn/interfaces/asynXXXArrayBase.h index 1bdfa0d..5787b0e 100644 --- a/asyn/interfaces/asynXXXArrayBase.h +++ b/asyn/interfaces/asynXXXArrayBase.h @@ -17,7 +17,7 @@ static asynStatus initialize(const char *portName, asynInterface *pInterface); \ \ static INTERFACE_BASE arrayBase = {initialize}; \ -epicsShareDef INTERFACE_BASE *PINTERFACE_BASE = &arrayBase; \ +INTERFACE_BASE *PINTERFACE_BASE = &arrayBase; \ \ static asynStatus writeDefault(void *drvPvt, asynUser *pasynUser, \ EPICS_TYPE *value, size_t nelem); \ diff --git a/asyn/interfaces/asynXXXArraySyncIO.c b/asyn/interfaces/asynXXXArraySyncIO.c index c45fde5..0ffac72 100644 --- a/asyn/interfaces/asynXXXArraySyncIO.c +++ b/asyn/interfaces/asynXXXArraySyncIO.c @@ -19,8 +19,6 @@ #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynFloat64.h" #include "asynDrvUser.h" @@ -54,8 +52,8 @@ static asynFloat64SyncIO interface = { writeOpOnce, readOpOnce }; -epicsShareDef asynFloat64SyncIO *pasynFloat64SyncIO = &interface; - +asynFloat64SyncIO *pasynFloat64SyncIO = &interface; + static asynStatus connect(const char *port, int addr, asynUser **ppasynUser, const char *drvInfo) { @@ -68,7 +66,7 @@ static asynStatus connect(const char *port, int addr, pasynUser = pasynManager->createAsynUser(0,0); pasynUser->userPvt = pioPvt; *ppasynUser = pasynUser; - status = pasynManager->connectDevice(pasynUser, port, addr); + status = pasynManager->connectDevice(pasynUser, port, addr); if (status != asynSuccess) { return status; } @@ -107,7 +105,7 @@ static asynStatus connect(const char *port, int addr, } return asynSuccess ; } - + static asynStatus disconnect(asynUser *pasynUser) { ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; @@ -126,7 +124,7 @@ static asynStatus disconnect(asynUser *pasynUser) free(pioPvt); return asynSuccess; } - + static asynStatus writeOp(asynUser *pasynUser,epicsFloat64 value,double timeout) { asynStatus status, unlockStatus; @@ -139,7 +137,7 @@ static asynStatus writeOp(asynUser *pasynUser,epicsFloat64 value,double timeout) } status = pPvt->pasynFloat64->write(pPvt->float64Pvt, pasynUser,value); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynFloat64SyncIO wrote: %e\n", value); } @@ -162,7 +160,7 @@ static asynStatus readOp(asynUser *pasynUser,epicsFloat64 *pvalue,double timeout } status = pPvt->pasynFloat64->read(pPvt->float64Pvt, pasynUser, pvalue); if (status==asynSuccess) { - asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, + asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, "asynFloat64SyncIO read: %e\n", *pvalue); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); @@ -171,7 +169,7 @@ static asynStatus readOp(asynUser *pasynUser,epicsFloat64 *pvalue,double timeout } return status; } - + static asynStatus writeOpOnce(const char *port, int addr, epicsFloat64 value,double timeout,const char *drvInfo) { diff --git a/asyn/linuxGpib/drvLinuxGpib.c b/asyn/linuxGpib/drvLinuxGpib.c index f57c0c5..382ef32 100644 --- a/asyn/linuxGpib/drvLinuxGpib.c +++ b/asyn/linuxGpib/drvLinuxGpib.c @@ -2,7 +2,7 @@ /*********************************************************************** * Copyright (c) 2004 by Danfysik and Cosylab (Danfysik has funded the work * performed by Cosylab). -* linux-gpib port driver is distributed subject to a Software License Agreement +* linux-gpib port driver is distributed subject to a Software License Agreement * found in file LICENSE that is included with this distribution. ***********************************************************************/ @@ -66,7 +66,7 @@ static void report(void *pdrvPvt,FILE *fd,int details); static asynStatus connect(void *pdrvPvt,asynUser *pasynUser); static asynStatus disconnect(void *pdrvPvt,asynUser *pasynUser); /*asynOctet methods */ -static asynStatus gpibRead(void *pdrvPvt,asynUser *pasynUser,char +static asynStatus gpibRead(void *pdrvPvt,asynUser *pasynUser,char *data,int maxchars,int *nbytesTransfered,int *eomReason); static asynStatus gpibWrite(void *pdrvPvt,asynUser *pasynUser, const char *data,int numchars,int *nbytesTransfered); @@ -116,41 +116,41 @@ static asynGpibPort GpibBoardDriver = { }; static asynStatus gpibPortSetPortOptions(void *pdrvPvt,asynUser *pasynUser, - const char *key, const char *val); + const char *key, const char *val); static asynStatus gpibPortGetPortOptions(void *pdrvPvt,asynUser *pasynUser, - const char *key, char *val, int sizeval); + const char *key, char *val, int sizeval); static asynOption GpibBoardOption = { - gpibPortSetPortOptions, - gpibPortGetPortOptions + gpibPortSetPortOptions, + gpibPortGetPortOptions }; volatile int work; void signal_handler(int signum){ - if(signum==SIGUSR1) - work=0; + if(signum==SIGUSR1) + work=0; } static void poll_worker(GpibBoardPvt *pGpibBoardPvt) { - /*mask for srq bit*/ - int mask=SRQI; - struct sigaction new_action,old_action; - work = 1; - new_action.sa_handler=signal_handler; - sigemptyset(&new_action.sa_mask); - new_action.sa_flags=0; - - pGpibBoardPvt->worker_pid=getpid(); - - sigaction(SIGUSR1,&new_action,&old_action); - - while(work){ - ibwait(pGpibBoardPvt->ud,mask); - callbackRequest(&pGpibBoardPvt->callback); - epicsThreadSleep(0.001); - } + /*mask for srq bit*/ + int mask=SRQI; + struct sigaction new_action,old_action; + work = 1; + new_action.sa_handler=signal_handler; + sigemptyset(&new_action.sa_mask); + new_action.sa_flags=0; + + pGpibBoardPvt->worker_pid=getpid(); + + sigaction(SIGUSR1,&new_action,&old_action); + + while(work){ + ibwait(pGpibBoardPvt->ud,mask); + callbackRequest(&pGpibBoardPvt->callback); + epicsThreadSleep(0.001); + } } @@ -158,611 +158,605 @@ static void poll_worker(GpibBoardPvt *pGpibBoardPvt) void poll_worker_starter(initHookState state) { - if(state == initHookAtEnd) - { - /*create thread only if not yet created*/ - if((!epicsThreadGetId("PollThread"))) - epicsThreadCreate("PollThread", epicsThreadPriorityMedium, - epicsThreadGetStackSize(epicsThreadStackSmall), - (EPICSTHREADFUNC)poll_worker,pGlobalGpibBoardPvt); - } + if(state == initHookAtEnd) + { + /*create thread only if not yet created*/ + if((!epicsThreadGetId("PollThread"))) + epicsThreadCreate("PollThread", epicsThreadPriorityMedium, + epicsThreadGetStackSize(epicsThreadStackSmall), + (EPICSTHREADFUNC)poll_worker, pGlobalGpibBoardPvt); + } } static void report(void *pdrvPvt,FILE *fd,int details) -{ - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - - if(DEBUG) printf("drvGpibBoard:report!!\n"); - fprintf(fd,"GpibBoard port %s, boardIndex %d,timeout %d.\n", - pGpibBoardPvt->portName,pGpibBoardPvt->boardIndex,pGpibBoardPvt->timeout); - +{ + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + + if(DEBUG) printf("drvGpibBoard:report!!\n"); + fprintf(fd,"GpibBoard port %s, boardIndex %d,timeout %d.\n", + pGpibBoardPvt->portName,pGpibBoardPvt->boardIndex,pGpibBoardPvt->timeout); + } static asynStatus connect(void *pdrvPvt,asynUser *pasynUser) { - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - int addr = 0; - int primaryAddr = 0; - int secondaryAddr = 0; - asynStatus status; - - - if(DEBUG) printf("drvGpibBoard:connect!!\n"); - - status = pasynManager->getAddr(pasynUser,&addr); - if(status!=asynSuccess) return status; - - - asynPrint(pasynUser, ASYN_TRACE_FLOW, - "%s addr %d connect\n",pGpibBoardPvt->portName,addr); - - if(DEBUG) printf("ADDR: %d\n", addr); - - if(addr==-1){ - pGpibBoardPvt->ud=ibfind(pGpibBoardPvt->portName); - if(DEBUG) printf("DESCRIPTOR: %d\n",pGpibBoardPvt->ud); - - if(pGpibBoardPvt->ud<0){ - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - } - - - /*disable autopolling*/ - ibconfig(pGpibBoardPvt->ud,IbcAUTOPOLL,0); - - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - - /*set general timeout for board*/ - ibtmo(pGpibBoardPvt->ud,pGpibBoardPvt->timeout); + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + int addr = 0; + int primaryAddr = 0; + int secondaryAddr = 0; + asynStatus status; + + + if(DEBUG) printf("drvGpibBoard:connect!!\n"); + + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + + + asynPrint(pasynUser, ASYN_TRACE_FLOW, + "%s addr %d connect\n",pGpibBoardPvt->portName,addr); + + if(DEBUG) printf("ADDR: %d\n", addr); + + if(addr==-1) { + pGpibBoardPvt->ud=ibfind(pGpibBoardPvt->portName); + if(DEBUG) printf("DESCRIPTOR: %d\n",pGpibBoardPvt->ud); + + if(pGpibBoardPvt->ud<0){ + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + } + + /*disable autopolling*/ + ibconfig(pGpibBoardPvt->ud,IbcAUTOPOLL,0); + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + + /*set general timeout for board*/ + ibtmo(pGpibBoardPvt->ud,pGpibBoardPvt->timeout); + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + } + else { + getAddr(addr,&primaryAddr,&secondaryAddr); + /*third argument:secondary address,last two arguments are:set EOI line and set eos*/ + if((primaryAddr>=0 && primaryAddr<=30) && (secondaryAddr>=0 && secondaryAddr<=30)){ + pGpibBoardPvt->uddev[primaryAddr][secondaryAddr]=ibdev(pGpibBoardPvt->boardIndex,primaryAddr,secondaryAddr + 96,pGpibBoardPvt->timeout,1,0); + + if(DEBUG) printf("DESCRIPTOR: %d\n",pGpibBoardPvt->uddev[primaryAddr][secondaryAddr]); + + if(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr]<0){ status=checkError(pdrvPvt,pasynUser,addr); if(status!=asynSuccess)return status; - - - } - else{ - getAddr(addr,&primaryAddr,&secondaryAddr); - /*third argument:secondary address,last two arguments are:set EOI line and set eos*/ - if((primaryAddr>=0 && primaryAddr<=30) && (secondaryAddr>=0 && secondaryAddr<=30)){ - pGpibBoardPvt->uddev[primaryAddr][secondaryAddr]=ibdev(pGpibBoardPvt->boardIndex,primaryAddr,secondaryAddr + 96,pGpibBoardPvt->timeout,1,0); - - if(DEBUG) printf("DESCRIPTOR: %d\n",pGpibBoardPvt->uddev[primaryAddr][secondaryAddr]); - - if(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr]<0){ - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - } - } - else{ - asynPrint(pasynUser,ASYN_TRACE_ERROR, - "%s addr %d connect illegal primary or secondary address (primary:%d,secondary %d)\n", - pGpibBoardPvt->portName,addr,primaryAddr,secondaryAddr); - return asynError; - } - } - - - pasynManager->exceptionConnect(pasynUser); - - return asynSuccess; + } + } + else{ + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s addr %d connect illegal primary or secondary address (primary:%d,secondary %d)\n", + pGpibBoardPvt->portName,addr,primaryAddr,secondaryAddr); + return asynError; + } + } + + + pasynManager->exceptionConnect(pasynUser); + + return asynSuccess; } static asynStatus disconnect(void *pdrvPvt,asynUser *pasynUser) { - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - int addr=0; - int primaryAddr = 0; - int secondaryAddr = 0; ; - asynStatus status; - - if(DEBUG) printf("drvGpibBoard:disconnect!!\n"); - - status = pasynManager->getAddr(pasynUser,&addr); - if(status!=asynSuccess) return status; - - getAddr(addr,&primaryAddr,&secondaryAddr); - - asynPrint(pasynUser, ASYN_TRACE_FLOW, - "%s addr %d disconnect\n",pGpibBoardPvt->portName,addr); - - /*disconnect device or board*/ - if(addr==-1){ - - ibonl(pGpibBoardPvt->ud,0); - - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - - /*destroy poll_worker*/ - kill(pGpibBoardPvt->worker_pid,SIGUSR1); - } - else{ - ibonl(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],0); - - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - - } + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + int addr=0; + int primaryAddr = 0; + int secondaryAddr = 0; ; + asynStatus status; + + if(DEBUG) printf("drvGpibBoard:disconnect!!\n"); + + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + + getAddr(addr,&primaryAddr,&secondaryAddr); + + asynPrint(pasynUser, ASYN_TRACE_FLOW, + "%s addr %d disconnect\n",pGpibBoardPvt->portName,addr); + + /*disconnect device or board*/ + if(addr==-1){ + + ibonl(pGpibBoardPvt->ud,0); + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + + /*destroy poll_worker*/ + kill(pGpibBoardPvt->worker_pid,SIGUSR1); + } + else{ + ibonl(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],0); + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; - pasynManager->exceptionDisconnect(pasynUser); - return asynSuccess; + } + + pasynManager->exceptionDisconnect(pasynUser); + return asynSuccess; } static asynStatus gpibPortSetPortOptions(void *pdrvPvt,asynUser *pasynUser, const char *key, const char *val) { - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - int option,value; - int addr=0,j=0; - int primaryAddr = 0; - int secondaryAddr = 0; - char cset[] = "1234567890ABCDEFabcdefxX"; - asynStatus status; - int parseStatus; - - - status = pasynManager->getAddr(pasynUser,&addr); - if(status!=asynSuccess) return status; - - getAddr(addr,&primaryAddr,&secondaryAddr); - - if(DEBUG) printf("drvGpibBoard:gpibPortSetPortOptions!!\n"); - - asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s gpibPortSetPortOptions\n", - pGpibBoardPvt->portName); - - - j = strspn (key,cset); - - if((*key != '0') || ((*(key+1) != 'x') && (*(key+1) != 'X')) || ( j != strlen(key))){ - asynPrint(pasynUser,ASYN_TRACE_ERROR, - "%s addr %d gpibPortSetPortOptions illegal option: %s\n", - pGpibBoardPvt->portName,addr,key); - return asynError; - } - - parseStatus = sscanf(key,"%x",&option); - - if(parseStatus != 1){ - asynPrint(pasynUser,ASYN_TRACE_ERROR, - "%s addr %d gpibPortSetPortOptions illegal option: %s\n", - pGpibBoardPvt->portName,addr,key); - return asynError; - } - - parseStatus = sscanf(val,"%d",&value); - - if(parseStatus != 1){ - asynPrint(pasynUser,ASYN_TRACE_ERROR, - "%s addr %d gpibPortSetPortOptions illegal option value: %s\n", - pGpibBoardPvt->portName,addr,val); - return asynError; - } - - if(DEBUG) printf("option %d set with value %d\n",option,value); - - - if(addr==-1){ - ibconfig(pGpibBoardPvt->ud,option,value); - } - else{ - ibconfig(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],option,value); - } - - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - - return asynSuccess; + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + int option,value; + int addr=0,j=0; + int primaryAddr = 0; + int secondaryAddr = 0; + char cset[] = "1234567890ABCDEFabcdefxX"; + asynStatus status; + int parseStatus; + + + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + + getAddr(addr,&primaryAddr,&secondaryAddr); + + if(DEBUG) printf("drvGpibBoard:gpibPortSetPortOptions!!\n"); + + asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s gpibPortSetPortOptions\n", + pGpibBoardPvt->portName); + + + j = strspn (key,cset); + + if((*key != '0') || ((*(key+1) != 'x') && (*(key+1) != 'X')) || ( j != strlen(key))){ + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s addr %d gpibPortSetPortOptions illegal option: %s\n", + pGpibBoardPvt->portName,addr,key); + return asynError; + } + + parseStatus = sscanf(key,"%x",(unsigned int *)&option); + + if(parseStatus != 1){ + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s addr %d gpibPortSetPortOptions illegal option: %s\n", + pGpibBoardPvt->portName,addr,key); + return asynError; + } + + parseStatus = sscanf(val,"%d",&value); + + if(parseStatus != 1){ + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s addr %d gpibPortSetPortOptions illegal option value: %s\n", + pGpibBoardPvt->portName,addr,val); + return asynError; + } + + if(DEBUG) printf("option %d set with value %d\n",option,value); + + + if(addr==-1){ + ibconfig(pGpibBoardPvt->ud,option,value); + } + else{ + ibconfig(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],option,value); + } + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + + return asynSuccess; } static asynStatus gpibPortGetPortOptions(void *pdrvPvt,asynUser *pasynUser, const char *key, char *val, int sizeval) { - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - int value,option; - int addr=0,j=0; - int primaryAddr = 0; - int secondaryAddr = 0; - asynStatus status; - char cset[] = "1234567890ABCDEFabcdefxX"; - int parseStatus = 0; - - - - status = pasynManager->getAddr(pasynUser,&addr); - if(status!=asynSuccess) return status; - - getAddr(addr,&primaryAddr,&secondaryAddr); - - if(DEBUG) printf("drvGpibBoard:gpibPortGetPortOptions!!\n"); - - - asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s gpibPortGetPortOptions\n", - *pGpibBoardPvt->portName); - - - j = strspn (key,cset); - - if((*key != '0') || ((*(key+1) != 'x') && (*(key+1) != 'X')) || ( j != strlen(key))){ - asynPrint(pasynUser,ASYN_TRACE_ERROR, - "%s addr %d gpibPortGetPortOptions illegal option: %s\n", - pGpibBoardPvt->portName,addr,key); - return asynError; - } - - parseStatus=sscanf(key,"%x",&option); - - if(parseStatus != 1){ - asynPrint(pasynUser,ASYN_TRACE_ERROR, - "%s addr %d gpibPortGetPortOptions illegal option: %s\n", - pGpibBoardPvt->portName,addr,key); - return asynError; - } - - if(addr==-1){ - ibask(pGpibBoardPvt->ud,option,&value); - } - else{ - ibask(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],option,&value); - } - - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - - sprintf(val,"%d",value); + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + int value,option; + int addr=0,j=0; + int primaryAddr = 0; + int secondaryAddr = 0; + asynStatus status; + char cset[] = "1234567890ABCDEFabcdefxX"; + int parseStatus = 0; + + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + + getAddr(addr,&primaryAddr,&secondaryAddr); + + if(DEBUG) printf("drvGpibBoard:gpibPortGetPortOptions!!\n"); + + + asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s gpibPortGetPortOptions\n", + *pGpibBoardPvt->portName); + + + j = strspn (key,cset); + + if((*key != '0') || ((*(key+1) != 'x') && (*(key+1) != 'X')) || ( j != strlen(key))){ + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s addr %d gpibPortGetPortOptions illegal option: %s\n", + pGpibBoardPvt->portName,addr,key); + return asynError; + } + + parseStatus=sscanf(key,"%x",(unsigned int *)&option); + + if(parseStatus != 1){ + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s addr %d gpibPortGetPortOptions illegal option: %s\n", + pGpibBoardPvt->portName,addr,key); + return asynError; + } + + if(addr==-1){ + ibask(pGpibBoardPvt->ud,option,&value); + } + else{ + ibask(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],option,&value); + } + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + + sprintf(val,"%d",value); + + if(DEBUG) printf("option %d get with value %d\n",option,value); - if(DEBUG) printf("option %d get with value %d\n",option,value); - - return asynSuccess; + return asynSuccess; } /*asynOctet methods */ static asynStatus gpibRead(void *pdrvPvt,asynUser *pasynUser,char *data,int maxchars,int *nbytesTransfered,int *eomReason) { - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - int addr=0; - int primaryAddr = 0; - int secondaryAddr = 0; - asynStatus status=asynSuccess; - double timeout = pasynUser->timeout; - int ibsta; - - if(DEBUG) printf("drvGpibBoard:gpibRead!!\n"); - epicsThreadSleep(epicsThreadSleepQuantum()); - - status = pasynManager->getAddr(pasynUser,&addr); - if(status!=asynSuccess) return status; - - getAddr(addr,&primaryAddr,&secondaryAddr); - - asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s addr %d gpibRead\n", - pGpibBoardPvt->portName,addr); - - /*set timeout*/ - ibtmo(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],sec_to_timeout(timeout)); - - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - - - /*read data*/ - ibsta = ibrd(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],data,maxchars); - - /*ibcnt holds number of bytes transfered*/ - *nbytesTransfered=ibcnt; - - if (eomReason != NULL) - { - *eomReason = 0; - if (ibsta & END) *eomReason = ASYN_EOM_END; - if (ibcnt == maxchars) *eomReason = ASYN_EOM_CNT; - } - - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess){ - epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, - "%s readGpib failed %s",pGpibBoardPvt->portName,gpib_error_string(pGpibBoardPvt->iberr)); - - return status; - } - - asynPrintIO(pasynUser,ASYN_TRACEIO_DRIVER,data,ibcnt,"%s addr %d gpibPortRead\n",pGpibBoardPvt->portName,addr); - - /*if last response is shorter than previous*/ - if(ibcnttimeout; + int ibsta; + + if(DEBUG) printf("drvGpibBoard:gpibRead!!\n"); + epicsThreadSleep(epicsThreadSleepQuantum()); + + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + + getAddr(addr,&primaryAddr,&secondaryAddr); + + asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s addr %d gpibRead\n", + pGpibBoardPvt->portName,addr); + + /*set timeout*/ + ibtmo(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],sec_to_timeout(timeout)); + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + + + /*read data*/ + ibsta = ibrd(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],data,maxchars); + + /*ibcnt holds number of bytes transfered*/ + *nbytesTransfered=ibcnt; + + if (eomReason != NULL) + { + *eomReason = 0; + if (ibsta & END) *eomReason = ASYN_EOM_END; + if (ibcnt == maxchars) *eomReason = ASYN_EOM_CNT; + } + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess){ + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "%s readGpib failed %s",pGpibBoardPvt->portName,gpib_error_string(pGpibBoardPvt->iberr)); + + return status; + } + + asynPrintIO(pasynUser,ASYN_TRACEIO_DRIVER,data,ibcnt,"%s addr %d gpibPortRead\n",pGpibBoardPvt->portName,addr); + + /*if last response is shorter than previous*/ + if(ibcnttimeout; - - status = pasynManager->getAddr(pasynUser,&addr); - if(status!=asynSuccess) return status; - - getAddr(addr,&primaryAddr,&secondaryAddr); - - if(DEBUG){ - printf("drvGpibBoard:gpibWrite!!\n"); - printf("WRITING STRING: %s \n",data); - } - - asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s addr %d gpibWrite nchar %d\n", - pGpibBoardPvt->portName,addr,numchars); - - /*set timeout*/ - ibtmo(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],sec_to_timeout(timeout)); + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + int addr=0; + int primaryAddr = 0; + int secondaryAddr = 0; + asynStatus status=asynSuccess; + double timeout = pasynUser->timeout; - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - - /*write data*/ - ibwrt(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],data,numchars); - - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess){ - epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, - "%s writeGpib failed %s",pGpibBoardPvt->portName,gpib_error_string(pGpibBoardPvt->iberr)); - - return status; - } - - - /*ibcnt holds number of bytes transfered*/ - *nbytesTransfered=ibcnt; - - asynPrintIO(pasynUser,ASYN_TRACEIO_DRIVER, - data,ibcnt,"%s addr %d gpibPortWrite\n",pGpibBoardPvt->portName,addr); - - return status; + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + + getAddr(addr,&primaryAddr,&secondaryAddr); + + if(DEBUG){ + printf("drvGpibBoard:gpibWrite!!\n"); + printf("WRITING STRING: %s \n",data); + } + + asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s addr %d gpibWrite nchar %d\n", + pGpibBoardPvt->portName,addr,numchars); + + /*set timeout*/ + ibtmo(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],sec_to_timeout(timeout)); + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + + /*write data*/ + ibwrt(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],data,numchars); + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess){ + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "%s writeGpib failed %s",pGpibBoardPvt->portName,gpib_error_string(pGpibBoardPvt->iberr)); + + return status; + } + + + /*ibcnt holds number of bytes transfered*/ + *nbytesTransfered=ibcnt; + + asynPrintIO(pasynUser,ASYN_TRACEIO_DRIVER, + data,ibcnt,"%s addr %d gpibPortWrite\n",pGpibBoardPvt->portName,addr); + + return status; } static asynStatus gpibFlush(void *pdrvPvt,asynUser *pasynUser) { - if(DEBUG) - printf("drvGpibBoard:gpibFlush!!\n"); - /*nothing to do*/ - return asynSuccess; + if(DEBUG) + printf("drvGpibBoard:gpibFlush!!\n"); + /*nothing to do*/ + return asynSuccess; } static asynStatus setEos(void *pdrvPvt,asynUser *pasynUser,const char *eos,int eoslen) { - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - int addr = 0; - int primaryAddr = 0; - int secondaryAddr = 0; - asynStatus status; - - if(DEBUG) printf("drvGpibBoard:setEos!!\n"); - - status = pasynManager->getAddr(pasynUser,&addr); - if(status!=asynSuccess) return status; - - getAddr(addr,&primaryAddr,&secondaryAddr); - - asynPrint(pasynUser, ASYN_TRACE_FLOW, - "%s addr %d setEos eoslen %d\n",pGpibBoardPvt->portName,addr,eoslen); - - if(eoslen>1 || eoslen<0){ - asynPrint(pasynUser,ASYN_TRACE_ERROR, - "%s addr %d gpibBoard:setEos illegal eoslen %d\n", - pGpibBoardPvt->portName,addr,eoslen); - - return asynError; - } - - if(eoslen==1){ - ibconfig(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],IbcEOScmp,1); - ibconfig(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],IbcEOSchar,*eos); + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + int addr = 0; + int primaryAddr = 0; + int secondaryAddr = 0; + asynStatus status; - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - - ibconfig(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],IbcEOSrd,1); - - if(DEBUG) - printf("Seting EOS: %u\n",*eos); + if(DEBUG) printf("drvGpibBoard:setEos!!\n"); - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - - } - else{ - pGpibBoardPvt->ibsta=ibconfig(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],IbcEOSrd,0); - if(DEBUG) printf("Disabling EOS\n"); - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - } - return asynSuccess; + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + + getAddr(addr,&primaryAddr,&secondaryAddr); + + asynPrint(pasynUser, ASYN_TRACE_FLOW, + "%s addr %d setEos eoslen %d\n",pGpibBoardPvt->portName,addr,eoslen); + + if(eoslen>1 || eoslen<0){ + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s addr %d gpibBoard:setEos illegal eoslen %d\n", + pGpibBoardPvt->portName,addr,eoslen); + return asynError; + } + + if(eoslen==1){ + ibconfig(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],IbcEOScmp,1); + ibconfig(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],IbcEOSchar,*eos); + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + + ibconfig(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],IbcEOSrd,1); + + if(DEBUG) + printf("Seting EOS: %u\n",*eos); + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + } + else{ + pGpibBoardPvt->ibsta=ibconfig(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],IbcEOSrd,0); + if(DEBUG) printf("Disabling EOS\n"); + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + } + return asynSuccess; } static asynStatus getEos(void *pdrvPvt,asynUser *pasynUser, char *eos, int eossize, int *eoslen) { - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - int addr = 0; - int primaryAddr = 0; - int secondaryAddr = 0; - asynStatus status; - int ieos; - - status = pasynManager->getAddr(pasynUser,&addr); - if(status!=asynSuccess) return status; - - getAddr(addr,&primaryAddr,&secondaryAddr); - - asynPrint(pasynUser, ASYN_TRACE_FLOW, - "%s addr %d gpibPortGetEos\n",pGpibBoardPvt->portName,addr); - - if(DEBUG) printf("drvGpibBoard:getEos!!\n"); - - - if(eossize<1) { - asynPrint(pasynUser,ASYN_TRACE_ERROR, - "%s addr %d getEos eossize %d too small\n", - pGpibBoardPvt->portName,eossize); - *eoslen = 0; - return asynError; - } - - ibask(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],IbaEOSrd,&ieos); + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + int addr = 0; + int primaryAddr = 0; + int secondaryAddr = 0; + asynStatus status; + int ieos; + + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + + getAddr(addr,&primaryAddr,&secondaryAddr); + + asynPrint(pasynUser, ASYN_TRACE_FLOW, + "%s addr %d gpibPortGetEos\n",pGpibBoardPvt->portName,addr); + + if(DEBUG) printf("drvGpibBoard:getEos!!\n"); + + + if(eossize<1) { + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s addr %d getEos eossize %d too small\n", + pGpibBoardPvt->portName,eossize); + *eoslen = 0; + return asynError; + } + + ibask(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],IbaEOSrd,&ieos); + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + + + if(ieos==0){ + *eoslen = 0; + if(DEBUG) printf("EOS disabled\n"); + } + else { + *eoslen = 1; + ibask(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],IbaEOSchar,&ieos); status=checkError(pdrvPvt,pasynUser,addr); if(status!=asynSuccess)return status; - - - if(ieos==0){ - *eoslen = 0; - if(DEBUG) printf("EOS disabled\n"); - } - else { - *eoslen = 1; - ibask(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],IbaEOSchar,&ieos); - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - - if(DEBUG) printf("EOS: %d\n",ieos); - eos[0]=ieos; - } - - return asynSuccess; -} - + if(DEBUG) printf("EOS: %d\n",ieos); + eos[0]=ieos; + } + + return asynSuccess; +} + static asynStatus addressedCmd (void *pdrvPvt,asynUser *pasynUser, - const char *data, int length) + const char *data, int length) { - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - int addr = 0; - int primaryAddr = 0; - int secondaryAddr = 0; - asynStatus status; - double timeout = pasynUser->timeout; - - if(DEBUG) printf("drvGpibBoard:addressedCmd!!\n"); - status = pasynManager->getAddr(pasynUser,&addr); - if(status!=asynSuccess) return status; - - getAddr(addr,&primaryAddr,&secondaryAddr); - - asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s addr %d addressedCmd nchar %d\n", - pGpibBoardPvt->portName,addr,length); - - /*set timeout*/ - ibtmo(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],sec_to_timeout(timeout)); + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + int addr = 0; + int primaryAddr = 0; + int secondaryAddr = 0; + asynStatus status; + double timeout = pasynUser->timeout; - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - - if(DEBUG) printf("DATA: %s\n", data); - - Send(pGpibBoardPvt->ud,MakeAddr(primaryAddr,secondaryAddr),data,strlen(data),1); - - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - - return asynSuccess; + if(DEBUG) printf("drvGpibBoard:addressedCmd!!\n"); + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + + getAddr(addr,&primaryAddr,&secondaryAddr); + + asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s addr %d addressedCmd nchar %d\n", + pGpibBoardPvt->portName,addr,length); + + /*set timeout*/ + ibtmo(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],sec_to_timeout(timeout)); + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + + if(DEBUG) printf("DATA: %s\n", data); + + Send(pGpibBoardPvt->ud,MakeAddr(primaryAddr,secondaryAddr),data,strlen(data),1); + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + + return asynSuccess; } static asynStatus universalCmd(void *pdrvPvt, asynUser *pasynUser, int cmd) { - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - int addr=0; - int primaryAddr = 0; - int secondaryAddr = 0; - asynStatus status; - char chcmd[20]; - - status = pasynManager->getAddr(pasynUser,&addr); - if(status!=asynSuccess) return status; - - getAddr(addr,&primaryAddr,&secondaryAddr); - - asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s universalCmd %2.2x\n", - pGpibBoardPvt->portName,cmd); - - if(DEBUG){ - printf("drvGpibBoard:universalCmd!!\n"); - printf("CMD integer: %d\n",cmd); - } - sprintf(chcmd,"\\%x",cmd); - - if(DEBUG)printf("CMD string: %s\n",chcmd); - - ibcmd(pGpibBoardPvt->ud,chcmd,strlen(chcmd)); - - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - - return asynSuccess; + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + int addr=0; + int primaryAddr = 0; + int secondaryAddr = 0; + asynStatus status; + char chcmd[20]; + + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + + getAddr(addr,&primaryAddr,&secondaryAddr); + + asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s universalCmd %2.2x\n", + pGpibBoardPvt->portName,cmd); + + if(DEBUG){ + printf("drvGpibBoard:universalCmd!!\n"); + printf("CMD integer: %d\n",cmd); + } + sprintf(chcmd,"\\%x",cmd); + + if(DEBUG)printf("CMD string: %s\n",chcmd); + + ibcmd(pGpibBoardPvt->ud,chcmd,strlen(chcmd)); + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + + return asynSuccess; } static asynStatus ifc(void *pdrvPvt,asynUser *pasynUser) { - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - int addr=0; - int primaryAddr = 0; - int secondaryAddr = 0; - asynStatus status; - - status = pasynManager->getAddr(pasynUser,&addr); - if(status!=asynSuccess) return status; - - getAddr(addr,&primaryAddr,&secondaryAddr); - - if(DEBUG)printf("drvGpibBoard:ifc!!\n"); - - asynPrint(pasynUser, ASYN_TRACE_FLOW, - "%s ifc\n",pGpibBoardPvt->portName); - - ibsic(pGpibBoardPvt->ud); - - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - - return asynSuccess; + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + int addr=0; + int primaryAddr = 0; + int secondaryAddr = 0; + asynStatus status; + + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + + getAddr(addr,&primaryAddr,&secondaryAddr); + + if(DEBUG)printf("drvGpibBoard:ifc!!\n"); + + asynPrint(pasynUser, ASYN_TRACE_FLOW, + "%s ifc\n",pGpibBoardPvt->portName); + + ibsic(pGpibBoardPvt->ud); + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + + return asynSuccess; } static asynStatus ren(void *pdrvPvt,asynUser *pasynUser, int onOff) -{ - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - int addr=0; - int primaryAddr = 0; - int secondaryAddr = 0; - asynStatus status; - - status = pasynManager->getAddr(pasynUser,&addr); - if(status!=asynSuccess) return status; - - getAddr(addr,&primaryAddr,&secondaryAddr); - - if(DEBUG)printf("drvGpibBoard:ren!!\n"); - - asynPrint(pasynUser, ASYN_TRACE_FLOW, - "%s ren %s\n",pGpibBoardPvt->portName,(onOff ? "On" : "Off")); - - ibsre(pGpibBoardPvt->ud,onOff); +{ + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + int addr=0; + int primaryAddr = 0; + int secondaryAddr = 0; + asynStatus status; - status=checkError(pdrvPvt,pasynUser,addr); - if(status!=asynSuccess)return status; - - return asynSuccess; + status = pasynManager->getAddr(pasynUser,&addr); + if(status!=asynSuccess) return status; + + getAddr(addr,&primaryAddr,&secondaryAddr); + + if(DEBUG)printf("drvGpibBoard:ren!!\n"); + + asynPrint(pasynUser, ASYN_TRACE_FLOW, + "%s ren %s\n",pGpibBoardPvt->portName,(onOff ? "On" : "Off")); + + ibsre(pGpibBoardPvt->ud,onOff); + + status=checkError(pdrvPvt,pasynUser,addr); + if(status!=asynSuccess)return status; + + return asynSuccess; } @@ -770,180 +764,180 @@ static asynStatus ren(void *pdrvPvt,asynUser *pasynUser, int onOff) static asynStatus srqStatus (void *pdrvPvt,int *isSet) { - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - - if(DEBUG)printf("drvGpibBoard:srqStatus!!\n"); - - *isSet=pGpibBoardPvt->srqHappened; - - pGpibBoardPvt->srqHappened = 0; - - return asynSuccess; + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + + if(DEBUG)printf("drvGpibBoard:srqStatus!!\n"); + + *isSet=pGpibBoardPvt->srqHappened; + + pGpibBoardPvt->srqHappened = 0; + + return asynSuccess; } static asynStatus srqEnable (void *pdrvPvt, int onOff) { - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - if(DEBUG)printf("drvGpibBoard:srqEnable\n"); + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + if(DEBUG)printf("drvGpibBoard:srqEnable\n"); - pGpibBoardPvt->srqEnabled = (onOff != 0); - - return asynSuccess; + pGpibBoardPvt->srqEnabled = (onOff != 0); + + return asynSuccess; } static asynStatus serialPollBegin (void *pdrvPvt) { - /*not used*/ - return asynSuccess; + /*not used*/ + return asynSuccess; } static asynStatus serialPoll (void *pdrvPvt, int addr, double timeout,int *statusByte) { - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - char serialPollByte = 0; - int ibsta; - int primaryAddr = 0; - int secondaryAddr = 0; - - getAddr(addr,&primaryAddr,&secondaryAddr); - - if(DEBUG){ - printf("drvGpibBoard:serialPoll!!\n"); - printf("ADDR: %d\n",addr); - printf("uddev: %d\n",pGpibBoardPvt->uddev[primaryAddr][secondaryAddr]); - } - - /*set timeout*/ - ibsta=ibtmo(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],sec_to_timeout(timeout)); - if(ibsta&TIMO) - return asynTimeout; - if(ibsta&ERR) - return asynError; - - - /*serial poll*/ - ibsta=ibrsp(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],&serialPollByte); - if(ibsta&TIMO) - return asynTimeout; - if(ibsta&ERR) - return asynError; - - *statusByte = (int)serialPollByte; - - return asynSuccess; + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + char serialPollByte = 0; + int ibsta; + int primaryAddr = 0; + int secondaryAddr = 0; + + getAddr(addr,&primaryAddr,&secondaryAddr); + + if(DEBUG){ + printf("drvGpibBoard:serialPoll!!\n"); + printf("ADDR: %d\n",addr); + printf("uddev: %d\n",pGpibBoardPvt->uddev[primaryAddr][secondaryAddr]); + } + + /*set timeout*/ + ibsta=ibtmo(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],sec_to_timeout(timeout)); + if(ibsta&TIMO) + return asynTimeout; + if(ibsta&ERR) + return asynError; + + + /*serial poll*/ + ibsta=ibrsp(pGpibBoardPvt->uddev[primaryAddr][secondaryAddr],&serialPollByte); + if(ibsta&TIMO) + return asynTimeout; + if(ibsta&ERR) + return asynError; + + *statusByte = (int)serialPollByte; + + return asynSuccess; } static asynStatus serialPollEnd (void *pdrvPvt) { - /*not used*/ - return asynSuccess; + /*not used*/ + return asynSuccess; } asynStatus checkError(void *pdrvPvt,asynUser *pasynUser,int addr) { - GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; - - pGpibBoardPvt->ibsta=ThreadIbsta(); - pGpibBoardPvt->iberr=ThreadIberr(); - - if(DEBUG){ - printf("drvGpibBoard:checkIberr\n"); - printf("ibsta: %d\n",pGpibBoardPvt->ibsta); - - if(pGpibBoardPvt->ibsta & DCAS) - printf("IBSTA bit 0\n"); - if(pGpibBoardPvt->ibsta & DTAS) - printf("IBSTA bit 1\n"); - if(pGpibBoardPvt->ibsta & LACS) - printf("IBSTA bit 2\n"); - if(pGpibBoardPvt->ibsta & TACS) - printf("IBSTA bit 3\n"); - if(pGpibBoardPvt->ibsta & ATN) - printf("IBSTA bit 4\n"); - if(pGpibBoardPvt->ibsta & CIC) - printf("IBSTA bit 5\n"); - if(pGpibBoardPvt->ibsta & REM) - printf("IBSTA bit 6\n"); - if(pGpibBoardPvt->ibsta & LOK) - printf("IBSTA bit 7\n"); - if(pGpibBoardPvt->ibsta & CMPL) - printf("IBSTA bit 8\n"); - if(pGpibBoardPvt->ibsta & EVENT) - printf("IBSTA bit 9\n"); - if(pGpibBoardPvt->ibsta & SPOLL) - printf("IBSTA bit 10\n"); - if(pGpibBoardPvt->ibsta & RQS) - printf("IBSTA bit 11\n"); - if(pGpibBoardPvt->ibsta & SRQI) - printf("IBSTA bit 12\n"); - if(pGpibBoardPvt->ibsta & END) - printf("IBSTA bit 13\n"); - if(pGpibBoardPvt->ibsta & TIMO) - printf("IBSTA bit 14\n"); - if(pGpibBoardPvt->ibsta & ERR) - printf("IBSTA bit 15\n"); - - printf("iberr: %d\n",pGpibBoardPvt->iberr); - - } - - if(pGpibBoardPvt->ibsta & TIMO){ - asynPrint(pasynUser,ASYN_TRACE_ERROR,"%s addr %d : device timed out.\n",pGpibBoardPvt->portName,addr); - return asynTimeout; - } - - if(pGpibBoardPvt->ibsta & ERR){ - asynPrint(pasynUser,ASYN_TRACE_ERROR,"%s addr %d : %s.\n",pGpibBoardPvt->portName,addr,gpib_error_string(pGpibBoardPvt->iberr)); - - return asynError; - } - - return asynSuccess; + GpibBoardPvt *pGpibBoardPvt = (GpibBoardPvt *)pdrvPvt; + + pGpibBoardPvt->ibsta=ThreadIbsta(); + pGpibBoardPvt->iberr=ThreadIberr(); + + if(DEBUG){ + printf("drvGpibBoard:checkIberr\n"); + printf("ibsta: %d\n",pGpibBoardPvt->ibsta); + + if(pGpibBoardPvt->ibsta & DCAS) + printf("IBSTA bit 0\n"); + if(pGpibBoardPvt->ibsta & DTAS) + printf("IBSTA bit 1\n"); + if(pGpibBoardPvt->ibsta & LACS) + printf("IBSTA bit 2\n"); + if(pGpibBoardPvt->ibsta & TACS) + printf("IBSTA bit 3\n"); + if(pGpibBoardPvt->ibsta & ATN) + printf("IBSTA bit 4\n"); + if(pGpibBoardPvt->ibsta & CIC) + printf("IBSTA bit 5\n"); + if(pGpibBoardPvt->ibsta & REM) + printf("IBSTA bit 6\n"); + if(pGpibBoardPvt->ibsta & LOK) + printf("IBSTA bit 7\n"); + if(pGpibBoardPvt->ibsta & CMPL) + printf("IBSTA bit 8\n"); + if(pGpibBoardPvt->ibsta & EVENT) + printf("IBSTA bit 9\n"); + if(pGpibBoardPvt->ibsta & SPOLL) + printf("IBSTA bit 10\n"); + if(pGpibBoardPvt->ibsta & RQS) + printf("IBSTA bit 11\n"); + if(pGpibBoardPvt->ibsta & SRQI) + printf("IBSTA bit 12\n"); + if(pGpibBoardPvt->ibsta & END) + printf("IBSTA bit 13\n"); + if(pGpibBoardPvt->ibsta & TIMO) + printf("IBSTA bit 14\n"); + if(pGpibBoardPvt->ibsta & ERR) + printf("IBSTA bit 15\n"); + + printf("iberr: %d\n",pGpibBoardPvt->iberr); + + } + + if(pGpibBoardPvt->ibsta & TIMO){ + asynPrint(pasynUser,ASYN_TRACE_ERROR,"%s addr %d : device timed out.\n",pGpibBoardPvt->portName,addr); + return asynTimeout; + } + + if(pGpibBoardPvt->ibsta & ERR){ + asynPrint(pasynUser,ASYN_TRACE_ERROR,"%s addr %d : %s.\n",pGpibBoardPvt->portName,addr,gpib_error_string(pGpibBoardPvt->iberr)); + + return asynError; + } + + return asynSuccess; } unsigned int sec_to_timeout( double sec ) { - if( sec <= 0 ) return TNONE; - else if( sec <= .00001 ) return T10us; - else if( sec <= .00003 ) return T30us; - else if( sec <= .0001 ) return T100us; - else if( sec <= .0003 ) return T300us; - else if( sec <= .001 ) return T1ms; - else if( sec <= .003 ) return T3ms; - else if( sec <= .01 ) return T10ms; - else if( sec <= .03 ) return T30ms; - else if( sec <= .1 ) return T100ms; - else if( sec <= .3 ) return T300ms; - else if( sec <= 1 ) return T1s; - else if( sec <= 3 ) return T3s; - else if( sec <= 10 ) return T10s; - else if( sec <= 30 ) return T30s; - else if( sec <= 100 ) return T100s; - else if( sec <= 300 ) return T300s; - else if( sec <= 1000 ) return T1000s; - return TNONE; + if( sec <= 0 ) return TNONE; + else if( sec <= .00001 ) return T10us; + else if( sec <= .00003 ) return T30us; + else if( sec <= .0001 ) return T100us; + else if( sec <= .0003 ) return T300us; + else if( sec <= .001 ) return T1ms; + else if( sec <= .003 ) return T3ms; + else if( sec <= .01 ) return T10ms; + else if( sec <= .03 ) return T30ms; + else if( sec <= .1 ) return T100ms; + else if( sec <= .3 ) return T300ms; + else if( sec <= 1 ) return T1s; + else if( sec <= 3 ) return T3s; + else if( sec <= 10 ) return T10s; + else if( sec <= 30 ) return T30s; + else if( sec <= 100 ) return T100s; + else if( sec <= 300 ) return T300s; + else if( sec <= 1000 ) return T1000s; + return TNONE; } static void srqCallback(CALLBACK *pcallback) { - GpibBoardPvt *pGpibBoardPvt; + GpibBoardPvt *pGpibBoardPvt; - callbackGetUser(pGpibBoardPvt,pcallback); - if(!pGpibBoardPvt->srqEnabled) return; - pGpibBoardPvt->srqHappened = 1; - pasynGpib->srqHappened(pGpibBoardPvt->asynGpibPvt); + callbackGetUser(pGpibBoardPvt,pcallback); + if(!pGpibBoardPvt->srqEnabled) return; + pGpibBoardPvt->srqHappened = 1; + pasynGpib->srqHappened(pGpibBoardPvt->asynGpibPvt); } void getAddr(int addr,int *primAddr,int *secAddr) { - if(addr < 100){ - *primAddr = addr; - return; - } - *primAddr = addr/100; - *secAddr = addr%100; - return; + if(addr < 100){ + *primAddr = addr; + return; + } + *primAddr = addr/100; + *secAddr = addr%100; + return; } @@ -953,10 +947,10 @@ int GpibBoardDriverConfig(char *name,int autoConnect,int boardIndex,double timeo GpibBoardPvt *pGpibBoardPvt; int size; asynStatus status; - + if(DEBUG) printf("GpibBoardDriverConfig\n"); - - + + size=sizeof(GpibBoardPvt)+strlen(name)+1; pGpibBoardPvt=callocMustSucceed(size,sizeof(char),"GpibBoardDriverConfig"); pGpibBoardPvt->portName =(char *) (pGpibBoardPvt+1); @@ -965,26 +959,26 @@ int GpibBoardDriverConfig(char *name,int autoConnect,int boardIndex,double timeo pGpibBoardPvt->timeout=sec_to_timeout(timeout); callbackSetCallback(srqCallback,&pGpibBoardPvt->callback); callbackSetUser(pGpibBoardPvt,&pGpibBoardPvt->callback); - + pGpibBoardPvt->asynGpibPvt = pasynGpib->registerPort(pGpibBoardPvt->portName, - ASYN_MULTIDEVICE|ASYN_CANBLOCK,autoConnect,&GpibBoardDriver,pGpibBoardPvt,priority,0); + ASYN_MULTIDEVICE|ASYN_CANBLOCK,autoConnect,&GpibBoardDriver,pGpibBoardPvt,priority,0); pGpibBoardPvt->option.interfaceType=asynOptionType; pGpibBoardPvt->option.pinterface=(void *) &GpibBoardOption; pGpibBoardPvt->option.drvPvt= pGpibBoardPvt; status = pasynManager->registerInterface(pGpibBoardPvt->portName,&pGpibBoardPvt->option); - + if(status==asynError){ - errlogPrintf("GpibBoardDriverConfig: Can't register option.\n"); - return -1; + errlogPrintf("GpibBoardDriverConfig: Can't register option.\n"); + return -1; } - + pGlobalGpibBoardPvt = pGpibBoardPvt; - + /*register for init */ initHookRegister(poll_worker_starter); - + return 0; } diff --git a/asyn/miscellaneous/asynInterposeCom.c b/asyn/miscellaneous/asynInterposeCom.c index 5491bab..021675d 100644 --- a/asyn/miscellaneous/asynInterposeCom.c +++ b/asyn/miscellaneous/asynInterposeCom.c @@ -1,6 +1,6 @@ -/* +/* * RFC 2117 support for remote serial ports - * + * * Author: W. Eric Norum * "$Date: 2011/01/12 00:13:59 $ (UTC)" */ @@ -20,8 +20,6 @@ #include #include -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynOctet.h" #include "asynOption.h" @@ -44,7 +42,7 @@ #define CPO_SET_BAUDRATE 1 /* Comand port option set baud rate */ #define CPO_SET_DATASIZE 2 /* Comand port option set data size */ #define CPO_SET_PARITY 3 /* Comand port option set parity */ -# define CPO_PARITY_NONE 1 +# define CPO_PARITY_NONE 1 # define CPO_PARITY_ODD 2 # define CPO_PARITY_EVEN 3 # define CPO_PARITY_MARK 4 @@ -78,13 +76,13 @@ typedef struct interposePvt { int stop; int flow; - char *xBuf; /* Buffer for transmit IAC stuffing */ + char *xBuf; /* Buffer for transmit IAC stuffing */ size_t xBufCapacity; } interposePvt; /* * Fetch next character from device - * Inefficient, but + * Inefficient, but * a) this is likely only happening during IOC startup * b) the replies from the device are fairly short */ @@ -169,7 +167,7 @@ writeIt(void *ppvt, asynUser *pasynUser, memcpy(dst, data, nCopy); dst += nCopy; if (iac != NULL) { - *dst++ = C_IAC; + *dst++ = (char)C_IAC; nIAC++; } nLeft -= nCopy; @@ -202,7 +200,7 @@ readIt(void *ppvt, asynUser *pasynUser, char *base = data; int unstuffed = 0; asynStatus status; - + status = pinterposePvt->pasynOctetDrv->read(pinterposePvt->drvOctetPvt, pasynUser, data, maxchars, &nRead, &eom); if (status != asynSuccess) @@ -330,7 +328,7 @@ willdo(interposePvt *pinterposePvt, asynUser *pasynUser, int command, int code) int wd; size_t nbytes; - cbuf[0] = C_IAC; + cbuf[0] = (char)C_IAC; cbuf[1] = command; cbuf[2] = code; status = pinterposePvt->pasynOctetDrv->write(pinterposePvt->drvOctetPvt, @@ -345,7 +343,7 @@ willdo(interposePvt *pinterposePvt, asynUser *pasynUser, int command, int code) case EOF: return asynError; case C_IAC: break; case C_SE: break; - + case C_DO: case C_DONT: wd = c; @@ -418,12 +416,12 @@ sbComPortOption(interposePvt *pinterposePvt, asynUser *pasynUser, const char *xB int c; size_t nbytes; - cbuf[0] = C_IAC; - cbuf[1] = C_SB; + cbuf[0] = (char)C_IAC; + cbuf[1] = (char)C_SB; cbuf[2] = SB_COM_PORT_OPTION; memcpy(cbuf+3, xBuf, xLen); - cbuf[3+xLen+0] = C_IAC; - cbuf[3+xLen+1] = C_SE; + cbuf[3+xLen+0] = (char)C_IAC; + cbuf[3+xLen+1] = (char)C_SE; status = pinterposePvt->pasynOctetDrv->write(pinterposePvt->drvOctetPvt, pasynUser, cbuf, 5+xLen, &nbytes); if (status != asynSuccess) @@ -677,11 +675,11 @@ getOption(void *ppvt, asynUser *pasynUser, const char *key, char *val, int valSi return status; } -static asynOption optionMethods = { setOption, getOption }; +static asynOption optionMethods = { setOption, getOption }; static asynStatus restoreSettings(interposePvt *pinterposePvt, asynUser *pasynUser) -{ +{ asynStatus s; int i; const char *keys[] = { "baud", "bits", "parity", "stop", "crtscts", "ixon" }; @@ -726,7 +724,7 @@ exceptionHandler(asynUser *pasynUser, asynException exception) } } -epicsShareFunc int +ASYN_API int asynInterposeCOM(const char *portName) { interposePvt *pinterposePvt; @@ -806,4 +804,4 @@ asynInterposeCOM(const char *portName) printf("WARNING -- Can't set serial port parameters: %s\n", pasynUser->errorMessage); return 0; -} \ No newline at end of file +} diff --git a/asyn/miscellaneous/asynInterposeCom.h b/asyn/miscellaneous/asynInterposeCom.h index c7608db..e887202 100644 --- a/asyn/miscellaneous/asynInterposeCom.h +++ b/asyn/miscellaneous/asynInterposeCom.h @@ -8,13 +8,11 @@ #ifndef asynInterposeCom_H #define asynInterposeCom_H -#include - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -epicsShareFunc int asynInterposeCOM(const char *portName); +ASYN_API int asynInterposeCOM(const char *portName); #ifdef __cplusplus } diff --git a/asyn/miscellaneous/asynInterposeDelay.c b/asyn/miscellaneous/asynInterposeDelay.c index 646540d..75a935b 100644 --- a/asyn/miscellaneous/asynInterposeDelay.c +++ b/asyn/miscellaneous/asynInterposeDelay.c @@ -3,7 +3,7 @@ /* Interpose for devices where each written char needs a delay * before sending the next char. - * + * * Author: Dirk Zimoch */ @@ -28,7 +28,7 @@ typedef struct interposePvt { void *optionPvt; double delay; }interposePvt; - + /* asynOctet methods */ static asynStatus writeIt(void *ppvt, asynUser *pasynUser, const char *data, size_t numchars, size_t *nbytesTransfered) @@ -37,7 +37,7 @@ static asynStatus writeIt(void *ppvt, asynUser *pasynUser, size_t n; size_t transfered = 0; asynStatus status = asynSuccess; - + while (transfered < numchars) { /* write one char at a time */ status = pvt->pasynOctetDrv->write(pvt->octetPvt, @@ -128,7 +128,7 @@ static asynOctet octet = { registerInterruptUser, cancelInterruptUser, setInputEos, getInputEos, setOutputEos, getOutputEos }; - + /* asynOption methods */ static asynStatus @@ -170,9 +170,9 @@ setOption(void *ppvt, asynUser *pasynUser, const char *key, const char *val) static asynOption option = { setOption, getOption }; - -epicsShareFunc int + +ASYN_API int asynInterposeDelay(const char *portName, int addr, double delay) { interposePvt *pvt; @@ -187,7 +187,7 @@ asynInterposeDelay(const char *portName, int addr, double delay) status = pasynManager->interposeInterface(portName, addr, &pvt->octet, &poctetasynInterface); if ((status!=asynSuccess) || !poctetasynInterface) { - printf("%s interposeInterface asynOctetType failed.\n", portName); + printf("%s interposeInterface asynOctetType failed.\n", portName); free(pvt); return -1; } @@ -217,7 +217,7 @@ static const iocshArg iocshArg1 = {"addr", iocshArgInt}; static const iocshArg iocshArg2 = {"delay(sec)", iocshArgDouble }; static const iocshArg *iocshArgs[] = {&iocshArg0, & iocshArg1, &iocshArg2}; - + static const iocshFuncDef asynInterposeDelayFuncDef = {"asynInterposeDelay", 3, iocshArgs}; diff --git a/asyn/miscellaneous/asynInterposeEcho.c b/asyn/miscellaneous/asynInterposeEcho.c index 7b3eab3..1fe96b9 100644 --- a/asyn/miscellaneous/asynInterposeEcho.c +++ b/asyn/miscellaneous/asynInterposeEcho.c @@ -3,7 +3,7 @@ /* Interpose for devices where each written char needs to read back * before sending the next char. - * + * * Author: Dirk Zimoch */ @@ -22,7 +22,7 @@ #elif defined(_WIN32) #define Z "I" #else -#define Z +#define Z #endif /* compatibility with older EPICS 3.14 versions */ @@ -46,7 +46,7 @@ static asynStatus writeIt(void *ppvt, asynUser *pasynUser, char echo[4]; asynStatus status = asynSuccess; int eomReason; - + while (transfered < numchars) { /* write one char at a time */ status = pvt->pasynOctetDrv->write(pvt->drvPvt, @@ -162,7 +162,7 @@ static asynOctet octet = { }; /* asynOctet methods */ -epicsShareFunc int +ASYN_API int asynInterposeEcho(const char *portName, int addr) { interposePvt *pvt; @@ -176,7 +176,7 @@ asynInterposeEcho(const char *portName, int addr) status = pasynManager->interposeInterface(portName, addr, &pvt->octet, &poctetasynInterface); if ((status!=asynSuccess) || !poctetasynInterface) { - printf("%s interposeInterface failed.\n", portName); + printf("%s interposeInterface failed.\n", portName); free(pvt); return -1; } @@ -190,7 +190,7 @@ static const iocshArg iocshArg0 = {"portName", iocshArgString}; static const iocshArg iocshArg1 = {"addr", iocshArgInt}; static const iocshArg *iocshArgs[] = {&iocshArg0, & iocshArg1}; - + static const iocshFuncDef asynInterposeEchoFuncDef = {"asynInterposeEcho", 2, iocshArgs}; diff --git a/asyn/miscellaneous/asynInterposeEos.c b/asyn/miscellaneous/asynInterposeEos.c index 558c0a7..fbc69f0 100644 --- a/asyn/miscellaneous/asynInterposeEos.c +++ b/asyn/miscellaneous/asynInterposeEos.c @@ -8,7 +8,7 @@ * found in file LICENSE that is included with this distribution. ***********************************************************************/ -/* +/* * End-of-string processing for asyn * * Author: Eric Norum @@ -53,7 +53,7 @@ typedef struct eosPvt { char eosOut[2]; int eosOutLen; }eosPvt; - + /* Connect/disconnect handling */ static void eosInExceptionHandler(asynUser *pasynUser,asynException exception); @@ -80,8 +80,8 @@ static asynOctet octet = { registerInterruptUser, cancelInterruptUser, setInputEos,getInputEos,setOutputEos,getOutputEos }; - -epicsShareFunc int asynInterposeEosConfig(const char *portName,int addr, + +ASYN_API int asynInterposeEosConfig(const char *portName,int addr, int processEosIn,int processEosOut) { eosPvt *peosPvt; @@ -138,7 +138,7 @@ epicsShareFunc int asynInterposeEosConfig(const char *portName,int addr, } return(0); } - + static void eosInExceptionHandler(asynUser *pasynUser,asynException exception) { eosPvt *peosPvt = (eosPvt *)pasynUser->userPvt; @@ -149,7 +149,7 @@ static void eosInExceptionHandler(asynUser *pasynUser,asynException exception) peosPvt->eosInMatch = 0; } } - + /* asynOctet methods */ static asynStatus writeIt(void *ppvt,asynUser *pasynUser, const char *data,size_t numchars,size_t *nbytesTransfered) @@ -158,7 +158,7 @@ static asynStatus writeIt(void *ppvt,asynUser *pasynUser, asynStatus status; size_t nbytesActual = 0; - if(!peosPvt->processEosOut) { + if((!peosPvt->processEosOut) || (peosPvt->eosOutLen <= 0)) { return peosPvt->poctet->write(peosPvt->octetPvt, pasynUser,data,numchars,nbytesTransfered); } @@ -222,7 +222,7 @@ static asynStatus readIt(void *ppvt,asynUser *pasynUser, } } if (nRead >= maxchars) { - eom |= ASYN_EOM_CNT; + eom = ASYN_EOM_CNT; break; } continue; @@ -232,7 +232,7 @@ static asynStatus readIt(void *ppvt,asynUser *pasynUser, pasynUser,peosPvt->inBuf,peosPvt->inBufSize,&thisRead,&eom); if(status==asynSuccess) { asynPrintIO(pasynUser,ASYN_TRACEIO_FILTER,peosPvt->inBuf,thisRead, - "%s read %d bytes eom=%d\n",peosPvt->portName, thisRead, eom); + "%s read %llu bytes eom=%d\n",peosPvt->portName, (epicsUInt64)thisRead, eom); /* * Read could have returned with ASYN_EOM_CNT set in eom because * the number of octets available exceeded inBufSize. This is not @@ -274,7 +274,7 @@ static asynStatus registerInterruptUser(void *ppvt,asynUser *pasynUser, return peosPvt->poctet->registerInterruptUser(peosPvt->octetPvt, pasynUser,callback,userPvt,registrarPvt); -} +} static asynStatus cancelInterruptUser(void *drvPvt,asynUser *pasynUser, void *registrarPvt) @@ -283,7 +283,7 @@ static asynStatus cancelInterruptUser(void *drvPvt,asynUser *pasynUser, return peosPvt->poctet->cancelInterruptUser(peosPvt->octetPvt, pasynUser,registrarPvt); -} +} static asynStatus setInputEos(void *ppvt,asynUser *pasynUser, const char *eos,int eoslen) @@ -388,7 +388,7 @@ static asynStatus getOutputEos(void *ppvt,asynUser *pasynUser, "%s get Eos %d\n", peosPvt->portName, *eoslen); return asynSuccess; } - + /* register asynInterposeEosConfig*/ static const iocshArg asynInterposeEosConfigArg0 = { "portName", iocshArgString }; @@ -398,7 +398,7 @@ static const iocshArg asynInterposeEosConfigArg2 = { "processIn (0,1) => (no,yes)", iocshArgInt }; static const iocshArg asynInterposeEosConfigArg3 = { "processOut (0,1) => (no,yes)", iocshArgInt }; -static const iocshArg *asynInterposeEosConfigArgs[] = +static const iocshArg *asynInterposeEosConfigArgs[] = {&asynInterposeEosConfigArg0,&asynInterposeEosConfigArg1, &asynInterposeEosConfigArg2,&asynInterposeEosConfigArg3}; static const iocshFuncDef asynInterposeEosConfigFuncDef = diff --git a/asyn/miscellaneous/asynInterposeEos.h b/asyn/miscellaneous/asynInterposeEos.h index 6a4da59..bad184f 100644 --- a/asyn/miscellaneous/asynInterposeEos.h +++ b/asyn/miscellaneous/asynInterposeEos.h @@ -8,7 +8,7 @@ * found in file LICENSE that is included with this distribution. ***********************************************************************/ -/* +/* * End-of-string processing for asyn * * Author: Eric Norum @@ -17,13 +17,11 @@ #ifndef asynInterposeEos_H #define asynInterposeEos_H -#include - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -epicsShareFunc int asynInterposeEosConfig(const char *portName,int addr, +ASYN_API int asynInterposeEosConfig(const char *portName,int addr, int processEosIn,int processEosOut); #ifdef __cplusplus diff --git a/asyn/miscellaneous/asynInterposeFlush.c b/asyn/miscellaneous/asynInterposeFlush.c index 3e2f186..12391c7 100644 --- a/asyn/miscellaneous/asynInterposeFlush.c +++ b/asyn/miscellaneous/asynInterposeFlush.c @@ -9,7 +9,7 @@ ***********************************************************************/ /*test process module for asyn support*/ -/* +/* * Author: Marty Kraimer */ @@ -37,7 +37,7 @@ typedef struct interposePvt { void *drvPvt; double timeout; }interposePvt; - + /* asynOctet methods */ static asynStatus writeIt(void *ppvt,asynUser *pasynUser, const char *data,size_t numchars,size_t *nbytesTransfered); @@ -61,8 +61,8 @@ static asynOctet octet = { registerInterruptUser,cancelInterruptUser, setInputEos,getInputEos,setOutputEos,getOutputEos }; - -epicsShareFunc int + +ASYN_API int asynInterposeFlushConfig(const char *portName,int addr,int timeout) { interposePvt *pinterposePvt; @@ -89,7 +89,7 @@ asynInterposeFlushConfig(const char *portName,int addr,int timeout) pinterposePvt->drvPvt = poctetasynInterface->drvPvt; return(0); } - + /* asynOctet methods */ static asynStatus writeIt(void *ppvt,asynUser *pasynUser, const char *data,size_t numchars,size_t *nbytesTransfered) @@ -186,7 +186,7 @@ static asynStatus getOutputEos(void *ppvt,asynUser *pasynUser, return pinterposePvt->pasynOctetDrv->getOutputEos(pinterposePvt->drvPvt, pasynUser,eos,eossize,eoslen); } - + /* register asynInterposeFlushConfig*/ static const iocshArg asynInterposeFlushConfigArg0 = { "portName", iocshArgString }; @@ -194,7 +194,7 @@ static const iocshArg asynInterposeFlushConfigArg1 = { "addr", iocshArgInt }; static const iocshArg asynInterposeFlushConfigArg2 = { "timeout", iocshArgDouble }; -static const iocshArg *asynInterposeFlushConfigArgs[] = +static const iocshArg *asynInterposeFlushConfigArgs[] = {&asynInterposeFlushConfigArg0,&asynInterposeFlushConfigArg1, &asynInterposeFlushConfigArg2}; static const iocshFuncDef asynInterposeFlushConfigFuncDef = diff --git a/asyn/miscellaneous/asynInterposeFlush.h b/asyn/miscellaneous/asynInterposeFlush.h index 9b63aa9..c23d831 100644 --- a/asyn/miscellaneous/asynInterposeFlush.h +++ b/asyn/miscellaneous/asynInterposeFlush.h @@ -11,13 +11,11 @@ #ifndef asynInterposeEos_H #define asynInterposeEos_H -#include - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -epicsShareFunc int asynInterposeFlushConfig( +ASYN_API int asynInterposeFlushConfig( const char *portName,int addr, int timeout); #ifdef __cplusplus diff --git a/asyn/miscellaneous/asynShellCommands.c b/asyn/miscellaneous/asynShellCommands.c index c33bbed..2b6f666 100644 --- a/asyn/miscellaneous/asynShellCommands.c +++ b/asyn/miscellaneous/asynShellCommands.c @@ -29,8 +29,6 @@ #include #endif -#define epicsExportSharedSymbols -#include #include "asynDriver.h" #include "asynOctet.h" #include "asynOption.h" @@ -99,12 +97,12 @@ static void setOption(asynUser *pasynUser) status = poptionargs->pasynOption->setOption(poptionargs->drvPvt, pasynUser, poptionargs->key, poptionargs->val); - if(status!=asynSuccess) + if(status!=asynSuccess) printf("setOption failed %s\n", pasynUser->errorMessage); epicsEventSignal(poptionargs->done); } -epicsShareFunc int +ASYN_API int asynSetOption(const char *portName, int addr, const char *key, const char *val) { asynUser *pasynUser; @@ -137,7 +135,7 @@ epicsShareFunc int pasynManager->freeAsynUser(pasynUser); return asynSuccess; } - + static void showOption(asynUser *pasynUser) { showOptionArgs *poptionargs = (showOptionArgs *)pasynUser->userPvt; @@ -152,7 +150,7 @@ static void showOption(asynUser *pasynUser) epicsEventSignal(poptionargs->done); } -epicsShareFunc int +ASYN_API int asynShowOption(const char *portName, int addr,const char *key) { asynInterface *pasynInterface; @@ -184,7 +182,7 @@ epicsShareFunc int pasynManager->freeAsynUser(pasynUser); return asynSuccess; } - + enum eosType { eosIn, eosOut }; typedef struct eosArgs { enum eosType type; @@ -309,7 +307,7 @@ asynShowEos(const char *portName, int addr, enum eosType type) } return eosargs.status; } - + /* Default timeout for reading */ #define READ_TIMEOUT 1.0 /* Default buffer size */ @@ -329,7 +327,7 @@ static asynIOPvt* asynFindEntry(const char *name) return((asynIOPvt *)hashEntry->userPvt); } -epicsShareFunc int +ASYN_API int asynOctetConnect(const char *entry, const char *port, int addr, int timeout, int buffer_len, const char *drvInfo) { @@ -351,7 +349,7 @@ epicsShareFunc int return(-1); } hashEntry = gphAdd(asynHash, epicsStrDup(entry), NULL); - pPvt = (asynIOPvt *)calloc(1, sizeof(asynIOPvt)); + pPvt = (asynIOPvt *)calloc(1, sizeof(asynIOPvt)); hashEntry->userPvt = pPvt; pPvt->pasynUser = pasynUser; pPvt->timeout = timeout ? (double)timeout : READ_TIMEOUT; @@ -362,7 +360,7 @@ epicsShareFunc int return(0); } -epicsShareFunc int +ASYN_API int asynOctetDisconnect(const char *entry) { asynIOPvt *pPvt; @@ -395,7 +393,7 @@ epicsShareFunc int return(0); } -epicsShareFunc int +ASYN_API int asynOctetRead(const char *entry, int nread) { asynStatus status; @@ -426,7 +424,7 @@ epicsShareFunc int return (int)ninp; } -epicsShareFunc int +ASYN_API int asynOctetWrite(const char *entry, const char *output) { asynStatus status; @@ -459,7 +457,7 @@ epicsShareFunc int return (int)nout; } -epicsShareFunc int +ASYN_API int asynOctetWriteRead(const char *entry, const char *output, int nread) { asynStatus status; @@ -501,7 +499,7 @@ epicsShareFunc int return (int)ninp; } -epicsShareFunc int +ASYN_API int asynOctetFlush(const char *entry) { asynIOPvt *pPvt; @@ -523,59 +521,59 @@ epicsShareFunc int } return(0); } - -epicsShareFunc int + +ASYN_API int asynOctetSetInputEos(const char *portName, int addr, const char *eosin) { return asynSetEos(portName, addr, eosIn, eosin) == asynSuccess ? 0 : -1; } -epicsShareFunc int +ASYN_API int asynOctetGetInputEos(const char *portName, int addr) { return asynShowEos(portName, addr, eosIn) == asynSuccess ? 0 : -1; } -epicsShareFunc int +ASYN_API int asynOctetSetOutputEos(const char *portName, int addr, const char *eosout) { return asynSetEos(portName, addr, eosOut, eosout)==asynSuccess ? 0 : -1; } -epicsShareFunc int +ASYN_API int asynOctetGetOutputEos(const char *portName, int addr) { return asynShowEos(portName, addr, eosOut) == asynSuccess ? 0 : -1; } -epicsShareFunc int +ASYN_API int asynWaitConnect(const char *portName, double timeout) { asynUser *pasynUser=NULL; int isConnected=0; asynStatus status; - + pasynUser = pasynManager->createAsynUser(0,0); if (!pasynUser) { - asynPrint(pasynUser, ASYN_TRACE_ERROR, - "waitConnect: port=%s error calling createAsynUser\n", + asynPrint(pasynUser, ASYN_TRACE_ERROR, + "waitConnect: port=%s error calling createAsynUser\n", portName); return asynError; } status = pasynManager->connectDevice(pasynUser, portName, -1); if (status) { - asynPrint(pasynUser, ASYN_TRACE_ERROR, + asynPrint(pasynUser, ASYN_TRACE_ERROR, "waitConnect: port=%s error calling connectDevice\n", portName); return asynError; } status = pasynManager->waitConnect(pasynUser, timeout); if (status == asynSuccess) isConnected = 1; - asynPrint(pasynUser, ASYN_TRACE_FLOW, - "waitConnect: port=%s exit, isConnected=%d\n", + asynPrint(pasynUser, ASYN_TRACE_FLOW, + "waitConnect: port=%s exit, isConnected=%d\n", portName, isConnected); pasynManager->freeAsynUser(pasynUser); - if (isConnected) return asynSuccess; + if (isConnected) return asynSuccess; return asynError; } @@ -585,7 +583,7 @@ static const iocshArg asynReportArg1 = {"port", iocshArgString}; static const iocshArg *const asynReportArgs[] = { &asynReportArg0,&asynReportArg1}; static const iocshFuncDef asynReportDef = {"asynReport", 2, asynReportArgs}; -epicsShareFunc int +ASYN_API int asynReport(int level, const char *portName) { pasynManager->report(stdout,level,portName); @@ -616,15 +614,40 @@ static const iocshFuncDef asynShowOptionDef = {"asynShowOption", 3, asynShowOpti static void asynShowOptionCall(const iocshArgBuf * args) { asynShowOption(args[0].sval,args[1].ival,args[2].sval); } - + static const iocshArg asynSetTraceMaskArg0 = {"portName", iocshArgString}; static const iocshArg asynSetTraceMaskArg1 = {"addr", iocshArgInt}; static const iocshArg asynSetTraceMaskArg2 = {"mask", iocshArgString}; static const iocshArg *const asynSetTraceMaskArgs[] = { &asynSetTraceMaskArg0,&asynSetTraceMaskArg1,&asynSetTraceMaskArg2}; static const iocshFuncDef asynSetTraceMaskDef = - {"asynSetTraceMask", 3, asynSetTraceMaskArgs}; -epicsShareFunc int + {"asynSetTraceMask", 3, asynSetTraceMaskArgs +#ifdef IOCSHFUNCDEF_HAS_USAGE + , +#else + }; +static const char asynSetTraceMaskUsage[] = +#endif + "Set logging level bit mask, either as a number," + " or since asyn R4-35 a combination of names.\n" + " mask bits\n" + " 0x01 - ERROR\n" + " 0x02 - DEVICE\n" + " 0x04 - FILTER\n" + " 0x08 - DRIVER\n" + " 0x10 - FLOW\n" + " 0x20 - WARNING\n" + "\n" + " eg. the following are equivalent\n" + " asynSetTraceMask MYPORT -1 0x21\n" + " asynSetTraceMask MYPORT -1 \"WARNING+ERROR\"\n" +#ifdef IOCSHFUNCDEF_HAS_USAGE + }; +#define asynSetTraceMaskUsage asynSetTraceMaskDef.usage +#else + ; +#endif +ASYN_API int asynSetTraceMask(const char *portName,int addr,int mask) { asynUser *pasynUser=NULL; @@ -675,7 +698,7 @@ static int asynTraceMaskStringToInt(const char* maskStr) { } while ((*maskStr == '|' || *maskStr == '+') && maskStr++); if (*maskStr) { - printf("Mask string invalid at \"%s\"\n", maskStr); + printf("%s\nError: Mask string invalid at \"%s\"\n", asynSetTraceMaskUsage, maskStr); } return mask; } @@ -693,8 +716,30 @@ static const iocshArg asynSetTraceIOMaskArg2 = {"mask", iocshArgString}; static const iocshArg *const asynSetTraceIOMaskArgs[] = { &asynSetTraceIOMaskArg0,&asynSetTraceIOMaskArg1,&asynSetTraceIOMaskArg2}; static const iocshFuncDef asynSetTraceIOMaskDef = - {"asynSetTraceIOMask", 3, asynSetTraceIOMaskArgs}; -epicsShareFunc int + {"asynSetTraceIOMask", 3, asynSetTraceIOMaskArgs +#ifdef IOCSHFUNCDEF_HAS_USAGE + , +#else + }; +static const char asynSetTraceIOMaskUsage[] = +#endif + "Set logging I/O print formatting bit mask, either as a number,\n" + " or since asyn R4-35 a combination of names.\n" + " mask bits\n" + " 0x01 - ASCII\n" + " 0x02 - ESCAPE\n" + " 0x04 - HEX\n" + "\n" + " eg. the following are equivalent\n" + " asynSetTraceIOMask MYPORT -1 0x6\n" + " asynSetTraceIOMask MYPORT -1 \"ESCAPE+HEX\"\n" +#ifdef IOCSHFUNCDEF_HAS_USAGE + }; +#define asynSetTraceIOMaskUsage asynSetTraceIOMaskDef.usage +#else + ; +#endif +ASYN_API int asynSetTraceIOMask(const char *portName,int addr,int mask) { asynUser *pasynUser=NULL; @@ -741,7 +786,7 @@ static int asynTraceIOMaskStringToInt(const char* maskStr) { } while ((*maskStr == '|' || *maskStr == '+') && maskStr++); if (*maskStr) { - printf("Mask string invalid at \"%s\"\n", maskStr); + printf("%s\nError: Mask string invalid at \"%s\"\n", asynSetTraceIOMaskUsage, maskStr); } return mask; } @@ -752,7 +797,7 @@ static void asynSetTraceIOMaskCall(const iocshArgBuf * args) { int mask = asynTraceIOMaskStringToInt(args[2].sval); asynSetTraceIOMask(portName,addr,mask); } - + static const iocshArg asynSetTraceInfoMaskArg0 = {"portName", iocshArgString}; static const iocshArg asynSetTraceInfoMaskArg1 = {"addr", iocshArgInt}; static const iocshArg asynSetTraceInfoMaskArg2 = {"mask", iocshArgString}; @@ -760,7 +805,7 @@ static const iocshArg *const asynSetTraceInfoMaskArgs[] = { &asynSetTraceInfoMaskArg0,&asynSetTraceInfoMaskArg1,&asynSetTraceInfoMaskArg2}; static const iocshFuncDef asynSetTraceInfoMaskDef = {"asynSetTraceInfoMask", 3, asynSetTraceInfoMaskArgs}; -epicsShareFunc int +ASYN_API int asynSetTraceInfoMask(const char *portName,int addr,int mask) { asynUser *pasynUser=NULL; @@ -818,8 +863,8 @@ static void asynSetTraceInfoMaskCall(const iocshArgBuf * args) { int mask = asynTraceInfoMaskStringToInt(args[2].sval); asynSetTraceInfoMask(portName,addr,mask); } - -epicsShareFunc int + +ASYN_API int asynSetTraceFile(const char *portName,int addr,const char *filename) { asynUser *pasynUser; @@ -868,7 +913,7 @@ static void asynSetTraceFileCall(const iocshArgBuf * args) { const char *filename = args[2].sval; asynSetTraceFile(portName,addr,filename); } - + static const iocshArg asynSetTraceIOTruncateSizeArg0 = {"portName", iocshArgString}; static const iocshArg asynSetTraceIOTruncateSizeArg1 = {"addr", iocshArgInt}; static const iocshArg asynSetTraceIOTruncateSizeArg2 = {"size", iocshArgInt}; @@ -876,7 +921,7 @@ static const iocshArg *const asynSetTraceIOTruncateSizeArgs[] = { &asynSetTraceIOTruncateSizeArg0,&asynSetTraceIOTruncateSizeArg1,&asynSetTraceIOTruncateSizeArg2}; static const iocshFuncDef asynSetTraceIOTruncateSizeDef = {"asynSetTraceIOTruncateSize", 3, asynSetTraceIOTruncateSizeArgs}; -epicsShareFunc int +ASYN_API int asynSetTraceIOTruncateSize(const char *portName,int addr,int size) { asynUser *pasynUser; @@ -902,7 +947,7 @@ static void asynSetTraceIOTruncateSizeCall(const iocshArgBuf * args) { int size = args[2].ival; asynSetTraceIOTruncateSize(portName,addr,size); } - + static const iocshArg asynEnableArg0 = {"portName", iocshArgString}; static const iocshArg asynEnableArg1 = {"addr", iocshArgInt}; static const iocshArg asynEnableArg2 = {"yesNo", iocshArgInt}; @@ -910,7 +955,7 @@ static const iocshArg *const asynEnableArgs[] = { &asynEnableArg0,&asynEnableArg1,&asynEnableArg2}; static const iocshFuncDef asynEnableDef = {"asynEnable", 3, asynEnableArgs}; -epicsShareFunc int +ASYN_API int asynEnable(const char *portName,int addr,int yesNo) { asynUser *pasynUser; @@ -944,7 +989,7 @@ static const iocshArg *const asynAutoConnectArgs[] = { &asynAutoConnectArg0,&asynAutoConnectArg1,&asynAutoConnectArg2}; static const iocshFuncDef asynAutoConnectDef = {"asynAutoConnect", 3, asynAutoConnectArgs}; -epicsShareFunc int +ASYN_API int asynAutoConnect(const char *portName,int addr,int yesNo) { asynUser *pasynUser; @@ -1128,9 +1173,9 @@ static const iocshArg asynRegisterTimeStampSourceArg0 = { "portName",iocshArgStr static const iocshArg asynRegisterTimeStampSourceArg1 = { "functionName",iocshArgString}; static const iocshArg * const asynRegisterTimeStampSourceArgs[] = { &asynRegisterTimeStampSourceArg0, &asynRegisterTimeStampSourceArg1}; -static const iocshFuncDef asynRegisterTimeStampSourceDef = +static const iocshFuncDef asynRegisterTimeStampSourceDef = {"asynRegisterTimeStampSource",2,asynRegisterTimeStampSourceArgs}; -static const iocshFuncDef asynUnregisterTimeStampSourceDef = +static const iocshFuncDef asynUnregisterTimeStampSourceDef = {"asynUnregisterTimeStampSource",1,asynRegisterTimeStampSourceArgs}; static void asynRegisterTimeStampSourceCall(const iocshArgBuf *args) @@ -1142,12 +1187,12 @@ static void asynUnregisterTimeStampSourceCall(const iocshArgBuf *args) { asynUnregisterTimeStampSource(args[0].sval); } -epicsShareFunc int asynRegisterTimeStampSource(const char *portName, const char *functionName) +ASYN_API int asynRegisterTimeStampSource(const char *portName, const char *functionName) { asynUser *pasynUser; asynStatus status; timeStampCallback pFunction; - + if (!portName || !functionName || (strlen(portName) == 0) || (strlen(functionName) == 0)) { printf("Usage: registerUserTimeStampSource portName functionName\n"); return -1; @@ -1167,11 +1212,11 @@ epicsShareFunc int asynRegisterTimeStampSource(const char *portName, const char return 0; } -epicsShareFunc int asynUnregisterTimeStampSource(const char *portName) +ASYN_API int asynUnregisterTimeStampSource(const char *portName) { asynUser *pasynUser; asynStatus status; - + if (!portName || (strlen(portName) == 0)) { printf("Usage: asynUnregisterTimeStampSource portName\n"); return -1; @@ -1195,32 +1240,32 @@ static void resetTimer(void *Pvt) timeEndPeriod(minPeriodMs); } -epicsShareFunc int asynSetMinTimerPeriod(double minPeriod) +ASYN_API int asynSetMinTimerPeriod(double minPeriod) { TIMECAPS timeCaps; MMRESULT status; - + if (minPeriodMs == 0) { /* First time */ epicsAtExit(resetTimer, 0); } else { resetTimer(0); } - + timeGetDevCaps(&timeCaps, sizeof(timeCaps)); - /* printf("Minimum time=%d, maximum time=%d, sleepQuantum=%f\n", + /* printf("Minimum time=%d, maximum time=%d, sleepQuantum=%f\n", timeCaps.wPeriodMin, timeCaps.wPeriodMax, epicsThreadSleepQuantum()); */ minPeriodMs = (int)(minPeriod*1000. + 0.5); if (minPeriodMs < timeCaps.wPeriodMin) minPeriodMs = timeCaps.wPeriodMin; if (minPeriodMs > timeCaps.wPeriodMax) minPeriodMs = timeCaps.wPeriodMax; status = timeBeginPeriod(minPeriodMs); - /* printf("Called timePeriodBegin(%d), status=%d, sleepQuantum=%f\n", + /* printf("Called timePeriodBegin(%d), status=%d, sleepQuantum=%f\n", minPeriodMs, status, epicsThreadSleepQuantum()); */ - return (int)status; + return (int)status; } #else /* _WIN32 */ -epicsShareFunc int asynSetMinTimerPeriod(double minPeriod) +ASYN_API int asynSetMinTimerPeriod(double minPeriod) { printf("asynSetMinTimerPeriod is not currently supported on this OS\n"); return -1; @@ -1229,7 +1274,7 @@ epicsShareFunc int asynSetMinTimerPeriod(double minPeriod) #endif /* _WIN32 */ static const iocshArg asynSetMinTimerPeriodArg0 = { "minimum period", iocshArgDouble }; -static const iocshArg *asynSetMinTimerPeriodArgs[] = +static const iocshArg *asynSetMinTimerPeriodArgs[] = {&asynSetMinTimerPeriodArg0}; static const iocshFuncDef asynSetMinTimerPeriodDef = {"asynSetMinTimerPeriod", 1, asynSetMinTimerPeriodArgs}; @@ -1244,7 +1289,7 @@ static const iocshArg *const asynSetQueueLockPortTimeoutArgs[] = { &asynSetQueueLockPortTimeoutArg0,&asynSetQueueLockPortTimeoutArg1}; static const iocshFuncDef asynSetQueueLockPortTimeoutDef = {"asynSetQueueLockPortTimeout", 2, asynSetQueueLockPortTimeoutArgs}; -epicsShareFunc int +ASYN_API int asynSetQueueLockPortTimeout(const char *portName, double timeout) { asynUser *pasynUser; diff --git a/asyn/miscellaneous/asynShellCommands.h b/asyn/miscellaneous/asynShellCommands.h index f916706..f9b7e58 100644 --- a/asyn/miscellaneous/asynShellCommands.h +++ b/asyn/miscellaneous/asynShellCommands.h @@ -12,62 +12,63 @@ #ifndef INCasynShellCommandsh #define INCasynShellCommandsh 1 -#include +#include + #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ -epicsShareFunc int +ASYN_API int asynSetOption(const char *portName, int addr, const char *key, const char *val); -epicsShareFunc int +ASYN_API int asynShowOption(const char *portName, int addr,const char *key); -epicsShareFunc int +ASYN_API int asynReport(int level, const char *portName); -epicsShareFunc int +ASYN_API int asynSetTraceMask(const char *portName,int addr,int mask); -epicsShareFunc int +ASYN_API int asynSetTraceIOMask(const char *portName,int addr,int mask); -epicsShareFunc int +ASYN_API int asynSetTraceInfoMask(const char *portName,int addr,int mask); -epicsShareFunc int +ASYN_API int asynSetTraceFile(const char *portName,int addr,const char *filename); -epicsShareFunc int +ASYN_API int asynSetTraceIOTruncateSize(const char *portName,int addr,int size); -epicsShareFunc int +ASYN_API int asynAutoConnect(const char *portName,int addr,int yesNo); -epicsShareFunc int +ASYN_API int asynEnable(const char *portName,int addr,int yesNo); -epicsShareFunc int +ASYN_API int asynOctetConnect(const char *entry, const char *port, int addr, int timeout, int buffer_len,const char *drvInfo); -epicsShareFunc int +ASYN_API int asynOctetDisconnect(const char *entry); -epicsShareFunc int +ASYN_API int asynWaitConnect(const char *portName, double timeout); -epicsShareFunc int +ASYN_API int asynOctetRead(const char *entry, int nread); -epicsShareFunc int +ASYN_API int asynOctetWrite(const char *entry, const char *output); -epicsShareFunc int +ASYN_API int asynOctetWriteRead(const char *entry, const char *output, int nread); -epicsShareFunc int +ASYN_API int asynOctetFlush(const char *entry); -epicsShareFunc int +ASYN_API int asynOctetSetInputEos(const char *port, int addr,const char *eos); -epicsShareFunc int +ASYN_API int asynOctetGetInputEos(const char *port, int addr); -epicsShareFunc int +ASYN_API int asynOctetSetOutputEos(const char *port, int addr,const char *eos); -epicsShareFunc int +ASYN_API int asynOctetGetOutputEos(const char *port, int addr); -epicsShareFunc int +ASYN_API int asynRegisterTimeStampSource(const char *portName, const char *functionName); -epicsShareFunc int +ASYN_API int asynUnregisterTimeStampSource(const char *portName); -epicsShareFunc int +ASYN_API int asynSetMinTimerPeriod(double period); -epicsShareFunc int +ASYN_API int asynSetQueueLockPortTimeout(const char *portName, double timeout); #ifdef __cplusplus diff --git a/asyn/ni1014/drvNi1014.c b/asyn/ni1014/drvNi1014.c index 8c7e48d..dc1e425 100644 --- a/asyn/ni1014/drvNi1014.c +++ b/asyn/ni1014/drvNi1014.c @@ -53,7 +53,7 @@ struct niport { int vector; int level; CALLBACK callback; - epicsUInt8 isr1; + epicsUInt8 isr1; epicsUInt8 isr2; int srqEnabled; transferState_t transferState; @@ -71,7 +71,7 @@ struct niport { epicsEventId waitForInterrupt; char errorMessage[ERROR_MESSAGE_BUFFER_SIZE]; }; - + static epicsUInt8 readRegister(niport *pniport, int offset); static void writeRegister(niport *pniport,int offset, epicsUInt8 value); static void printStatus(niport *pniport,const char *source); @@ -134,7 +134,7 @@ static asynGpibPort gpibPort = { gpibPortSerialPoll, gpibPortSerialPollEnd }; - + /* Register definitions */ /* All registers will be addressed as 16 bit integers */ #define PORT_REGISTER_SIZE 0x200 @@ -275,7 +275,7 @@ static epicsUInt8 readRegister(niport *pniport, int offset) volatile epicsUInt8 *pregister = (epicsUInt8 *) (((char *)pniport->registers)+offset); epicsUInt8 value; - + value = *pregister; if(ni1014Debug) { char message[100]; @@ -324,7 +324,7 @@ static void printStatus(niport *pniport, const char *source) "isr1 %2.2x isr2 %2.2x ADSR %2.2x\n", source, pniport->isr1,pniport->isr2,readRegister(pniport,ADSR)); } - + static void waitTimeout(niport *pniport,double seconds) { epicsEventWaitStatus status; @@ -375,7 +375,7 @@ static void srqCallback(CALLBACK *pcallback) if(!pniport->srqEnabled) return; pasynGpib->srqHappened(pniport->asynGpibPvt); } - + void ni1014(void *pvt) { niport *pniport = (niport *)pvt; @@ -505,7 +505,7 @@ static asynStatus writeAddr(niport *pniport,int talk, int listen, } return writeCmd(pniport,cmdbuf,lenCmd,timeout,nextState); } - + static asynStatus writeGpib(niport *pniport,const char *buf, int cnt, int *actual, int addr, double timeout) { @@ -558,7 +558,7 @@ static void gpibPortReport(void *pdrvPvt,FILE *fd,int details) fprintf(fd," gpibPort port %s vector %d base %x registers %p\n", pniport->portName,pniport->vector,pniport->base,pniport->registers); } - + static asynStatus gpibPortConnect(void *pdrvPvt,asynUser *pasynUser) { niport *pniport = (niport *)pdrvPvt; @@ -615,7 +615,7 @@ static asynStatus gpibPortConnect(void *pdrvPvt,asynUser *pasynUser) pasynManager->exceptionConnect(pasynUser); return asynSuccess; } - + static asynStatus gpibPortDisconnect(void *pdrvPvt,asynUser *pasynUser) { niport *pniport = (niport *)pdrvPvt; @@ -635,7 +635,7 @@ static asynStatus gpibPortDisconnect(void *pdrvPvt,asynUser *pasynUser) pasynManager->exceptionDisconnect(pasynUser); return asynSuccess; } - + static asynStatus gpibPortRead(void *pdrvPvt,asynUser *pasynUser, char *data,int maxchars,int *nbytesTransfered,int *eomReason) { @@ -689,7 +689,7 @@ static asynStatus gpibPortWrite(void *pdrvPvt,asynUser *pasynUser, *nbytesTransfered = actual; return status; } - + static asynStatus gpibPortFlush(void *pdrvPvt,asynUser *pasynUser) { /*Nothing to do */ @@ -742,7 +742,7 @@ static asynStatus gpibPortGetEos(void *pdrvPvt,asynUser *pasynUser, "%s addr %d gpibPortGetEos eoslen %p\n",pniport->portName,addr,eoslen); return asynSuccess; } - + static asynStatus gpibPortAddressedCmd(void *pdrvPvt,asynUser *pasynUser, const char *data, int length) { @@ -807,7 +807,7 @@ static asynStatus gpibPortIfc(void *pdrvPvt, asynUser *pasynUser) writeRegister(pniport,AUXMR,AUXCIFC); return asynSuccess; } - + static asynStatus gpibPortRen(void *pdrvPvt,asynUser *pasynUser, int onOff) { niport *pniport = (niport *)pdrvPvt; @@ -874,7 +874,7 @@ static asynStatus gpibPortSerialPollEnd(void *pdrvPvt) status = writeCmd(pniport,cmd,2,timeout,transferStateIdle); return status; } - + int ni1014Config(char *portNameA,char *portNameB, int base, int vector, int level, int priority, int noAutoConnect) { @@ -937,7 +937,7 @@ int ni1014Config(char *portNameA,char *portNameB, } return 0; } - + static const iocshArg ni1014ConfigArg0 = { "portNameA",iocshArgString}; static const iocshArg ni1014ConfigArg1 = { "portNameB",iocshArgString}; static const iocshArg ni1014ConfigArg2 = { "base",iocshArgInt}; diff --git a/asyn/vxi11/E2050Reboot.c b/asyn/vxi11/E2050Reboot.c index 1bbea0a..8425baa 100644 --- a/asyn/vxi11/E2050Reboot.c +++ b/asyn/vxi11/E2050Reboot.c @@ -23,7 +23,7 @@ #include #include - + int E2050Reboot(char * inetAddr) { struct sockaddr_in serverAddr; @@ -43,7 +43,7 @@ int E2050Reboot(char * inetAddr) status = aToIPAddr(inetAddr,23,&serverAddr); if(status) { printf("aToIPAddr failed\n"); - return(-1); + return(-1); } errno = 0; status = connect(fd,(struct sockaddr*)&serverAddr, sizeof(serverAddr)); diff --git a/asyn/vxi11/E5810Reboot.c b/asyn/vxi11/E5810Reboot.c index 93f84c9..0f33a74 100644 --- a/asyn/vxi11/E5810Reboot.c +++ b/asyn/vxi11/E5810Reboot.c @@ -23,7 +23,7 @@ #include #include - + char *defaultPassword = "E5810"; int E5810Reboot(char * inetAddr,char *password) { @@ -45,7 +45,7 @@ int E5810Reboot(char * inetAddr,char *password) status = aToIPAddr(inetAddr,23,&serverAddr); if(status) { printf("aToIPAddr failed\n"); - return(-1); + return(-1); } errno = 0; status = connect(fd,(struct sockaddr*)&serverAddr, sizeof(serverAddr)); @@ -58,7 +58,7 @@ int E5810Reboot(char * inetAddr,char *password) if(nbytes!=7) printf("nbytes %d expected 7\n",nbytes); epicsThreadSleep(1.0); nbytes = send(fd,password,(int)strlen(password),0); - if(nbytes!=strlen(password)) + if(nbytes!=strlen(password)) printf("nbytes %d expected %d\n",nbytes,(int)strlen(password)); epicsThreadSleep(1.0); nbytes = send(fd,"\ny\n",3,0); diff --git a/asyn/vxi11/TDS3000Reboot.c b/asyn/vxi11/TDS3000Reboot.c index fb24ed7..a133212 100644 --- a/asyn/vxi11/TDS3000Reboot.c +++ b/asyn/vxi11/TDS3000Reboot.c @@ -20,7 +20,7 @@ #include #include - + int TDS3000Reboot(char * inetAddr) { struct sockaddr_in serverAddr; @@ -44,7 +44,7 @@ int TDS3000Reboot(char * inetAddr) status = aToIPAddr(inetAddr,80,&serverAddr); if(status) { printf("aToIPAddr failed\n"); - return(-1); + return(-1); } errno = 0; status = connect(fd,(struct sockaddr*)&serverAddr, sizeof(serverAddr)); diff --git a/asyn/vxi11/drvVxi11.c b/asyn/vxi11/drvVxi11.c index 34f0d29..88a769f 100644 --- a/asyn/vxi11/drvVxi11.c +++ b/asyn/vxi11/drvVxi11.c @@ -58,7 +58,7 @@ #define FLAG_NO_SRQ 0x4 #define DEFAULT_RPC_TIMEOUT 4 - + typedef struct devLink { Device_Link lid; BOOL connected; @@ -108,14 +108,14 @@ typedef struct vxiPort { unsigned char lockDevices;/*lock devices when creating link*/ asynInterface option; epicsEventId srqThreadDone; - int srqBindSock; /*socket for bind*/ + SOCKET srqBindSock; /*socket for bind*/ osiSockAddr vxiServerAddr; /*addess of vxi11 server*/ char *srqThreadName; epicsInterruptibleSyscallContext *srqInterrupt; int srqEnabled; vxiConnectStatus previousConnectStatus; }vxiPort; - + /* Local routines */ static char *vxiError(Device_ErrorCode error); static unsigned long getIoTimeout(asynUser *pasynUser,vxiPort *ppvxiPort); @@ -141,7 +141,7 @@ static void vxiDestroyIrqChannel(vxiPort *pvxiPort); static void vxiSrqThread(void *pvxiPort); static asynStatus vxiConnectPort(vxiPort *pvxiPort,asynUser *pasynUser); static asynStatus vxiDisconnectPort(vxiPort *pvxiPort); - + /* asynGpibPort methods */ static void vxiReport(void *drvPvt,FILE *fd,int details); static asynStatus vxiConnect(void *drvPvt,asynUser *pasynUser); @@ -195,7 +195,7 @@ static const struct asynOption vxiOption = { vxiSetPortOption, vxiGetPortOption }; - + static char *vxiError(Device_ErrorCode error) { switch (error) { @@ -270,7 +270,7 @@ static void vxiDisconnectException(vxiPort *pvxiPort,int addr) status = pasynManager->connectDevice(pasynUser,pvxiPort->portName,-1); assert(status==asynSuccess); } - + static BOOL vxiCreateDeviceLink(vxiPort * pvxiPort, char *devName,Device_Link *pDevice_Link) { @@ -281,7 +281,7 @@ static BOOL vxiCreateDeviceLink(vxiPort * pvxiPort, asynUser *pasynUser = pvxiPort->pasynUser; crLinkP.clientId = (long) pvxiPort->rpcClient; - crLinkP.lockDevice = (pvxiPort->lockDevices != 0); + crLinkP.lockDevice = (pvxiPort->lockDevices != 0); crLinkP.lock_timeout = 0;/* if device is locked, forget it */ crLinkP.device = devName; /* initialize crLinkR */ @@ -307,7 +307,7 @@ static BOOL vxiCreateDeviceLink(vxiPort * pvxiPort, } else if(pvxiPort->maxRecvSize!=crLinkR.maxRecvSize) { asynPrint(pasynUser,ASYN_TRACE_ERROR, "%s vxiCreateDeviceLink maxRecvSize changed from %lu to %lu\n", - devName,pvxiPort->maxRecvSize,crLinkR.maxRecvSize); + devName,pvxiPort->maxRecvSize,(unsigned long)crLinkR.maxRecvSize); } if(pvxiPort->abortPort==0) { pvxiPort->abortPort = crLinkR.abortPort; @@ -340,7 +340,7 @@ static BOOL vxiCreateDevLink(vxiPort * pvxiPort,int addr,Device_Link *plid) } return vxiCreateDeviceLink(pvxiPort,devName,plid); } - + static devLink *vxiGetDevLink(vxiPort *pvxiPort, asynUser *pasynUser,int addr) { int primary,secondary; @@ -402,7 +402,7 @@ static BOOL vxiDestroyDevLink(vxiPort * pvxiPort, Device_Link devLink) xdr_free((const xdrproc_t) xdr_Device_Error, (char *) &devErr); return status; } - + /*write with ATN true */ static int vxiWriteAddressed(vxiPort *pvxiPort,asynUser *pasynUser, Device_Link lid, char *buffer, int length, double timeout) @@ -468,7 +468,7 @@ static int vxiWriteCmd(vxiPort * pvxiPort,asynUser *pasynUser, pdevLink->lid,buffer,length,pvxiPort->defTimeout); return status; } - + /****************************************************************************** * Check the bus status. Parameter can be a number from 1 to 8 to * indicate the information requested (see VXI_BSTAT_XXXX in vxi11.h) @@ -542,7 +542,7 @@ static asynStatus vxiBusStatus(vxiPort * pvxiPort, int request, *busStatus = status; return asynSuccess; } - + static enum clnt_stat clientCall(vxiPort * pvxiPort, u_long req,xdrproc_t proc1, caddr_t addr1,xdrproc_t proc2, caddr_t addr2) { @@ -588,7 +588,7 @@ static enum clnt_stat clientIoCall(vxiPort * pvxiPort,asynUser *pasynUser, } return stat; } - + /* In order to create_intr_chan the inet address and port for srqBindSock is required. @@ -609,7 +609,7 @@ static void vxiCreateIrqChannel(vxiPort *pvxiPort,asynUser *pasynUser) Device_Error devErr; Device_RemoteFunc devRemF; osiSockAddr tempAddr; - int tempSock; + SOCKET tempSock; osiSockAddr srqBindAddr; osiSocklen_t addrlen; @@ -659,7 +659,7 @@ static void vxiCreateIrqChannel(vxiPort *pvxiPort,asynUser *pasynUser) return; } pvxiPort->vxiServerAddr.ia.sin_addr.s_addr = tempAddr.ia.sin_addr.s_addr; - close(tempSock); + epicsSocketDestroy(tempSock); /* bind for receiving srq messages*/ pvxiPort->srqBindSock = epicsSocketCreate (PF_INET, SOCK_STREAM, 0); @@ -678,18 +678,18 @@ static void vxiCreateIrqChannel(vxiPort *pvxiPort,asynUser *pasynUser) asynPrint(pasynUser,ASYN_TRACE_ERROR, "%s vxiCreateIrqChannel bind failed %s\n", pvxiPort->portName,strerror (errno)); - close(pvxiPort->srqBindSock); + epicsSocketDestroy(pvxiPort->srqBindSock); return; } addrlen = sizeof tempAddr; - getsockname(pvxiPort->srqBindSock, &tempAddr.sa, &addrlen); + getsockname(pvxiPort->srqBindSock, &tempAddr.sa, &addrlen); /*Now we have srqBindAddr port*/ srqBindAddr.ia.sin_port = tempAddr.ia.sin_port; if (listen (pvxiPort->srqBindSock, 2) < 0) { asynPrint(pasynUser,ASYN_TRACE_ERROR, "%s vxiCreateIrqChannel listen failed %s\n", pvxiPort->srqThreadName,strerror (errno)); - close(pvxiPort->srqBindSock); + epicsSocketDestroy(pvxiPort->srqBindSock); return; } @@ -732,7 +732,7 @@ static void vxiCreateIrqChannel(vxiPort *pvxiPort,asynUser *pasynUser) asynPrint(pasynUser,ASYN_TRACE_ERROR, "%s Warning -- SRQ not operational.\n",pvxiPort->portName); } - + static void vxiDestroyIrqChannel(vxiPort *pvxiPort) { Device_Error devErr; @@ -788,13 +788,13 @@ static void vxiDestroyIrqChannel(vxiPort *pvxiPort) epicsEventDestroy(pvxiPort->srqThreadDone); pvxiPort->srqThreadDone = 0; } - + static void vxiSrqThread(void *arg) { vxiPort *pvxiPort = arg; asynUser *pasynUser = pvxiPort->pasynUser; epicsThreadId myTid; - int srqSock; + SOCKET srqSock; char buf[512]; int i; @@ -810,7 +810,7 @@ static void vxiSrqThread(void *arg) srqSock = epicsSocketAccept(pvxiPort->srqBindSock,&farAddr.sa,&addrlen); if(epicsInterruptibleSyscallWasInterrupted(pvxiPort->srqInterrupt)) { if(!epicsInterruptibleSyscallWasClosed(pvxiPort->srqInterrupt)) - close(pvxiPort->srqBindSock); + epicsSocketDestroy(pvxiPort->srqBindSock); asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s vxiSrqThread terminating\n", pvxiPort->portName); taskwdRemove(myTid); @@ -823,9 +823,9 @@ static void vxiSrqThread(void *arg) asynPrint(pasynUser,ASYN_TRACE_ERROR, "%s vxiSrqThread accept but not from vxiServer\n", pvxiPort->portName); - close(srqSock); + epicsSocketDestroy(srqSock); } - close(pvxiPort->srqBindSock); + epicsSocketDestroy(pvxiPort->srqBindSock); if(srqSock < 0) { asynPrint(pasynUser,ASYN_TRACE_ERROR,"%s can't accept connection: %s\n", pvxiPort->srqThreadName,strerror(errno)); @@ -837,7 +837,7 @@ static void vxiSrqThread(void *arg) for(;;) { if(epicsInterruptibleSyscallWasInterrupted(pvxiPort->srqInterrupt)) break; - i = read(srqSock, buf, sizeof buf); + i = recv(srqSock, buf, sizeof buf, 0); if(epicsInterruptibleSyscallWasInterrupted(pvxiPort->srqInterrupt)) break; if(i < 0) { @@ -855,13 +855,13 @@ static void vxiSrqThread(void *arg) pasynGpib->srqHappened(pvxiPort->asynGpibPvt); } if(!epicsInterruptibleSyscallWasClosed(pvxiPort->srqInterrupt)) - close(srqSock); + epicsSocketDestroy(srqSock); asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s vxiSrqThread terminating\n",pvxiPort->srqThreadName); taskwdRemove(myTid); epicsEventSignal(pvxiPort->srqThreadDone); } - + static void reportConnectStatus(vxiPort *pvxiPort, vxiConnectStatus status, const char* fmt, ...) { va_list args; @@ -882,17 +882,20 @@ static asynStatus vxiConnectPort(vxiPort *pvxiPort,asynUser *pasynUser) asynStatus status; struct sockaddr_in vxiServer; - /* Previously this pasynUser was created and connected to the port in vxi11Configure + /* Previously this pasynUser was created and connected to the port in vxi11Configure * after calling pasynGpib->registerPort - * But in asyn R4-12 and later a call to pasynCommon->connect (which calls this function) + * But in asyn R4-12 and later a call to pasynCommon->connect (which calls this function) * can happen almost immediately when pasynGpib->registerPort is called, so we move the code here. */ if (!pvxiPort->pasynUser) { pvxiPort->pasynUser = pasynManager->createAsynUser(0,0); pvxiPort->pasynUser->timeout = pvxiPort->defTimeout; status = pasynManager->connectDevice( pvxiPort->pasynUser, pvxiPort->portName,-1); - reportConnectStatus(pvxiPort, vxiConnectDevice, - "vxiConnectPort: connectDevice failed %s\n", pvxiPort->pasynUser->errorMessage); + if (status != asynSuccess) { + reportConnectStatus(pvxiPort, vxiConnectDevice, + "vxiConnectPort: connectDevice failed %s\n", pvxiPort->pasynUser->errorMessage); + return status; + } } if(pvxiPort->server.connected) { reportConnectStatus(pvxiPort, vxiConnectAlreadyConnected, @@ -924,7 +927,7 @@ static asynStatus vxiConnectPort(vxiPort *pvxiPort,asynUser *pasynUser) pvxiPort->portName, pvxiPort->hostName); return asynError; } - pvxiPort->rpcClient = clnttcp_create(&vxiServer, + pvxiPort->rpcClient = clnttcp_create(&vxiServer, DEVICE_CORE, DEVICE_CORE_VERSION, &sock, 0, 0); if(!pvxiPort->rpcClient) { reportConnectStatus(pvxiPort, vxiConnectClientCreate, @@ -934,7 +937,11 @@ static asynStatus vxiConnectPort(vxiPort *pvxiPort,asynUser *pasynUser) } /* now establish a link to the gateway (for docmds etc.) */ pvxiPort->abortPort = 0; - if(!vxiCreateDeviceLink(pvxiPort,pvxiPort->vxiName,&link)) return asynError; + if(!vxiCreateDeviceLink(pvxiPort,pvxiPort->vxiName,&link)) { + clnt_destroy(pvxiPort->rpcClient); + pvxiPort->rpcClient = NULL; + return asynError; + } pvxiPort->server.lid = link; pvxiPort->server.connected = TRUE; pvxiPort->ctrlAddr = -1; @@ -992,7 +999,7 @@ static asynStatus vxiConnectPort(vxiPort *pvxiPort,asynUser *pasynUser) "%s is now connected\n", pvxiPort->portName); return asynSuccess; } - + static asynStatus vxiDisconnectPort(vxiPort *pvxiPort) { int addr,secondary; @@ -1036,7 +1043,7 @@ static asynStatus vxiDisconnectPort(vxiPort *pvxiPort) pasynManager->exceptionDisconnect(pvxiPort->pasynUser); return asynSuccess; } - + static void vxiReport(void *drvPvt,FILE *fd,int details) { vxiPort *pvxiPort = (vxiPort *)drvPvt; @@ -1094,7 +1101,7 @@ static asynStatus vxiConnect(void *drvPvt,asynUser *pasynUser) pasynManager->exceptionConnect(pasynUser); return asynSuccess; } - + static asynStatus vxiDisconnect(void *drvPvt,asynUser *pasynUser) { vxiPort *pvxiPort = (vxiPort *)drvPvt; @@ -1125,7 +1132,7 @@ static asynStatus vxiDisconnect(void *drvPvt,asynUser *pasynUser) pasynManager->exceptionDisconnect(pasynUser); return status; } - + static asynStatus vxiRead(void *drvPvt,asynUser *pasynUser, char *data,int maxchars,int *nbytesTransfered,int *eomReason) { @@ -1187,7 +1194,7 @@ static asynStatus vxiRead(void *drvPvt,asynUser *pasynUser, "%s read request failed",pvxiPort->portName); status = (devReadR.error==VXI_IOTIMEOUT) ? asynTimeout : asynError; break; - } + } thisRead = devReadR.data.data_len; if(thisRead>0) { asynPrintIO(pasynUser,ASYN_TRACEIO_DRIVER, @@ -1209,7 +1216,7 @@ static asynStatus vxiRead(void *drvPvt,asynUser *pasynUser, *nbytesTransfered = nRead; return status; } - + static asynStatus vxiWrite(void *drvPvt,asynUser *pasynUser, const char *data,int numchars,int *nbytesTransfered) { @@ -1265,7 +1272,7 @@ static asynStatus vxiWrite(void *drvPvt,asynUser *pasynUser, status = asynError; break; } else if(devWriteR.error != VXI_OK) { - if(devWriteR.error == VXI_IOTIMEOUT && pvxiPort->recoverWithIFC) + if(devWriteR.error == VXI_IOTIMEOUT && pvxiPort->recoverWithIFC) vxiIfc(drvPvt, pasynUser); epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s write request failed",pvxiPort->portName); @@ -1285,7 +1292,7 @@ static asynStatus vxiWrite(void *drvPvt,asynUser *pasynUser, *nbytesTransfered = nWrite; return status; } - + static asynStatus vxiFlush(void *drvPvt,asynUser *pasynUser) { /* Nothing to do */ @@ -1349,7 +1356,7 @@ static asynStatus vxiGetEos(void *drvPvt,asynUser *pasynUser, "%s vxiGetEos %d\n",pvxiPort->portName, *eoslen); return asynSuccess; } - + static asynStatus vxiAddressedCmd(void *drvPvt,asynUser *pasynUser, const char *data, int length) { @@ -1415,7 +1422,7 @@ static asynStatus vxiUniversalCmd(void *drvPvt, asynUser *pasynUser, int cmd) } return status; } - + static asynStatus vxiIfc(void *drvPvt, asynUser *pasynUser) { vxiPort *pvxiPort = (vxiPort *)drvPvt; @@ -1461,7 +1468,7 @@ static asynStatus vxiIfc(void *drvPvt, asynUser *pasynUser) xdr_free((const xdrproc_t) xdr_Device_DocmdResp, (char *) &devDocmdR); return status; } - + static asynStatus vxiRen(void *drvPvt,asynUser *pasynUser, int onOff) { vxiPort *pvxiPort = (vxiPort *)drvPvt; @@ -1503,14 +1510,14 @@ static asynStatus vxiRen(void *drvPvt,asynUser *pasynUser, int onOff) pvxiPort->portName,clnt_sperror(pvxiPort->rpcClient,"")); status = asynError; } else if(devDocmdR.error != VXI_OK) { - asynPrint(pasynUser,ASYN_TRACE_ERROR,"%s vxiRen %s\n", + asynPrint(pasynUser,ASYN_TRACE_ERROR,"%s vxiRen %s\n", pvxiPort->portName, vxiError(devDocmdR.error)); status = (devDocmdR.error==VXI_IOTIMEOUT) ? asynTimeout : asynError; } xdr_free((const xdrproc_t) xdr_Device_DocmdResp, (char *) &devDocmdR); return status; } - + static asynStatus vxiSrqStatus(void *drvPvt,int *srqStatus) { vxiPort *pvxiPort = (vxiPort *)drvPvt; @@ -1535,7 +1542,7 @@ static asynStatus vxiSrqEnable(void *drvPvt, int onOff) enum clnt_stat clntStat; Device_EnableSrqParms devEnSrqP; Device_Error devErr; - char handle[16]; + char handle[17]; /* 16 for 64bit pointer value in hex + 1 for NULL terminator */ if(!pdevLink) return asynError; if(!vxiIsPortConnected(pvxiPort,0)) return asynError; @@ -1581,7 +1588,7 @@ static asynStatus vxiSrqEnable(void *drvPvt, int onOff) xdr_free((const xdrproc_t) xdr_Device_Error, (char *) &devErr); return status; } - + static asynStatus vxiSerialPollBegin(void *drvPvt) { return asynSuccess; @@ -1611,7 +1618,7 @@ static asynStatus vxiSerialPoll(void *drvPvt, int addr, return asynError; } pdevLink->lid = lid; - pdevLink->connected = TRUE; + pdevLink->connected = TRUE; } devGenP.lid = pdevLink->lid; devGenP.flags = 0; /* no timeout on a locked gateway */ @@ -1690,7 +1697,7 @@ static asynStatus vxiGetPortOption(void *drvPvt, epicsSnprintf(val,valSize,"%f",timeout); return asynSuccess; } - + int vxi11Configure(char *dn, char *hostName, int flags, char *defTimeoutString, char *vxiName, @@ -1736,7 +1743,7 @@ int vxi11Configure(char *dn, char *hostName, int flags, } pvxiPort->vxiName = epicsStrDup(vxiName); if (defTimeoutString) defTimeout = epicsStrtod(defTimeoutString, NULL); - pvxiPort->defTimeout = (defTimeout>.0001) ? + pvxiPort->defTimeout = (defTimeout>.0001) ? defTimeout : (double)DEFAULT_RPC_TIMEOUT ; if(flags & FLAG_RECOVER_WITH_IFC) pvxiPort->recoverWithIFC = TRUE; if(flags & FLAG_LOCK_DEVICES) pvxiPort->lockDevices = TRUE; @@ -1764,7 +1771,7 @@ int vxi11Configure(char *dn, char *hostName, int flags, pvxiPort->pasynUser->timeout = pvxiPort->defTimeout; status = pasynManager->connectDevice( pvxiPort->pasynUser,pvxiPort->portName,-1); - if (status!=asynSuccess) + if (status!=asynSuccess) printf("vxiConnectPort: connectDevice failed %s\n",pvxiPort->pasynUser->errorMessage); } pvxiPort->option.interfaceType = asynOptionType; @@ -1774,7 +1781,7 @@ int vxi11Configure(char *dn, char *hostName, int flags, if(status!=asynSuccess) printf("Can't register option.\n"); return 0; } - + /* * IOC shell command registration */ diff --git a/asyn/vxi11/osiRpc.h b/asyn/vxi11/osiRpc.h index dbf3d61..9da2c3f 100644 --- a/asyn/vxi11/osiRpc.h +++ b/asyn/vxi11/osiRpc.h @@ -46,4 +46,8 @@ #define rpcTaskInit() 0 #endif +#ifdef freebsd +#define rpcTaskInit() 0 +#endif + #endif /* _osiRpcH_ */ diff --git a/asyn/vxi11/rpc/vxi11core.h b/asyn/vxi11/rpc/vxi11core.h index d36d19a..8554f03 100644 --- a/asyn/vxi11/rpc/vxi11core.h +++ b/asyn/vxi11/rpc/vxi11core.h @@ -17,8 +17,8 @@ extern "C" { typedef long Device_Link; enum Device_AddrFamily { - DEVICE_TCP = 0, - DEVICE_UDP = 1, + DEVICE_TCP = 0, + DEVICE_UDP = 1, }; typedef enum Device_AddrFamily Device_AddrFamily; @@ -27,125 +27,125 @@ typedef long Device_Flags; typedef long Device_ErrorCode; struct Device_Error { - Device_ErrorCode error; + Device_ErrorCode error; }; typedef struct Device_Error Device_Error; struct Create_LinkParms { - long clientId; - bool_t lockDevice; - u_long lock_timeout; - char *device; + long clientId; + bool_t lockDevice; + u_long lock_timeout; + char *device; }; typedef struct Create_LinkParms Create_LinkParms; struct Create_LinkResp { - Device_ErrorCode error; - Device_Link lid; - u_short abortPort; - u_long maxRecvSize; + Device_ErrorCode error; + Device_Link lid; + u_short abortPort; + u_long maxRecvSize; }; typedef struct Create_LinkResp Create_LinkResp; struct Device_WriteParms { - Device_Link lid; - u_long io_timeout; - u_long lock_timeout; - Device_Flags flags; - struct { - u_int data_len; - char *data_val; - } data; + Device_Link lid; + u_long io_timeout; + u_long lock_timeout; + Device_Flags flags; + struct { + u_int data_len; + char *data_val; + } data; }; typedef struct Device_WriteParms Device_WriteParms; struct Device_WriteResp { - Device_ErrorCode error; - u_long size; + Device_ErrorCode error; + u_long size; }; typedef struct Device_WriteResp Device_WriteResp; struct Device_ReadParms { - Device_Link lid; - u_long requestSize; - u_long io_timeout; - u_long lock_timeout; - Device_Flags flags; - char termChar; + Device_Link lid; + u_long requestSize; + u_long io_timeout; + u_long lock_timeout; + Device_Flags flags; + char termChar; }; typedef struct Device_ReadParms Device_ReadParms; struct Device_ReadResp { - Device_ErrorCode error; - long reason; - struct { - u_int data_len; - char *data_val; - } data; + Device_ErrorCode error; + long reason; + struct { + u_int data_len; + char *data_val; + } data; }; typedef struct Device_ReadResp Device_ReadResp; struct Device_ReadStbResp { - Device_ErrorCode error; - u_char stb; + Device_ErrorCode error; + u_char stb; }; typedef struct Device_ReadStbResp Device_ReadStbResp; struct Device_GenericParms { - Device_Link lid; - Device_Flags flags; - u_long lock_timeout; - u_long io_timeout; + Device_Link lid; + Device_Flags flags; + u_long lock_timeout; + u_long io_timeout; }; typedef struct Device_GenericParms Device_GenericParms; struct Device_RemoteFunc { - u_long hostAddr; - u_long hostPort; - u_long progNum; - u_long progVers; - Device_AddrFamily progFamily; + u_long hostAddr; + u_long hostPort; + u_long progNum; + u_long progVers; + Device_AddrFamily progFamily; }; typedef struct Device_RemoteFunc Device_RemoteFunc; struct Device_EnableSrqParms { - Device_Link lid; - bool_t enable; - struct { - u_int handle_len; - char *handle_val; - } handle; + Device_Link lid; + bool_t enable; + struct { + u_int handle_len; + char *handle_val; + } handle; }; typedef struct Device_EnableSrqParms Device_EnableSrqParms; struct Device_LockParms { - Device_Link lid; - Device_Flags flags; - u_long lock_timeout; + Device_Link lid; + Device_Flags flags; + u_long lock_timeout; }; typedef struct Device_LockParms Device_LockParms; struct Device_DocmdParms { - Device_Link lid; - Device_Flags flags; - u_long io_timeout; - u_long lock_timeout; - long cmd; - bool_t network_order; - long datasize; - struct { - u_int data_in_len; - char *data_in_val; - } data_in; + Device_Link lid; + Device_Flags flags; + u_long io_timeout; + u_long lock_timeout; + long cmd; + bool_t network_order; + long datasize; + struct { + u_int data_in_len; + char *data_in_val; + } data_in; }; typedef struct Device_DocmdParms Device_DocmdParms; struct Device_DocmdResp { - Device_ErrorCode error; - struct { - u_int data_out_len; - char *data_out_val; - } data_out; + Device_ErrorCode error; + struct { + u_int data_out_len; + char *data_out_val; + } data_out; }; typedef struct Device_DocmdResp Device_DocmdResp; diff --git a/asyn/vxi11/rpc/vxi11core_xdr.c b/asyn/vxi11/rpc/vxi11core_xdr.c index 6474129..06f97e8 100644 --- a/asyn/vxi11/rpc/vxi11core_xdr.c +++ b/asyn/vxi11/rpc/vxi11core_xdr.c @@ -9,430 +9,430 @@ bool_t xdr_Device_Link (XDR *xdrs, Device_Link *objp) { - if (!xdr_long (xdrs, objp)) - return FALSE; - return TRUE; + if (!xdr_long (xdrs, objp)) + return FALSE; + return TRUE; } bool_t xdr_Device_AddrFamily (XDR *xdrs, Device_AddrFamily *objp) { - if (!xdr_enum (xdrs, (enum_t *) objp)) - return FALSE; - return TRUE; + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; } bool_t xdr_Device_Flags (XDR *xdrs, Device_Flags *objp) { - if (!xdr_long (xdrs, objp)) - return FALSE; - return TRUE; + if (!xdr_long (xdrs, objp)) + return FALSE; + return TRUE; } bool_t xdr_Device_ErrorCode (XDR *xdrs, Device_ErrorCode *objp) { - if (!xdr_long (xdrs, objp)) - return FALSE; - return TRUE; + if (!xdr_long (xdrs, objp)) + return FALSE; + return TRUE; } bool_t xdr_Device_Error (XDR *xdrs, Device_Error *objp) { - if (!xdr_Device_ErrorCode (xdrs, &objp->error)) - return FALSE; - return TRUE; + if (!xdr_Device_ErrorCode (xdrs, &objp->error)) + return FALSE; + return TRUE; } bool_t xdr_Create_LinkParms (XDR *xdrs, Create_LinkParms *objp) { - int32_t *buf; - - - if (xdrs->x_op == XDR_ENCODE) { - buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); - if (buf == NULL) { - if (!xdr_long (xdrs, &objp->clientId)) - return FALSE; - if (!xdr_bool (xdrs, &objp->lockDevice)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->lock_timeout)) - return FALSE; - - } else { - IXDR_PUT_LONG(buf, objp->clientId); - IXDR_PUT_BOOL(buf, objp->lockDevice); - IXDR_PUT_U_LONG(buf, objp->lock_timeout); - } - if (!xdr_string (xdrs, &objp->device, ~0)) - return FALSE; - return TRUE; - } else if (xdrs->x_op == XDR_DECODE) { - buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); - if (buf == NULL) { - if (!xdr_long (xdrs, &objp->clientId)) - return FALSE; - if (!xdr_bool (xdrs, &objp->lockDevice)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->lock_timeout)) - return FALSE; - - } else { - objp->clientId = IXDR_GET_LONG(buf); - objp->lockDevice = IXDR_GET_BOOL(buf); - objp->lock_timeout = IXDR_GET_U_LONG(buf); - } - if (!xdr_string (xdrs, &objp->device, ~0)) - return FALSE; - return TRUE; - } - - if (!xdr_long (xdrs, &objp->clientId)) - return FALSE; - if (!xdr_bool (xdrs, &objp->lockDevice)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->lock_timeout)) - return FALSE; - if (!xdr_string (xdrs, &objp->device, ~0)) - return FALSE; - return TRUE; + int32_t *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_long (xdrs, &objp->clientId)) + return FALSE; + if (!xdr_bool (xdrs, &objp->lockDevice)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->lock_timeout)) + return FALSE; + + } else { + IXDR_PUT_LONG(buf, objp->clientId); + IXDR_PUT_BOOL(buf, objp->lockDevice); + IXDR_PUT_U_LONG(buf, objp->lock_timeout); + } + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_long (xdrs, &objp->clientId)) + return FALSE; + if (!xdr_bool (xdrs, &objp->lockDevice)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->lock_timeout)) + return FALSE; + + } else { + objp->clientId = IXDR_GET_LONG(buf); + objp->lockDevice = IXDR_GET_BOOL(buf); + objp->lock_timeout = IXDR_GET_U_LONG(buf); + } + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + return TRUE; + } + + if (!xdr_long (xdrs, &objp->clientId)) + return FALSE; + if (!xdr_bool (xdrs, &objp->lockDevice)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->lock_timeout)) + return FALSE; + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + return TRUE; } bool_t xdr_Create_LinkResp (XDR *xdrs, Create_LinkResp *objp) { - if (!xdr_Device_ErrorCode (xdrs, &objp->error)) - return FALSE; - if (!xdr_Device_Link (xdrs, &objp->lid)) - return FALSE; - if (!xdr_u_short (xdrs, &objp->abortPort)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->maxRecvSize)) - return FALSE; - return TRUE; + if (!xdr_Device_ErrorCode (xdrs, &objp->error)) + return FALSE; + if (!xdr_Device_Link (xdrs, &objp->lid)) + return FALSE; + if (!xdr_u_short (xdrs, &objp->abortPort)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->maxRecvSize)) + return FALSE; + return TRUE; } bool_t xdr_Device_WriteParms (XDR *xdrs, Device_WriteParms *objp) { - if (!xdr_Device_Link (xdrs, &objp->lid)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->io_timeout)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->lock_timeout)) - return FALSE; - if (!xdr_Device_Flags (xdrs, &objp->flags)) - return FALSE; - if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0)) - return FALSE; - return TRUE; + if (!xdr_Device_Link (xdrs, &objp->lid)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->io_timeout)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->lock_timeout)) + return FALSE; + if (!xdr_Device_Flags (xdrs, &objp->flags)) + return FALSE; + if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0)) + return FALSE; + return TRUE; } bool_t xdr_Device_WriteResp (XDR *xdrs, Device_WriteResp *objp) { - if (!xdr_Device_ErrorCode (xdrs, &objp->error)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->size)) - return FALSE; - return TRUE; + if (!xdr_Device_ErrorCode (xdrs, &objp->error)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->size)) + return FALSE; + return TRUE; } bool_t xdr_Device_ReadParms (XDR *xdrs, Device_ReadParms *objp) { - int32_t *buf; - - - if (xdrs->x_op == XDR_ENCODE) { - if (!xdr_Device_Link (xdrs, &objp->lid)) - return FALSE; - buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); - if (buf == NULL) { - if (!xdr_u_long (xdrs, &objp->requestSize)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->io_timeout)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->lock_timeout)) - return FALSE; - - } else { - IXDR_PUT_U_LONG(buf, objp->requestSize); - IXDR_PUT_U_LONG(buf, objp->io_timeout); - IXDR_PUT_U_LONG(buf, objp->lock_timeout); - } - if (!xdr_Device_Flags (xdrs, &objp->flags)) - return FALSE; - if (!xdr_char (xdrs, &objp->termChar)) - return FALSE; - return TRUE; - } else if (xdrs->x_op == XDR_DECODE) { - if (!xdr_Device_Link (xdrs, &objp->lid)) - return FALSE; - buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); - if (buf == NULL) { - if (!xdr_u_long (xdrs, &objp->requestSize)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->io_timeout)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->lock_timeout)) - return FALSE; - - } else { - objp->requestSize = IXDR_GET_U_LONG(buf); - objp->io_timeout = IXDR_GET_U_LONG(buf); - objp->lock_timeout = IXDR_GET_U_LONG(buf); - } - if (!xdr_Device_Flags (xdrs, &objp->flags)) - return FALSE; - if (!xdr_char (xdrs, &objp->termChar)) - return FALSE; - return TRUE; - } - - if (!xdr_Device_Link (xdrs, &objp->lid)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->requestSize)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->io_timeout)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->lock_timeout)) - return FALSE; - if (!xdr_Device_Flags (xdrs, &objp->flags)) - return FALSE; - if (!xdr_char (xdrs, &objp->termChar)) - return FALSE; - return TRUE; + int32_t *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + if (!xdr_Device_Link (xdrs, &objp->lid)) + return FALSE; + buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_long (xdrs, &objp->requestSize)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->io_timeout)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->lock_timeout)) + return FALSE; + + } else { + IXDR_PUT_U_LONG(buf, objp->requestSize); + IXDR_PUT_U_LONG(buf, objp->io_timeout); + IXDR_PUT_U_LONG(buf, objp->lock_timeout); + } + if (!xdr_Device_Flags (xdrs, &objp->flags)) + return FALSE; + if (!xdr_char (xdrs, &objp->termChar)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (!xdr_Device_Link (xdrs, &objp->lid)) + return FALSE; + buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_long (xdrs, &objp->requestSize)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->io_timeout)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->lock_timeout)) + return FALSE; + + } else { + objp->requestSize = IXDR_GET_U_LONG(buf); + objp->io_timeout = IXDR_GET_U_LONG(buf); + objp->lock_timeout = IXDR_GET_U_LONG(buf); + } + if (!xdr_Device_Flags (xdrs, &objp->flags)) + return FALSE; + if (!xdr_char (xdrs, &objp->termChar)) + return FALSE; + return TRUE; + } + + if (!xdr_Device_Link (xdrs, &objp->lid)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->requestSize)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->io_timeout)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->lock_timeout)) + return FALSE; + if (!xdr_Device_Flags (xdrs, &objp->flags)) + return FALSE; + if (!xdr_char (xdrs, &objp->termChar)) + return FALSE; + return TRUE; } bool_t xdr_Device_ReadResp (XDR *xdrs, Device_ReadResp *objp) { - if (!xdr_Device_ErrorCode (xdrs, &objp->error)) - return FALSE; - if (!xdr_long (xdrs, &objp->reason)) - return FALSE; - if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0)) - return FALSE; - return TRUE; + if (!xdr_Device_ErrorCode (xdrs, &objp->error)) + return FALSE; + if (!xdr_long (xdrs, &objp->reason)) + return FALSE; + if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0)) + return FALSE; + return TRUE; } bool_t xdr_Device_ReadStbResp (XDR *xdrs, Device_ReadStbResp *objp) { - if (!xdr_Device_ErrorCode (xdrs, &objp->error)) - return FALSE; - if (!xdr_u_char (xdrs, &objp->stb)) - return FALSE; - return TRUE; + if (!xdr_Device_ErrorCode (xdrs, &objp->error)) + return FALSE; + if (!xdr_u_char (xdrs, &objp->stb)) + return FALSE; + return TRUE; } bool_t xdr_Device_GenericParms (XDR *xdrs, Device_GenericParms *objp) { - if (!xdr_Device_Link (xdrs, &objp->lid)) - return FALSE; - if (!xdr_Device_Flags (xdrs, &objp->flags)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->lock_timeout)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->io_timeout)) - return FALSE; - return TRUE; + if (!xdr_Device_Link (xdrs, &objp->lid)) + return FALSE; + if (!xdr_Device_Flags (xdrs, &objp->flags)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->lock_timeout)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->io_timeout)) + return FALSE; + return TRUE; } bool_t xdr_Device_RemoteFunc (XDR *xdrs, Device_RemoteFunc *objp) { - int32_t *buf; - - - if (xdrs->x_op == XDR_ENCODE) { - buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT); - if (buf == NULL) { - if (!xdr_u_long (xdrs, &objp->hostAddr)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->hostPort)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->progNum)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->progVers)) - return FALSE; - - } else { - IXDR_PUT_U_LONG(buf, objp->hostAddr); - IXDR_PUT_U_LONG(buf, objp->hostPort); - IXDR_PUT_U_LONG(buf, objp->progNum); - IXDR_PUT_U_LONG(buf, objp->progVers); - } - if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily)) - return FALSE; - return TRUE; - } else if (xdrs->x_op == XDR_DECODE) { - buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT); - if (buf == NULL) { - if (!xdr_u_long (xdrs, &objp->hostAddr)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->hostPort)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->progNum)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->progVers)) - return FALSE; - - } else { - objp->hostAddr = IXDR_GET_U_LONG(buf); - objp->hostPort = IXDR_GET_U_LONG(buf); - objp->progNum = IXDR_GET_U_LONG(buf); - objp->progVers = IXDR_GET_U_LONG(buf); - } - if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily)) - return FALSE; - return TRUE; - } - - if (!xdr_u_long (xdrs, &objp->hostAddr)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->hostPort)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->progNum)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->progVers)) - return FALSE; - if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily)) - return FALSE; - return TRUE; + int32_t *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_long (xdrs, &objp->hostAddr)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->hostPort)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->progNum)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->progVers)) + return FALSE; + + } else { + IXDR_PUT_U_LONG(buf, objp->hostAddr); + IXDR_PUT_U_LONG(buf, objp->hostPort); + IXDR_PUT_U_LONG(buf, objp->progNum); + IXDR_PUT_U_LONG(buf, objp->progVers); + } + if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_long (xdrs, &objp->hostAddr)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->hostPort)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->progNum)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->progVers)) + return FALSE; + + } else { + objp->hostAddr = IXDR_GET_U_LONG(buf); + objp->hostPort = IXDR_GET_U_LONG(buf); + objp->progNum = IXDR_GET_U_LONG(buf); + objp->progVers = IXDR_GET_U_LONG(buf); + } + if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily)) + return FALSE; + return TRUE; + } + + if (!xdr_u_long (xdrs, &objp->hostAddr)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->hostPort)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->progNum)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->progVers)) + return FALSE; + if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily)) + return FALSE; + return TRUE; } bool_t xdr_Device_EnableSrqParms (XDR *xdrs, Device_EnableSrqParms *objp) { - if (!xdr_Device_Link (xdrs, &objp->lid)) - return FALSE; - if (!xdr_bool (xdrs, &objp->enable)) - return FALSE; - if (!xdr_bytes (xdrs, (char **)&objp->handle.handle_val, (u_int *) &objp->handle.handle_len, 40)) - return FALSE; - return TRUE; + if (!xdr_Device_Link (xdrs, &objp->lid)) + return FALSE; + if (!xdr_bool (xdrs, &objp->enable)) + return FALSE; + if (!xdr_bytes (xdrs, (char **)&objp->handle.handle_val, (u_int *) &objp->handle.handle_len, 40)) + return FALSE; + return TRUE; } bool_t xdr_Device_LockParms (XDR *xdrs, Device_LockParms *objp) { - if (!xdr_Device_Link (xdrs, &objp->lid)) - return FALSE; - if (!xdr_Device_Flags (xdrs, &objp->flags)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->lock_timeout)) - return FALSE; - return TRUE; + if (!xdr_Device_Link (xdrs, &objp->lid)) + return FALSE; + if (!xdr_Device_Flags (xdrs, &objp->flags)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->lock_timeout)) + return FALSE; + return TRUE; } bool_t xdr_Device_DocmdParms (XDR *xdrs, Device_DocmdParms *objp) { - int32_t *buf; - - - if (xdrs->x_op == XDR_ENCODE) { - if (!xdr_Device_Link (xdrs, &objp->lid)) - return FALSE; - if (!xdr_Device_Flags (xdrs, &objp->flags)) - return FALSE; - buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT); - if (buf == NULL) { - if (!xdr_u_long (xdrs, &objp->io_timeout)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->lock_timeout)) - return FALSE; - if (!xdr_long (xdrs, &objp->cmd)) - return FALSE; - if (!xdr_bool (xdrs, &objp->network_order)) - return FALSE; - if (!xdr_long (xdrs, &objp->datasize)) - return FALSE; - - } else { - IXDR_PUT_U_LONG(buf, objp->io_timeout); - IXDR_PUT_U_LONG(buf, objp->lock_timeout); - IXDR_PUT_LONG(buf, objp->cmd); - IXDR_PUT_BOOL(buf, objp->network_order); - IXDR_PUT_LONG(buf, objp->datasize); - } - if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0)) - return FALSE; - return TRUE; - } else if (xdrs->x_op == XDR_DECODE) { - if (!xdr_Device_Link (xdrs, &objp->lid)) - return FALSE; - if (!xdr_Device_Flags (xdrs, &objp->flags)) - return FALSE; - buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT); - if (buf == NULL) { - if (!xdr_u_long (xdrs, &objp->io_timeout)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->lock_timeout)) - return FALSE; - if (!xdr_long (xdrs, &objp->cmd)) - return FALSE; - if (!xdr_bool (xdrs, &objp->network_order)) - return FALSE; - if (!xdr_long (xdrs, &objp->datasize)) - return FALSE; - - } else { - objp->io_timeout = IXDR_GET_U_LONG(buf); - objp->lock_timeout = IXDR_GET_U_LONG(buf); - objp->cmd = IXDR_GET_LONG(buf); - objp->network_order = IXDR_GET_BOOL(buf); - objp->datasize = IXDR_GET_LONG(buf); - } - if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0)) - return FALSE; - return TRUE; - } - - if (!xdr_Device_Link (xdrs, &objp->lid)) - return FALSE; - if (!xdr_Device_Flags (xdrs, &objp->flags)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->io_timeout)) - return FALSE; - if (!xdr_u_long (xdrs, &objp->lock_timeout)) - return FALSE; - if (!xdr_long (xdrs, &objp->cmd)) - return FALSE; - if (!xdr_bool (xdrs, &objp->network_order)) - return FALSE; - if (!xdr_long (xdrs, &objp->datasize)) - return FALSE; - if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0)) - return FALSE; - return TRUE; + int32_t *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + if (!xdr_Device_Link (xdrs, &objp->lid)) + return FALSE; + if (!xdr_Device_Flags (xdrs, &objp->flags)) + return FALSE; + buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_long (xdrs, &objp->io_timeout)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->lock_timeout)) + return FALSE; + if (!xdr_long (xdrs, &objp->cmd)) + return FALSE; + if (!xdr_bool (xdrs, &objp->network_order)) + return FALSE; + if (!xdr_long (xdrs, &objp->datasize)) + return FALSE; + + } else { + IXDR_PUT_U_LONG(buf, objp->io_timeout); + IXDR_PUT_U_LONG(buf, objp->lock_timeout); + IXDR_PUT_LONG(buf, objp->cmd); + IXDR_PUT_BOOL(buf, objp->network_order); + IXDR_PUT_LONG(buf, objp->datasize); + } + if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (!xdr_Device_Link (xdrs, &objp->lid)) + return FALSE; + if (!xdr_Device_Flags (xdrs, &objp->flags)) + return FALSE; + buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_long (xdrs, &objp->io_timeout)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->lock_timeout)) + return FALSE; + if (!xdr_long (xdrs, &objp->cmd)) + return FALSE; + if (!xdr_bool (xdrs, &objp->network_order)) + return FALSE; + if (!xdr_long (xdrs, &objp->datasize)) + return FALSE; + + } else { + objp->io_timeout = IXDR_GET_U_LONG(buf); + objp->lock_timeout = IXDR_GET_U_LONG(buf); + objp->cmd = IXDR_GET_LONG(buf); + objp->network_order = IXDR_GET_BOOL(buf); + objp->datasize = IXDR_GET_LONG(buf); + } + if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0)) + return FALSE; + return TRUE; + } + + if (!xdr_Device_Link (xdrs, &objp->lid)) + return FALSE; + if (!xdr_Device_Flags (xdrs, &objp->flags)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->io_timeout)) + return FALSE; + if (!xdr_u_long (xdrs, &objp->lock_timeout)) + return FALSE; + if (!xdr_long (xdrs, &objp->cmd)) + return FALSE; + if (!xdr_bool (xdrs, &objp->network_order)) + return FALSE; + if (!xdr_long (xdrs, &objp->datasize)) + return FALSE; + if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0)) + return FALSE; + return TRUE; } bool_t xdr_Device_DocmdResp (XDR *xdrs, Device_DocmdResp *objp) { - if (!xdr_Device_ErrorCode (xdrs, &objp->error)) - return FALSE; - if (!xdr_bytes (xdrs, (char **)&objp->data_out.data_out_val, (u_int *) &objp->data_out.data_out_len, ~0)) - return FALSE; - return TRUE; + if (!xdr_Device_ErrorCode (xdrs, &objp->error)) + return FALSE; + if (!xdr_bytes (xdrs, (char **)&objp->data_out.data_out_val, (u_int *) &objp->data_out.data_out_len, ~0)) + return FALSE; + return TRUE; } diff --git a/asyn/vxi11/rpc/vxi11intr.h b/asyn/vxi11/rpc/vxi11intr.h index a1ee1e1..582c1ed 100644 --- a/asyn/vxi11/rpc/vxi11intr.h +++ b/asyn/vxi11/rpc/vxi11intr.h @@ -15,10 +15,10 @@ extern "C" { struct Device_SrqParms { - struct { - u_int handle_len; - char *handle_val; - } handle; + struct { + u_int handle_len; + char *handle_val; + } handle; }; typedef struct Device_SrqParms Device_SrqParms; diff --git a/asyn/vxi11/rpc/vxi11intr_xdr.c b/asyn/vxi11/rpc/vxi11intr_xdr.c index f27ba57..1230527 100644 --- a/asyn/vxi11/rpc/vxi11intr_xdr.c +++ b/asyn/vxi11/rpc/vxi11intr_xdr.c @@ -8,9 +8,9 @@ bool_t xdr_Device_SrqParms (XDR *xdrs, Device_SrqParms *objp) { - register int32_t *buf; + register int32_t *buf; - if (!xdr_bytes (xdrs, (char **)&objp->handle.handle_val, (u_int *) &objp->handle.handle_len, ~0)) - return FALSE; - return TRUE; + if (!xdr_bytes (xdrs, (char **)&objp->handle.handle_val, (u_int *) &objp->handle.handle_len, ~0)) + return FALSE; + return TRUE; } diff --git a/asyn/vxi11/vxi11.h b/asyn/vxi11/vxi11.h index 595009f..06075c0 100644 --- a/asyn/vxi11/vxi11.h +++ b/asyn/vxi11/vxi11.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * $RCSfile: vxi11.h,v $ + * $RCSfile: vxi11.h,v $ * ******************************************************************************/ /*********************************************************************** @@ -23,7 +23,7 @@ */ #ifndef VXI11_H #define VXI11_H - + /* VXI-11 error codes */ #define VXI_OK 0 /* no error */ #define VXI_SYNERR 1 /* syntax error */ diff --git a/configure/CONFIG_SITE b/configure/CONFIG_SITE index ffa637e..538cd55 100644 --- a/configure/CONFIG_SITE +++ b/configure/CONFIG_SITE @@ -45,6 +45,12 @@ LINUX_GPIB=NO # DRV_USBTMC=YES #endif +# If you have libusb-1.0 and libftdi, and want FTDI support, set DRV_FTDI=YES +DRV_FTDI=NO + +# If your system has libftdi1, set the following to YES. If it has libftdi, set it to NO +DRV_FTDI_USE_LIBFTDI1=NO + # If you want to build asyn so the only dependency on EPICS base is libCom then set the following flag #EPICS_LIBCOM_ONLY=YES @@ -54,3 +60,9 @@ LINUX_GPIB=NO -include $(SUPPORT)/configure/CONFIG_SITE +# These allow developers to override the CONFIG_SITE variable +# settings without having to modify the configure/CONFIG_SITE +# file itself. +-include $(TOP)/../CONFIG_SITE.local +-include $(TOP)/configure/CONFIG_SITE.local + diff --git a/configure/CONFIG_SITE.Common.linux-x86_64 b/configure/CONFIG_SITE.Common.linux-x86_64 new file mode 100644 index 0000000..e24205e --- /dev/null +++ b/configure/CONFIG_SITE.Common.linux-x86_64 @@ -0,0 +1,5 @@ +# If you have libusb-1.0 and libftdi, and want FTDI support, set DRV_FTDI=YES +#DRV_FTDI=YES + +# If your system has libftdi1, set the following to YES. If it has libftdi, set it to NO +#DRV_FTDI_USE_LIBFTDI1=YES diff --git a/configure/CONFIG_SITE.Common.linux-x86_64-centos8 b/configure/CONFIG_SITE.Common.linux-x86_64-centos8 new file mode 100644 index 0000000..28e1e78 --- /dev/null +++ b/configure/CONFIG_SITE.Common.linux-x86_64-centos8 @@ -0,0 +1,2 @@ +TIRPC=YES + diff --git a/configure/RELEASE b/configure/RELEASE index 66cf16d..ff75dcd 100644 --- a/configure/RELEASE +++ b/configure/RELEASE @@ -1,15 +1,37 @@ -#RELEASE Location of external products +# RELEASE Location of external products -SUPPORT=/corvette/home/epics/devel --include $(TOP)/../configure/SUPPORT.$(EPICS_HOST_ARCH) +# Define the following Required or Optional +# either in this file, or in a RELEASE.local -# IPAC is only necessary if support for Greensprings IP488 is required -# IPAC release V2-7 or later is required. -IPAC=$(SUPPORT)/ipac-2-15 +#SUPPORT=/corvette/home/epics/devel +# Optional +# IPAC is only necessary if support for Greensprings IP488 is required +# IPAC release V2-7 or later is required. +# It can be obtained here: https://github.com/epics-modules/ipac +#IPAC=$(SUPPORT)/ipac-2-16 + +# Optional # SEQ is required for testIPServer -SNCSEQ=$(SUPPORT)/seq-2-2-5 +# It can be obtained here: https://www-csr.bessy.de/control/SoftDist/sequencer/Manual.html +#SNCSEQ=$(SUPPORT)/seq-2-2-5 + +# Optional +# For sCalcout support in asynOctet - applications include asynCalc.dbd +# It can be obtained here: https://github.com/epics-modules/calc +#CALC=$(SUPPORT)/calc-3-7-4 + +# Optional +# If CALC was built with SSCAN support then SSCAN must be defined for testEpicsApp +# It can be obtained here: https://github.com/epics-modules/sscan +#SSCAN=$(SUPPORT)/sscan-2-11-5 + +# Required +# EPICS_BASE 3.14.6 or later is required +# It can be obtained here: https://github.com/epics-base/epics-base +#EPICS_BASE=/corvette/usr/local/epics-devel/base-7.0.7 + +-include $(TOP)/../RELEASE.local +-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local +-include $(TOP)/configure/RELEASE.local -# EPICS_BASE 3.14.6 or later is required -EPICS_BASE=/corvette/usr/local/epics-devel/base-7.0.3 --include $(TOP)/../configure/EPICS_BASE.$(EPICS_HOST_ARCH) diff --git a/debian/changelog b/debian/changelog index f8e00b0..24db031 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,40 @@ +asyn (4.44.2-1+nmu1) unstable; urgency=medium + + * New upstream version 4.44.2 + + -- Conor Farah Tue, 14 May 2024 12:56:05 -0400 + +asyn (4.43-1) unstable; urgency=medium + + [ Evan Daykin ] + * New upstream version 4.43 + * tweak patch 0001 to apply to R4-43 + * update maintainer to daykin for this release + + [ Priller, John ] + * add linitian overrides + * rebased for uc5 + + -- epics Thu, 04 May 2023 07:33:47 -0400 + +asyn (4.38-1) unstable; urgency=medium + + [ Priller, John ] + * add linitian overrides + * New upstream version 4.38 + * rebased for v4.38 + * updated control version for v4.38 + + -- epics Fri, 13 Aug 2021 13:29:42 -0400 + +asyn (4.37-1) unstable; urgency=medium + + * New upstream version 4.37 + * Rebase patch queue1 + * Bump up version in package names + + -- Martin Konrad Tue, 19 Nov 2019 09:53:56 -0500 + asyn (4.36-1) unstable; urgency=medium * New upstream version 4.36 diff --git a/debian/control b/debian/control index fc73e22..90870f6 100644 --- a/debian/control +++ b/debian/control @@ -1,7 +1,7 @@ Source: asyn Section: libdevel Priority: optional -Maintainer: Martin Konrad +Maintainer: Evan Daykin Build-Depends: debhelper (>= 10), dpkg-dev (>= 1.17.14), epics-debhelper (>= 8.12~), epics-dev (>= 3.14.12), rtems-epics-mvme2100 , @@ -17,7 +17,7 @@ Vcs-Browser: https://github.com/epicsdeb/asyn Package: epics-asyn-dev Architecture: any -Depends: libasyn4.36 (= ${binary:Version}), +Depends: libasyn4.44.2 (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends}, ${epics:Depends}, Conflicts: epics-synapps, epics-synapps-dev, @@ -30,7 +30,7 @@ Description: Facility for interfacing to low level communication drivers . This package contains headers and libraries needed at build time. -Package: libasyn4.36 +Package: libasyn4.44.2 Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, Description: Facility for interfacing to low level communication drivers diff --git a/debian/epics-asyn-dev.lintian-overrides b/debian/epics-asyn-dev.lintian-overrides new file mode 100644 index 0000000..91d51d6 --- /dev/null +++ b/debian/epics-asyn-dev.lintian-overrides @@ -0,0 +1,2 @@ +# -debug targets not stripped +epics-asyn-dev: unstripped-binary-or-object diff --git a/debian/patches/0001-configure-RELEASE.patch b/debian/patches/0001-configure-RELEASE.patch deleted file mode 100644 index f337483..0000000 --- a/debian/patches/0001-configure-RELEASE.patch +++ /dev/null @@ -1,32 +0,0 @@ -From: Michael Davidsaver -Date: Wed, 9 Mar 2016 15:49:09 -0500 -Subject: configure/RELEASE - ---- - configure/RELEASE | 10 ++++------ - 1 file changed, 4 insertions(+), 6 deletions(-) - -diff --git a/configure/RELEASE b/configure/RELEASE -index 66cf16d..c8858f8 100644 ---- a/configure/RELEASE -+++ b/configure/RELEASE -@@ -1,15 +1,13 @@ - #RELEASE Location of external products - --SUPPORT=/corvette/home/epics/devel ---include $(TOP)/../configure/SUPPORT.$(EPICS_HOST_ARCH) -+SUPPORT=$(EPICS_BASE) - - # IPAC is only necessary if support for Greensprings IP488 is required - # IPAC release V2-7 or later is required. --IPAC=$(SUPPORT)/ipac-2-15 -+#IPAC=$(EPICS_BASE) - - # SEQ is required for testIPServer --SNCSEQ=$(SUPPORT)/seq-2-2-5 -+#SNCSEQ=$(EPICS_BASE) - - # EPICS_BASE 3.14.6 or later is required --EPICS_BASE=/corvette/usr/local/epics-devel/base-7.0.3 ---include $(TOP)/../configure/EPICS_BASE.$(EPICS_HOST_ARCH) -+EPICS_BASE=/usr/lib/epics diff --git a/debian/patches/0001-rebase-fix-configure-RELEASE.patch b/debian/patches/0001-rebase-fix-configure-RELEASE.patch new file mode 100644 index 0000000..f422908 --- /dev/null +++ b/debian/patches/0001-rebase-fix-configure-RELEASE.patch @@ -0,0 +1,42 @@ +From: "Priller, John" +Date: Fri, 13 Aug 2021 13:29:41 -0400 +Subject: rebase fix configure/RELEASE + +--- + configure/RELEASE | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +Index: asyn/configure/RELEASE +=================================================================== +--- asyn.orig/configure/RELEASE ++++ asyn/configure/RELEASE +@@ -3,7 +3,7 @@ + # Define the following Required or Optional + # either in this file, or in a RELEASE.local + +-#SUPPORT=/corvette/home/epics/devel ++SUPPORT=$(EPICS_BASE) + + # Optional + # IPAC is only necessary if support for Greensprings IP488 is required +@@ -19,17 +19,17 @@ + # Optional + # For sCalcout support in asynOctet - applications include asynCalc.dbd + # It can be obtained here: https://github.com/epics-modules/calc +-#CALC=$(SUPPORT)/calc-3-7-4 ++#CALC=$(SUPPORT) + + # Optional + # If CALC was built with SSCAN support then SSCAN must be defined for testEpicsApp + # It can be obtained here: https://github.com/epics-modules/sscan +-#SSCAN=$(SUPPORT)/sscan-2-11-5 ++SSCAN=$(SUPPORT) + + # Required + # EPICS_BASE 3.14.6 or later is required + # It can be obtained here: https://github.com/epics-base/epics-base +-#EPICS_BASE=/corvette/usr/local/epics-devel/base-7.0.7 ++EPICS_BASE=/usr/lib/epics + + -include $(TOP)/../RELEASE.local + -include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local diff --git a/debian/patches/0002-prevent-generated-docs-from-being-cleaned.patch b/debian/patches/0002-prevent-generated-docs-from-being-cleaned.patch index d1c3a48..33b7e27 100644 --- a/debian/patches/0002-prevent-generated-docs-from-being-cleaned.patch +++ b/debian/patches/0002-prevent-generated-docs-from-being-cleaned.patch @@ -7,10 +7,10 @@ Subject: prevent generated docs from being cleaned 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile -index 1ee8bf4..f2bbc8c 100644 +index 4b19f20..69507c6 100644 --- a/Makefile +++ b/Makefile -@@ -61,3 +61,5 @@ DIRS += testAsynPortClientApp +@@ -66,3 +66,5 @@ DIRS += testAsynPortClientApp testAsynPortClientApp_DEPEND_DIRS = asyn include $(TOP)/configure/RULES_TOP diff --git a/debian/patches/0003-Don-t-build-test.patch b/debian/patches/0003-Don-t-build-test.patch index 749bae9..47c4095 100644 --- a/debian/patches/0003-Don-t-build-test.patch +++ b/debian/patches/0003-Don-t-build-test.patch @@ -10,10 +10,10 @@ to build. 1 file changed, 48 deletions(-) diff --git a/Makefile b/Makefile -index f2bbc8c..f2dff97 100644 +index 69507c6..81cdeaf 100644 --- a/Makefile +++ b/Makefile -@@ -9,57 +9,9 @@ asyn_DEPEND_DIRS = configure +@@ -10,61 +10,13 @@ asyn_DEPEND_DIRS = configure DIRS += asyn/asynPortDriver/unittest asyn/asynPortDriver/unittest_DEPEND_DIRS = asyn @@ -63,6 +63,10 @@ index f2bbc8c..f2dff97 100644 - 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/debian/patches/0004-Enable-support-for-USB-test-and-measurement-TMC-devi.patch b/debian/patches/0004-Enable-support-for-USB-test-and-measurement-TMC-devi.patch index c8cd659..6e5ecee 100644 --- a/debian/patches/0004-Enable-support-for-USB-test-and-measurement-TMC-devi.patch +++ b/debian/patches/0004-Enable-support-for-USB-test-and-measurement-TMC-devi.patch @@ -7,7 +7,7 @@ Subject: Enable support for USB test and measurement (TMC) devices 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure/CONFIG_SITE b/configure/CONFIG_SITE -index ffa637e..ae52344 100644 +index 538cd55..217f9a3 100644 --- a/configure/CONFIG_SITE +++ b/configure/CONFIG_SITE @@ -37,7 +37,7 @@ CHECK_RELEASE = YES diff --git a/debian/patches/0005-need-TIRPC-defined-to-find-rpc.h.patch b/debian/patches/0005-need-TIRPC-defined-to-find-rpc.h.patch new file mode 100644 index 0000000..0e787d0 --- /dev/null +++ b/debian/patches/0005-need-TIRPC-defined-to-find-rpc.h.patch @@ -0,0 +1,21 @@ +From: "Priller, John" +Date: Thu, 4 May 2023 07:33:46 -0400 +Subject: need TIRPC defined to find rpc.h + +--- + configure/CONFIG_SITE | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure/CONFIG_SITE b/configure/CONFIG_SITE +index 217f9a3..b8c975f 100644 +--- a/configure/CONFIG_SITE ++++ b/configure/CONFIG_SITE +@@ -56,7 +56,7 @@ DRV_FTDI_USE_LIBFTDI1=NO + + # Some linux systems moved RPC related symbols to libtirpc + # To enable linking against this library, uncomment the following line +-# TIRPC=YES ++TIRPC=YES + + -include $(SUPPORT)/configure/CONFIG_SITE + diff --git a/debian/patches/series b/debian/patches/series index 7b923d6..69c1813 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,4 +1,5 @@ -0001-configure-RELEASE.patch +0001-rebase-fix-configure-RELEASE.patch 0002-prevent-generated-docs-from-being-cleaned.patch 0003-Don-t-build-test.patch 0004-Enable-support-for-USB-test-and-measurement-TMC-devi.patch +0005-need-TIRPC-defined-to-find-rpc.h.patch diff --git a/debian/source/include-binaries b/debian/source/include-binaries new file mode 100644 index 0000000..86ceba7 --- /dev/null +++ b/debian/source/include-binaries @@ -0,0 +1,23 @@ +docs/source/AsynFlow.jpg +docs/source/AsynOctetIDN.png +docs/source/AsynOctetWindow.png +docs/source/AsynRecordWindow.png +docs/source/AsynSynFlow.jpg +docs/source/AsynTimeStampSupport.doc +docs/source/HowToDoSerial.rst +docs/source/asynGPIBSetup.png +docs/source/asynIPPortSetup.png +docs/source/asynOctet.png +docs/source/asynPortClient.rst +docs/source/asynRecord.png +docs/source/asynRegister.png +docs/source/asynSerialPortSetup.png +docs/source/asynTest.png +docs/source/asynTestArrayRingBuffer.png +docs/source/asynTimeSeries.png +docs/source/asynTimeStampSupport.rst +docs/source/testAsynPortDriver.png +docs/source/testDigital.png +docs/source/testErrors.png +docs/source/testInt32.png +docs/source/testOctet.png \ No newline at end of file diff --git a/debian/source/lintian-overrides b/debian/source/lintian-overrides index fd904b3..3529e7e 100644 --- a/debian/source/lintian-overrides +++ b/debian/source/lintian-overrides @@ -1,3 +1,6 @@ +asyn: unstripped-binary-or-object usr/lib/epics/lib/linux-x86_64-debug/* +asyn source: source-is-missing documentation/asynDoxygenHTML/menu.js * +asyn source: source-is-missing html/asynDoxygenHTML/menu.js * asyn source: invalid-restriction-formula-in-build-profiles-field rtems-asyn-mvme2100 asyn source: invalid-restriction-formula-in-build-profiles-field rtems-asyn-mvme3100 asyn source: invalid-restriction-formula-in-build-profiles-field rtems-asyn-mvme5500 diff --git a/documentation/Doxyfile b/docs/Doxyfile similarity index 99% rename from documentation/Doxyfile rename to docs/Doxyfile index 03c516c..79dd797 100644 --- a/documentation/Doxyfile +++ b/docs/Doxyfile @@ -1,4 +1,5 @@ # Doxyfile 1.8.15 +# Doxyfile 1.8.15 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -38,7 +39,7 @@ PROJECT_NAME = asyn # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4-36 +PROJECT_NUMBER = 4-44-2 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -1130,7 +1131,7 @@ GENERATE_HTML = YES # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_OUTPUT = asynDoxygenHTML +HTML_OUTPUT = _build/html/doxygenHTML # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..14d3c76 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,22 @@ +SPHINX_MULTIBUILD=sphinx-multibuild + +DOCS_PATHS += -i . + +BUILD = _build +SOURCE = source +DOCS = _docs +#OPTS = -v -v -v +OPTS = + +doxygen: sphinx + doxygen + +all: sphinx doxygen + +sphinx: + $(SPHINX_MULTIBUILD) -i $(SOURCE) -s $(DOCS) -o $(BUILD)/html $(OPTS) -b html + +.PHONY: clean +clean: + rm -rf _docs + rm -rf _build diff --git a/documentation/ReleaseChecklist.txt b/docs/ReleaseChecklist.txt similarity index 69% rename from documentation/ReleaseChecklist.txt rename to docs/ReleaseChecklist.txt index f246765..b06fc5b 100755 --- a/documentation/ReleaseChecklist.txt +++ b/docs/ReleaseChecklist.txt @@ -3,8 +3,8 @@ Release checklist for asyn - Check for Issues and Pull Requests on Github. - Do "git pull" to make sure everything is up to date and checked in - Do "git diff --name-status RX-Y" against the previous release (RX-Y) to make sure everything is in the release notes -- Make sure to add the date and release number to asynDriver.html, RELEASE_NOTES.html and Doxyfile +- Make sure to add the date and release number to asynDriver.rst, RELEASE.md and Doxyfile - Update the asyn version number in asynDriver.h - Make the git repository tag with "git tag RX-Y" - Push the repository and tags to github with "git push" and "git push --tags" -- Make a tar file to send to Andrew with "make_asyn_tar_file RX-Y" from the devel directory + diff --git a/documentation/KnownProblems.html b/docs/obsolete/KnownProblems.html similarity index 100% rename from documentation/KnownProblems.html rename to docs/obsolete/KnownProblems.html diff --git a/documentation/gpibCoreConversion/conversionNotes.html b/docs/obsolete/conversionNotes.html similarity index 100% rename from documentation/gpibCoreConversion/conversionNotes.html rename to docs/obsolete/conversionNotes.html diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..7a1d887 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,7 @@ +sphinx +sphinx-rtd-theme>=1.2.0 +m2r2 +sphinx-multibuild +breathe +Jinja2<3.1 +mistune<0.8.5 diff --git a/documentation/AsynFlow.graffle b/docs/source/AsynFlow.graffle similarity index 100% rename from documentation/AsynFlow.graffle rename to docs/source/AsynFlow.graffle diff --git a/documentation/AsynFlow.jpg b/docs/source/AsynFlow.jpg similarity index 100% rename from documentation/AsynFlow.jpg rename to docs/source/AsynFlow.jpg diff --git a/docs/source/AsynOctetIDN.png b/docs/source/AsynOctetIDN.png new file mode 100755 index 0000000..42b4604 Binary files /dev/null and b/docs/source/AsynOctetIDN.png differ diff --git a/docs/source/AsynOctetWindow.png b/docs/source/AsynOctetWindow.png new file mode 100755 index 0000000..b2d1dd9 Binary files /dev/null and b/docs/source/AsynOctetWindow.png differ diff --git a/docs/source/AsynRecordWindow.png b/docs/source/AsynRecordWindow.png new file mode 100755 index 0000000..7d06009 Binary files /dev/null and b/docs/source/AsynRecordWindow.png differ diff --git a/documentation/AsynSynFlow.graffle b/docs/source/AsynSynFlow.graffle similarity index 100% rename from documentation/AsynSynFlow.graffle rename to docs/source/AsynSynFlow.graffle diff --git a/documentation/AsynSynFlow.jpg b/docs/source/AsynSynFlow.jpg similarity index 100% rename from documentation/AsynSynFlow.jpg rename to docs/source/AsynSynFlow.jpg diff --git a/documentation/AsynTimeStampSupport.doc b/docs/source/AsynTimeStampSupport.doc similarity index 100% rename from documentation/AsynTimeStampSupport.doc rename to docs/source/AsynTimeStampSupport.doc diff --git a/docs/source/HowToDoSerial.rst b/docs/source/HowToDoSerial.rst new file mode 100755 index 0000000..5b4bf41 --- /dev/null +++ b/docs/source/HowToDoSerial.rst @@ -0,0 +1,640 @@ +HowToDoSerial (StreamDevice) +============================ + +:author: W. Eric Norum + +This document describes how to use StreamDevice and ASYN to create EPICS device support for a simple serial, +GPIB, or network attached device + +1. Introduction +--------------- + +This tutorial provides step-by-step instructions on how to create EPICS support +for a simple serial, GPIB (IEEE-488) or network attached device. The steps are presented +in a way that should make it possible to apply them in cookbook fashion to create +support for other devices. For comprehensive description of all the details of the +I/O system used here, refer to the +`asynDriver `__ +and +`StreamDevice `__ +documentation. + +This document isn't for the absolute newcomer though. You must have EPICS installed +on a system somewhere and know how to build and run the example application. In +particular you must have the following installed: + +- EPICS R3.14.11 or higher. +- EPICS ASYN support module version 4.14 or higher. +- EPICS StreamDevice support module version 2.4.1 or higher. + +Serial, GPIB and network attached devices can now be treated in much the same way. +The EPICS StreamDevice and ASYN support modules can use drivers which communicate +with serial devices connected to ports on the IOC or to Ethernet/Serial converters +or with GPIB devices connected to local I/O cards or to Ethernet/GPIB converters +or to network attached devices using VXI-11 or plain TCP ('telnet') communication +protocols. + +I based this tutorial on the device support I wrote for a Hewlett Packard E3631A +power supply. I chose the E3610A as the basis for this tutorial partly because it +was what I found lying around but mostly because it uses SCPI-compliant commands +which are common to a wide range of devices. Sections 1 through 4 of this tutorial +apply to all SCPI (IEEE-488.2) devices. + +2. Create a new device support module +------------------------------------- +The easiest way to do this is with the makeSupport.pl script supplied with the EPICS +ASYN package. + +Here are the commands I ran. To make the command examples a little shorter I used +shell variables to hold the paths to my installation of EPICS base and the ASYN +support module. You can do this with values appropriate for your site or just type +the full path names to the commands. +:: + + EPICS_BASE=/usr/local/epics/R3.14.11/base + ASYN=/usr/local/epics/R3.14.11/modules/soft/synApps_5_5/support/asyn-4-14 + +You will have to change these to the values appropriate for your EPICS installation +or simply type the appropriate full paths to invoke the scripts. You must also have +the EPICS_HOST_ARCH environment variable set to match the machine on which you are +building. + +To create a new StreamDevice support module: +:: + + norume> mkdir HPE3631A + norume> cd HPE3631A + norume> $ASYN/bin/$EPICS_HOST_ARCH/makeSupport.pl -t streamSCPI HPE3631A + +2.1 Make changes to some files in configure/ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Edit the configure/RELEASE file which makeSupport.pl created and confirm that the +entries describing the paths to your EPICS base and ASYN support are correct. For +example these might be: +:: + + ASYN = /usr/local/epics/R3.14.11/modules/soft/synApps_5_5/support/asyn-4-14 + EPICS_BASE = /usr/local/epics/R3.14.11/base + +You'll also have to add a line describing the path to your StreamDevice support. +For example: +:: + + STREAM = /usr/local/epics/R3.14.11/modules/soft/synApps_5_5/support/stream-2-4-1 + +Edit the configure/CONFIG_SITE file which makeSupport.pl created and specify the +IOC architectures on which the application is to run. I wanted the application to +run as a soft IOC, so I uncommented the CROSS_COMPILER_TARGET_ARCHS definition and +set the definition to be empty: +:: + + CROSS_COMPILER_TARGET_ARCHS = + +You may have to fix an error in the HPE3631ASup/devHPE3631A.db file produced by +the makeSupport.pl command. Verify that the IDNwf record description looks like: +:: + + record(waveform, "$(P)$(R)IDNwf") + { + field(DESC, "SCPI identification string") + field(DTYP, "stream") + field(INP, "@devHPE3631A.proto getIDN(199) $(PORT) $(A)") + field(PINI, "YES") + field(FTVL, "CHAR") + field(NELM, "200") + } + +Some versions of the template have FTYP rather than FTVL for the waveform data type +field. + +I install the StreamDevice protocol file into the support module db/ directory. +This seems like a reasonable place to put this file since it's tied closely to its +associated database file. To have the protocol file installed into the db/ directory +edit HPE3631ASup/Makefile and add the line +:: + + DB_INSTALLS += $(TOP)/HPE3631ASup/devHPE3631A.proto + +to the list of DB_INSTALLS. + +3. Create a test application (optional) +--------------------------------------- +Now that a device support module has been produced it is a good idea to create a +new EPICS application to confirm that the device support is operating correctly. +The easiest way to do this is with the makeBaseApp.pl script supplied with EPICS. +The files in the configure/ directory produced in the previous step do not provide +all the information needed to build an application but will not be overwritten by +the makeBaseApp.pl script. The easiest solution to this problem is to simply remove +the configure/ directory and all its contents and then to make the changes to configure/RELEASE +and configure/CONFIG_SITE at mentioned above. + +Here are the commands I ran. +:: + + norume> rm -rf configure + norume> $EPICS_BASE/bin/$EPICS_HOST_ARCH/makeBaseApp.pl -t ioc HPE3631Atest + norume> $EPICS_BASE/bin/$EPICS_HOST_ARCH/makeBaseApp.pl -t ioc -i HPE3631Atest + + The following target architectures are available in base: + darwin-x86 + RTEMS-mvme2100 + RTEMS-mvme3100 + RTEMS-uC5282 + What architecture do you want to use? darwin-x86 + The following applications are available: + HPE3631Atest + What application should the IOC(s) boot? + The default uses the IOC's name, even if not listed above. + Application name? + norume> + + +I then added the ASYN and STREAM values to configure/RELEASE and made the change +to the CROSS_COMPILER_TARGET_ARCHS line in configure/CONFIG_SITE. + +You must add the StreamDevice and ASYN support modules to the test application. +Edit HPE3631AtestApp/src/Makefile and add the lines: +:: + + HPE3631Atest_DBD += stream.dbd + HPE3631Atest_DBD += asyn.dbd + HPE3631Atest_DBD += drvAsynSerialPort.dbd + and + HPE3631Atest_LIBS += stream asyn + +To install the support module files and build the test application simply run make: +:: + + norume> make + . + . + . + norume> + +The IOC startup script produced by the makeBaseApp.pl script must be modified before +the test application can be run. Change directories to iocBoot/iocHPE3631Atest and +edit the st.cmd file. Here's the file that I use: +:: + + 1 #!../../bin/darwin-x86/HPE3631Atest + 2 + 3 ############################################################################### + 4 # Set up environment + 5 < envPaths + 6 epicsEnvSet "STREAM_PROTOCOL_PATH" "$(TOP)/db" + 7 + + 8 ############################################################################### + 9 # Allow PV name prefixes and serial port name to be set from the environment + 10 epicsEnvSet "P" "$(P=hpE3631A)" + 11 epicsEnvSet "R" "$(R=Test)" + 12 epicsEnvSet "TTY" "$(TTY=/dev/tty.PL2303-000013FA)" + 13 + + 14 ############################################################################### + 15 ## Register all support components + 16 cd "${TOP}" + 17 dbLoadDatabase "dbd/HPE3631Atest.dbd" + 18 HPE3631Atest_registerRecordDeviceDriver pdbbase + 19 + + 20 ############################################################################### + 21 # Set up ASYN ports + 22 # drvAsynSerialPortConfigure port ipInfo priority noAutoconnect noProcessEos + 23 drvAsynSerialPortConfigure("L0","$(TTY)",0,0,0) + 24 asynSetOption("L0", -1, "baud", "9600") + 25 asynSetOption("L0", -1, "bits", "8") + 26 asynSetOption("L0", -1, "parity", "none") + 27 asynSetOption("L0", -1, "stop", "2") + 28 asynSetOption("L0", -1, "clocal", "Y") + 29 asynSetOption("L0", -1, "crtscts", "Y") + 30 asynOctetSetInputEos("L0", -1, "\n") + 31 asynOctetSetOutputEos("L0", -1, "\n") + 32 asynSetTraceIOMask("L0",-1,0x2) + 33 asynSetTraceMask("L0",-1,0x9) + 34 + + 35 ############################################################################### + 36 ## Load record instances + 37 dbLoadRecords("db/devHPE3631A.db","P=$(P),R=$(R),PORT=L0,A=0") + 38 + + 39 ############################################################################### + 40 ## Start EPICS + 41 cd "${TOP}/iocBoot/${IOC}" + 42 iocInit + +Lines that you'll likely have to modify are: + +.. list-table:: + :widths: 10 90 + + * - 10,11 + - The prefix applied to all PV names. + * - 12 + - The name of your serial line (for network attached devices or LAN/Serial adapters + this will be something like 192.168.0.23:4001). + * - 23 + - The command would be drvAsynIPPortConfigure for LAN/Serial adapters or network attached + devices. See the asynDriver documentation for information on connecting to GPIB + devices. + * - 24-29 + - The serial line settings for your device (for network attached devices or LAN/Serial + adapters or GPIB devices these lines can be removed or commented out). + * - 30,31 + - GPIB devices may not need line terminators since they can use the EOI line to mark + the end of messages. + * - 33 + - This trace mask value prints a message showing the characters sent to and received + from the device. This can produce a lot of messages on the IOC console. To display + error messages only set the trace mask to 1 rather than 9. + +So, if you have a LAN/Serial adapter or network attached device which uses a raw +TCP ('telnet' style) connection you would replace lines 23 through 29 with a single +line like: +:: + + drvAsynIPPortConfigure("L0","192.168.0.23:4001",0,0,0) + +You would also change the application Makefile to specify drvAsynIPPort.dbd rather +than drvAsynSerialPort.dbd. + +If you have a VXI-11 LAN/GPIB adapter or network attached device you would replace +lines 23 through 31 with a single line like: +:: + + vxi11Configure("L0","192.168.0.24",0,0.0,"gpib0",0,0) + +You would also change the application Makefile to specify drfvVxi11.dbd rather than +drvAsynSerialPort.dbd. + +3.1 Run the test application +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The application can be started by running the startup script if you make the script +executable: +:: + + norume> cd iocBoot/iocHPE3631Atest + norume> chmod +x st.cmd + +Then the application can be run by: +:: + + norume> ./st.cmd + #!../../bin/darwin-x86/HPE3631Atest + ############################################################################### + # Set up environment + < envPaths + epicsEnvSet("ARCH","darwin-x86") + epicsEnvSet("IOC","iocHPE3631Atest") + epicsEnvSet("TOP","/Users/wenorum/tmp/t/HPE3631A") + epicsEnvSet("ASYN","/usr/local/epics/R3.14.11/modules/soft/synApps_5_5/support/asyn-4-14") + epicsEnvSet("STREAM","/usr/local/epics/R3.14.11/modules/soft/synApps_5_5/support/stream-2-4-1") + epicsEnvSet("EPICS_BASE","/usr/local/epics/R3.14.11/base") + epicsEnvSet "STREAM_PROTOCOL_PATH" "/Users/wenorum/tmp/t/HPE3631A/db" + ############################################################################### + # Allow PV name prefixes and serial port name to be set from the environment + epicsEnvSet "P" "hpE3631A" + epicsEnvSet "R" "Test" + epicsEnvSet "TTY" "/dev/tty.PL2303-000013FA" + ############################################################################### + ## Register all support components + cd "/Users/wenorum/tmp/t/HPE3631A" + dbLoadDatabase "dbd/HPE3631Atest.dbd" + HPE3631Atest_registerRecordDeviceDriver pdbbase + ############################################################################### + # Set up ASYN ports + # drvAsynSerialPortConfigure port ipInfo priority noAutoconnect noProcessEos + drvAsynSerialPortConfigure("L0","/dev/tty.PL2303-000013FA",0,0,0) + asynSetOption("L0", -1, "baud", "9600") + asynSetOption("L0", -1, "bits", "8") + asynSetOption("L0", -1, "parity", "none") + asynSetOption("L0", -1, "stop", "2") + asynSetOption("L0", -1, "clocal", "Y") + asynSetOption("L0", -1, "crtscts", "Y") + asynOctetSetInputEos("L0", -1, "\n") + asynOctetSetOutputEos("L0", -1, "\n") + asynSetTraceIOMask("L0",-1,0x2) + asynSetTraceMask("L0",-1,0x9) + ############################################################################### + ## Load record instances + dbLoadRecords("db/devHPE3631A.db","P=hpE3631A,R=Test,PORT=L0,A=0") + ############################################################################### + ## Start EPICS + cd "/Users/wenorum/tmp/t/HPE3631A/iocBoot/iocHPE3631Atest" + iocInit + Starting iocInit + ############################################################################ + ## EPICS R3.14.11 $R3-14-11$ $2009/08/28 18:47:36$ + ## EPICS Base built Aug 24 2010 + ############################################################################ + 2010/08/31 13:10:32.986 /dev/tty.PL2303-000013FA write 6 + *IDN?\n + iocRun: All initialization complete + 2010/08/31 13:10:33.116 /dev/tty.PL2303-000013FA read 1 + H + 2010/08/31 13:10:33.135 /dev/tty.PL2303-000013FA read 1 + E + 2010/08/31 13:10:33.153 /dev/tty.PL2303-000013FA read 1 + W + 2010/08/31 13:10:33.171 /dev/tty.PL2303-000013FA read 1 + L + 2010/08/31 13:10:33.189 /dev/tty.PL2303-000013FA read 1 + E + 2010/08/31 13:10:33.208 /dev/tty.PL2303-000013FA read 1 + T + 2010/08/31 13:10:33.226 /dev/tty.PL2303-000013FA read 1 + T + . + . + . + epics>dbpr hpE3631ATestIDN + ASG: + DESC: SCPI identification string + DISA: 0 + DISP: 0 + DISV: 1 + NAME: hpE3631ATestIDN + SEVR: NO_ALARM STAT: NO_ALARM + SVAL: + TPRO: 0 + VAL: HEWLETT-PACKARD,E3631A,0,2.1-5.0-1.0 + + epics> + +The SCPI IDN*? commands are run as part of iocInit since their records have PINI=YES. +If the stringin record has truncated the identification string you should be able +to see the full string as a waveform record. In another window run: +:: + + norume> caget -S hpE3631ATestIDNwf + hpE3631ATestIDNwf HEWLETT-PACKARD,E3631A,0,2.1-5.0-1.0 + norume> + +4. asynRecord support +--------------------- +The asynRecord provides a convenient mechanism for controlling the diagnostic messages +produced by asyn drivers. You can also use the MEDM asynOctet screen to manually +send commands to and view responses from a device. This can be very handy when trying +to figure out just how a new device actually works. + +To use an asynRecord in your application: + +Add the line: +:: + + DB_INSTALLS += $(ASYN)/db/asynRecord.db + +to the application Makefile. + +Create the diagnostic record in the IOC by adding a line like: +:: + + dbLoadRecords("db/asynRecord.db","P=$(P)$(R),R=asyn,PORT=L0,ADDR=-1,OMAX=0,IMAX=0") + +to the application startup script. The PORT value must match the the value in the +corresponding drvAsynIPPortConfigure or drvAsynSerialPortConfigure command. The +ADDR value should be that of the instrument whose I/O you wish to monitor. + +To run the asynRecord screen, add<asynTop>/opi/medm to your EPICS_DISPLAY_PATH +environment variable and start medm with P, R, PORT and ADDR values matching those +given in the dbLoadRecords command: +:: + + medm -x -macro "P=hpE3631ATest,R=asyn,PORT=L0,ADDR=-1" asynRecord.adl + +If you have edm installed then you need to use the asynRecord.edl file instead. +Ensure that<asynTop>/opi/medm is in the EDMDATAFILES environment variable. +Start edm with the arguments appropriate for your IOC: +:: + + edm -x -m "P=hpE3631ATest, R=asyn,PORT=L1_TCP,ADDR=-1" asynRecord.edl + +5. Add records and protocol file entries +---------------------------------------- +The descriptions in this section apply directly to the HP E3631A only but may provide +useful hints for adding commands for your particular device. + +5.1 Add a record to set the device to local or remote control +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +First add an entry to HPE3631ASup/devHPE3631A.proto: +:: + + setLocRem { + out "SYST:%{LOC|REM}"; + } + +This uses the StreamDevice ENUM converter to send one of two strings to the device +based on the PV value. The corresponding addition to HPE3631ASup/devHPE3631A.db +is: +:: + + record(bo, "$(P)$(R)SetRemote") + { + field(DESC, "Set into local/remote mode") + field(DTYP, "stream") + field(OUT, "@devHPE3631A.proto setLocRem $(PORT) $(A)") + field(ZNAM, "Local") + field(ONAM, "Remote") + field(PINI, "YES") + field(VAL, "1") + } + +The PINI and VAL fields ensure that the device is set into remote control mode during +IOC startup. + +Once you've made the above changes run make to install the modified files. +If you've created the test application you can try out the new command and see if +it works. + +5.2 Add records to set and check the output on/off status +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These are simple since they use StreamDevice protocol entries that already exist. +The setD and getD entries set and get the value of a single integer parameter whose +command is passed as the argument to the protocol entry: +:: + + record(bo, "$(P)$(R)SetOnOff") + { + field(DESC, "Turn output off/on") + field(DTYP, "stream") + field(OUT, "@devHPE3631A.proto setD(OUTP) $(PORT) $(A)") + field(ZNAM, "Off") + field(ONAM, "On") + } + record(bi, "$(P)$(R)GetOnOff") + { + field(DESC, "Is output on?") + field(DTYP, "stream") + field(INP, "@devHPE3631A.proto getD(OUTP) $(PORT) $(A)") + field(ZNAM, "Off") + field(ONAM, "On") + } + +5.3 Add records to set and check the output voltage and current setpoints +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Add two entries to HPE3631ASup/devHPE3631A.proto: +:: + + setVI { + out "INST \$1;\$2 %g"; + } + getVI { + out "INST \$1;\$2?"; + in "%g"; + ExtraInput = Ignore; + } + +These entries set and get the floating point value for the channel passed as the +first argument and for the parameter passed as the second argument. + +The corresponding additions to HPE3631ASup/devHPE3631A.db are: +:: + + record(ao, "$(P)$(R)SetP6Volts") + { + field(DESC, "Set +6V output volage") + field(DTYP, "stream") + field(OUT, "@devHPE3631A.proto setVI(P6V,VOLT) $(PORT) $(A)") + field(EGU, "Volts") + field(LOPR, "0") + field(HOPR, "6.18") + field(EGUL, "0") + field(EGUF, "6.18") + field(DRVL, "0") + field(DRVH, "6.18") + } + record(ao, "$(P)$(R)SetP6Amps") + { + field(DESC, "Set +6V output current") + field(DTYP, "stream") + field(OUT, "@devHPE3631A.proto setVI(P6V,CURR) $(PORT) $(A)") + field(EGU, "Amps") + field(LOPR, "0") + field(HOPR, "5.15") + field(EGUL, "0") + field(EGUF, "5.15") + field(DRVL, "0") + field(DRVH, "5.15") + } + record(ao, "$(P)$(R)SetP25Volts") + { + field(DESC, "Set +25V output volage") + field(DTYP, "stream") + field(OUT, "@devHPE3631A.proto setVI(P25V,VOLT) $(PORT) $(A)") + field(EGU, "Volts") + field(LOPR, "0") + field(HOPR, "25.75") + field(EGUL, "0") + field(EGUF, "25.75") + field(DRVL, "0") + field(DRVH, "25.75") + } + record(ao, "$(P)$(R)SetP25Amps") + { + field(DESC, "Set +25V output current") + field(DTYP, "stream") + field(OUT, "@devHPE3631A.proto setVI(P25V,CURR) $(PORT) $(A)") + field(EGU, "Amps") + field(LOPR, "0") + field(HOPR, "1.03") + field(EGUL, "0") + field(EGUF, "1.03") + field(DRVL, "0") + field(DRVH, "1.03") + } + record(ao, "$(P)$(R)SetN25Volts") + { + field(DESC, "Set -25V output volage") + field(DTYP, "stream") + field(OUT, "@devHPE3631A.proto setVI(N25V,VOLT) $(PORT) $(A)") + field(EGU, "Volts") + field(HOPR, "0") + field(LOPR, "-25.75") + field(EGUF, "0") + field(EGUL, "-25.75") + field(DRVH, "0") + field(DRVL, "-25.75") + } + record(ao, "$(P)$(R)SetN25Amps") + { + field(DESC, "Set -25V output current") + field(DTYP, "stream") + field(OUT, "@devHPE3631A.proto setVI(N25V,CURR) $(PORT) $(A)") + field(EGU, "Amps") + field(LOPR, "0") + field(HOPR, "1.03") + field(EGUL, "0") + field(EGUF, "1.03") + field(DRVL, "0") + field(DRVH, "1.03") + } + record(ao, "$(P)$(R)GetP6Volts") + { + field(DESC, "Get +6V output volage") + field(DTYP, "stream") + field(OUT, "@devHPE3631A.proto getVI(P6V,VOLT) $(PORT) $(A)") + field(EGU, "Volts") + field(LOPR, "0") + field(HOPR, "6.18") + field(EGUL, "0") + field(EGUF, "6.18") + } + record(ao, "$(P)$(R)GetP6Amps") + { + field(DESC, "Get +6V output current") + field(DTYP, "stream") + field(OUT, "@devHPE3631A.proto getVI(P6V,CURR) $(PORT) $(A)") + field(EGU, "Amps") + field(LOPR, "0") + field(HOPR, "5.15") + field(EGUL, "0") + field(EGUF, "5.15") + } + record(ao, "$(P)$(R)GetP25Volts") + { + field(DESC, "Get +25V output volage") + field(DTYP, "stream") + field(OUT, "@devHPE3631A.proto getVI(P25V,VOLT) $(PORT) $(A)") + field(EGU, "Volts") + field(LOPR, "0") + field(HOPR, "25.75") + field(EGUL, "0") + field(EGUF, "25.75") + } + record(ao, "$(P)$(R)GetP25Amps") + { + field(DESC, "Get +25V output current") + field(DTYP, "stream") + field(OUT, "@devHPE3631A.proto getVI(P25V,CURR) $(PORT) $(A)") + field(EGU, "Amps") + field(LOPR, "0") + field(HOPR, "1.03") + field(EGUL, "0") + field(EGUF, "1.03") + } + record(ao, "$(P)$(R)GetN25Volts") + { + field(DESC, "Get -25V output volage") + field(DTYP, "stream") + field(OUT, "@devHPE3631A.proto getVI(N25V,VOLT) $(PORT) $(A)") + field(EGU, "Volts") + field(LOPR, "-25.75") + field(HOPR, "0") + field(EGUL, "-25.75") + field(EGUF, "0") + } + record(ao, "$(P)$(R)GetN25Amps") + { + field(DESC, "Get -25V output current") + field(DTYP, "stream") + field(OUT, "@devHPE3631A.proto getVI(N25V,CURR) $(PORT) $(A)") + field(EGU, "Amps") + field(LOPR, "0") + field(HOPR, "1.03") + field(EGUL, "0") + field(EGUF, "1.03") + } + +Depending on your application you might set up FLNK and/or SCAN fields to keep the +setpoint readbacks up to date. diff --git a/docs/source/_static/css/my_theme.css b/docs/source/_static/css/my_theme.css new file mode 100644 index 0000000..d61a819 --- /dev/null +++ b/docs/source/_static/css/my_theme.css @@ -0,0 +1,19 @@ +@import url("theme.css"); + +.wy-nav-content { + max-width: 90%; +} + +/* override table width restrictions */ +@media screen and (min-width: 767px) { + + .wy-table-responsive table td { + /* !important prevents the common CSS stylesheets from overriding + this as on RTD they are loaded after this stylesheet */ + white-space: normal !important; + } + + .wy-table-responsive { + overflow: visible !important; + } +} diff --git a/docs/source/asynDriver.rst b/docs/source/asynDriver.rst new file mode 100644 index 0000000..62dc6ec --- /dev/null +++ b/docs/source/asynDriver.rst @@ -0,0 +1,5798 @@ +asynDriver +========== + +:author: Mark Rivers, Eric Norum, and Marty Kraimer +:date: March 28, 2023 +:version: R4-44-2 + +License Agreement +----------------- +This product is available via the open source license +described at the end of this document. + +.. contents:: Contents + +Purpose +------- +**asynDriver** is a general purpose facility for interfacing device specific +code to low level drivers. asynDriver allows non-blocking device support that works +with both blocking and non-blocking drivers. + +A primary target for asynDriver is EPICS IOC device support but, other than using +libCom, much of it is independent of EPICS. + +asynDriver has the following key concepts: + +- Device support communicates with drivers via interfaces + + - Drivers take care of the details of how to communicate with a device and implement + interfaces for use by device support. Interfaces are defined for both message and + register based devices. In the past when support was written for a new type of device, + device support for standard EPICS records had to be written in addition to the driver + support. Now a driver just implements one or more of the standard interfaces. +- A port provides access to device instances + + - A port, which has a portName, identifies a communication path to one or more device + instances. For example a GPIB port can have up to 15 devices connected to it. An + RS232 port communicates with a single device. Drivers register a port. Device support + connects to a port. +- asynManager controls access to a port + + - asynManager, a component of asynDriver, provides exclusive access to a driver via + calls to queueRequest, lockPort/unlockPort, and queueLockPort/queueUnlockPort. Once + device support has access, it can make an arbitrary number of calls to the driver + knowing that no other support can call the driver. Device and driver support do + not need to implement queues or semaphores since asynManager does this for them. +- asynTrace provides a general purpose diagnostic facility + + - Rules are defined for providing diagnostic messages. Provided device and driver + support follow the rules, a user can obtain several levels of diagnostic information + that can be displayed on the console, written to a file, or sent to the EPICS errlog + facility. +- asynRecord - Generic access to an device/port + + - asynRecord is an EPICS record and set of associated MEDM displays that provide access + + - A port or a device connected to a port + + - The port or port,addr can be changed dynamically. Thus with one asynRecord in an + IOC, it is possible to talk to any device that has an asyn compatible driver. + - asynTrace - All asynTrace options can be controlled with the asynRecord. + - Connection Management + - Display and change connection, enable, and autoConnect state + - Standard interfaces + + - These can be used to communicate with devices. For example if a new instrument arrives + that has a serial, GPIB, or ethernet port, then it is often possible to communicate + with it just by attaching an asynRecord to it. +- Extensive Serial Support + + - asynDriver provides many facilities for communicating with RS232, RS485, GPIB, and + ethernet. + +Status +------ +This version provides: + +- asynManager: the software layer between device support and drivers. +- asynRecord: EPICS record support that provides a generic interface to asynManager, + asynCommon, asynOctet, asynGpib, and other interfaces. +- asynPortDriver: a C++ base class that makes it easy to write asyn drivers, with + much of the boilerplate asyn code handled in the base class methods. +- asynPortClient: C++ classes that makes it easy to write C++ asyn clients that + communicate directly with asyn port drivers without running an EPICS IOC. +- standard interfaces: Standard message and register based interfaces are defined. + Low Level Drivers implement standard interfaces. Device support communicates with + low level drivers via standard interfaces. +- devEpics: Generic device support for EPICS records. +- devGpib: EPICS device support that replaces the device support layer of the Winans/Franksen + gpibCore support. +- asynGpib: a replacement for the drvGpibCommon layer of the Franksen gpibCore support. +- drvAsynSerialPort: Support for devices connected to serial ports. +- drvAsynIPPort: Support for TCP/IP and UDP/IP socket communication, including serial + devices accessed via Ethernet/Serial converter boxes. +- drvAsynIPServerPort: Support for asyn socket servers that are accessed from remote + clients. TCP/IP sockets and UDP are supported. +- VXI-11: A replacement for the VXI-11 support of the Franksen gpibCore support. +- drvPrologixGPIB: Support for GPIB devices over Ethernet using the Prologix GPIB-Ethernet + controller. +- Linux-gpib: Support for the Linux GPIB Package library. +- gsIP488: A low level driver for the Greensprings IP488 Industry Pack module. +- ni1014: A low level driver for the National Instruments VME 1014D. +- Serial Bus Support: The asynLockPortNotify interface was added to make it easier + to support serial bus drivers that use the standard serial support. + +The following are some of the existing EPICS general purpose device support systems +that have been converted to use asynDriver: + +- StreamDevice. This is the protocol file-based support for serial/GPIB/CAN from + Dirk Zimoch. +- gpibCore. This is the operating-system-independent version of the Winans/Franksen + GPIB support. +- synApps (The APS BCDA synchrotron applications). The mca, dxp, motor, Ip330, IpUnidig, + DAC128V and quadEM applications in this package have all been converted to asyn. + The serial and GPIB modules in this package are no longer needed, because the asyn + record replaces them. The areaDetector module was written to use asyn, and was the + original motivation for the development of asynPortDriver. + +Acknowledgments +--------------- +The idea of creating asynDriver resulted from many years of experience with writing +device support for serial and GPIB devices. The following individuals have been +most influential. + +- **John Winans** + + - John provided the original EPICS GPIB support. Databases using John's support can + be used without modification with devGpib. With small modifications, device support + modules written for John's support can be used. +- **Benjamin Franksen** + + - John's support only worked on vxWorks. In addition, the driver support was implemented + as a single source file. Benjamin defined an interface between drvCommon and low + level controllers and split the code into drvGpib and the low level drivers. He + also created the support for drvVxi11. +- **Eric Norum** + + - Eric started with Benjamin's code and converted it to use the Operating System Independent + features of EPICS 3.14. +- **Marty Kraimer** + + - Marty started with Eric's version and made changes to support secondary addressing; + and to replace ioctl with code to support general bus management, universal commands, + and addressed commands. +- **Pete Owens** + + - Pete, for the Diamond Light Source, did a survey of several types of device/driver + support packages for serial devices. Diamond decided to use the StreamDevice support + developed by Dirk Zimoch. +- **Dirk Zimoch** + + - Dirk developed StreamDevice, which has a single device support model, but supports + arbitrary low level message based drivers, i.e. GPIB, serial, etc. +- **Jun-ichi Odagare** + + - Jun-ichi developed NetDev, a system that provides EPICS device support for network + based devices. It has a single device support model, but provides a general framework + for communicating with network based devices. +- **Mark Rivers** + + - Mark became an active developer of asynDriver soon after he started converting SynApps + to use asynDriver. He soon pushed to have asynDriver support synchronous drivers, + support register based drivers, and support interrupts. With these additions asynDriver + is a framework for interfacing to a large class of devices instead of just message + based asynchronous devices. +- **Yevgeny A. Gusev** + + - Yevgeny has found bugs and suggested improvements in the way asynManager handles + queue timeouts and cancels. He provides an expert and welcome set of eyes to look + at difficult code!!! + +Overview of asynDriver +---------------------- + +Definitions +~~~~~~~~~~~ +asynDriver is a software layer between device specific code and drivers that communicate +with devices. It supports both blocking and non-blocking communication and can be +used with both register and message based devices. asynDriver uses the following +terminology: + +- interface + + - All communication between software layers is done via interfaces. An interface definition + is a C language structure consisting entirely of function pointers. An asynDriver + interface is analogous to a C++ or Java pure virtual interface. Although the implementation + is in C, the spirit is object oriented. Thus this document uses the term "method" + rather than "function pointer". +- port + + - A physical or logical entity which provides access to a device. A port provides + access to one or more devices. +- portDriver + + - Code that communicates with a port. +- portThread + + - If a portDriver can block, a thread is created for each port, and all I/O to the + portDriver is done via this thread. +- device + + - A device (instrument) connected to a port. For example a GPIB interface can have + up to 15 devices connected to it. Other ports, e.g. RS-232 serial ports, only support + a single device. Whenever this document uses the word device without a qualifier, + it means something that is connected to a port. + +- device support + + - Code that interacts with a device. +- synchronous + + - Support that does not voluntarily give up control of the CPU. +- asynchronous + + - Support that is not synchronous. Some examples of asynchronous operations are epicsThreadSleep, + epicsEventWait, and stdio operations. Calls to epicsMutexTake are considered to + be synchronous operations, i.e. they are permitted in synchronous support. +- asynDriver + + - The name for the support described in this manual. It is also the name of the header + file that describes the core interfaces. +- asynManager + + - An interface and the code which implements the methods for interfaces asynManager + and asynTrace. +- asynchronous Driver + + - A driver that blocks while communicating with a device. Typical examples are serial, + gpib, and network based drivers. +- synchronous Driver + + - A driver that does not block while communicating with a device. Typical examples + are VME register based devices. +- Message Based Interfaces + + - Interfaces that use octet arrays for read/write operations. +- Register Based Interfaces + + - Interfaces that use integers or floats for read/write operations. +- interrupt + + - As implemented by asynManager, interrupt just means "I have a new value for port, + address". + +Synchronous/asynchronous and message/register are orthogonal concepts. For example +a register based driver can be either synchronous or asynchronous. The terminology +register vs message is adapted from VXI. + +Standard interfaces are defined so that device specific code can communicate with +multiple port drivers. For example if device support does all its communication +via reads and writes consisting of 8 bit bytes (octets), then it should work with +all port drivers that support octet messages. If device support requires more complicated +support, then the types of ports will be more limited. Standard interfaces are also +defined for drivers that accept 32 bit integers or 64 bit floats. Additional interfaces +can be defined, and it is expected that additional standard interfaces will be defined. + +One or more devices can be attached to a port. For example, only one device can +be attached to an RS-232 port, but up to 15 devices can be attached to a GPIB port. + +Multiple layers can exist between device specific code and a port driver. A software +layer calls interposeInterface in order to be placed between device specific code +and drivers. For more complicated protocols, additional layers can be created. For +example, GPIB support is implemented as an asynGpib interface which is called by +user code, and an asynGpibPort interface which is called by asynGpib. + +A driver normally implements multiple interfaces. For example asynGpib implements +asynCommon, asynOctet, and asynGpib. + +asynManager uses the Operating System Independent features of EPICS base. It is, +however, independent of record/device support. Thus, it can be used by other code, +e.g. a sequence program. + +Standard Interfaces +~~~~~~~~~~~~~~~~~~~ +These are interfaces provided by asynManager or interfaces implemented by all or +most port drivers. + +The interfaces are: + +**asynManager** provides services for communicating with a device connected to a port. + +**asynCommon** is an interface that must be implemented by all low level drivers. The methods are: + +- report - Report status of port. +- connect - Connect to the port or device. +- disconnect - Disconnect from the port or device. + +**asynTrace** is an interface for generating diagnostic messages. + +**asynLockPortNotify** is an interface that is implemented by a driver which is an asynUser of another driver. +An example is a serial bus driver that uses standard serial support. asynManager calls asynLockPortNotify +whenever it locks or unlocks the port. + +**asynDrvUser** is an interface for communicating information from device support to a driver without the device support knowing any +details about what is passed. + +Generic Interfaces +~~~~~~~~~~~~~~~~~~ + +In addition to **asynCommon** and optionally **asynDrvUser**, port drivers can implement one +or more of the following message and/or register based interfaces. + +**asynOctet** methods for message based devices + +**asynFloat64** methods for devices that read/write IEEE float values + +**asynFloat32Array** methods for devices that read/write arrays of IEEE 32-bit float values + +**asynFloat64Array** methods for devices that read/write arrays of IEEE 64-bit float values + +**asynInt32** methods for devices that read/write integer values. Many analog I/O drivers can use this interface. + +**asynInt64** methods for devices that read/write 64-bit integer values. + +**asynInt8Array** methods for devices that read/write arrays of 8-bit integer values + +**asynInt16Array** methods for devices that read/write arrays of 16-bit integer values + +**asynInt32Array** methods for devices that read/write arrays of 32-bit integer values + +**asynInt64Array** methods for devices that read/write arrays of 64-bit integer values + +**asynUInt32Digital** methods for devices that read/write arrays of digital values. +This interface provides a mask to address individual bits within registers. + +**asynGenericPointer** methods for devices that read/write arbitrary structures, passed via a void* pointer. +The client and the server of course need to agree on the structure type being pointed to. + +**asynEnum** methods for devices to define enum strings, values, and severities. + +**asynOption** methods for device configuration using key/value pairs. + + +asynManager +~~~~~~~~~~~ +asynManager is an interface and associated code. It is the "heart" of asynDriver +since it manages the interactions between device support code and drivers. It provides +the following services: + +reporting +......... + + Method: report + +asynUser creation +................. + + Methods: createAsynUser, duplicateAsynUser, freeAsynUser + + An asynUser is a "handle" for accessing asynManager services and for calling interfaces + implemented by drivers. An asynUser must only be created via a call to createAsynUser + or duplicateAsynUser since asynManager keeps private information for each asynUser. + freeAsynUser puts the asynUser on a free list rather than calling free. Clients + can continually create and free asynUsers quickly and without fragmenting memory. + + The call to createAsynUser specifies a processCallback and a timeoutCallback. These + are the callbacks that will be called as a result of a queueRequest. + An asynUser should not be shared between parts of code that can simultaneously access + a driver. For example device support for standard EPICS records should create an + asynUser for each record instance. + +Basic asynUser services +....................... + + Methods: connectDevice, disconnect, findInterface + + These methods should only be called by the code that created the asynUser. + + After an asynUser is created the user calls connectDevice. The user is connected + to a port driver that can communicate with a device. findInterface is called for + each interface the user requires. disconnect is called when the user is done with + the device. + +Queuing services +................ + + Methods: queueRequest, cancelRequest, lockPort, unlockPort, queueLockPort, queueUnlockPort, + blockProcessCallback, unblockProcessCallback + + queueRequest is a request to call the processCallback specified in the call to createAsynUser. + Most interface methods must only be called from processCallback via a call to queueRequest + or between calls to lockPort/unlockPort.. Exceptions to this rule must be clearly + documented (a common exception are methods registerInterruptUser/cancelInterruptUser). + + queueRequest semantics differ for ports that can block and ports that do not block + + When registerPort is called by a driver that can block, a thread is created for + the port. A set of queues, based on priority, is created for the thread. queueRequest + puts the request on one of the queues. The port thread takes the requests from the + queues and calls the associated callback. Only one callback is active at a time. + + When registerPort is called by a driver that does not block, a mutex is created + for the port. queueRequest takes the mutex, calls the callback, and releases the + mutex. The mutex guarantees that two callbacks to a port are not active at the same + time. + + lockPort is a request to lock all access to low level drivers until unlockPort is + called. If the port blocks then lockPort and all calls to the port driver may block. + lockPort/unlockPort are provided for use by code that is willing to block or for + communication with synchronous ports. A call to lockPort locks all addresses associated + with a multi-address port. Prior to asyn R4-14 pasynManager->lockPort() immediately + took the port mutex when it was available, rather than queueing a request to take + the mutex. From asyn R4-14 to R4-20 lockPort 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. In R4-21 + the queued lockPort and unlockPort functions were renamed to queueLockPort and queueUnlockPort, + and the original lightweight lockPort and unlockPort functions were restored. Up + to R4-32 when queueLockPort called queueRequest it did not specify a timeout. This + could lead to code being hung if the port disconnected after the call to queueRequest + but before the callback was called. The code would remain hung until the port reconnected. + In R4-32 the queueRequest is done with a timeout. The default timeout value is 2.0 + seconds but this can be change with the shell command asynSetQueueLockPortTimeout(portName, + double timeout). If the pasynUser->timeout passed to queueLockPort is greater + than the current port timeout value this larger timeout from the pasynUser is used + instead. + + blockProcessCallback is a request to prevent acccess to a device or port by other + asynUsers between queueRequests. blockProcessCallback can be called from a processCallback + or when the asynUser has no request queued. When called from processCallback blocking + starts immediately, otherwise blocking starts the next time processCallback is called. + Blocking means that no other asynUser's processCallback will be called until unblockProcessCallback + is called. blockProcessCallback only works with drivers that can block and an error + is returned if it is called for non-blocking drivers. + +Basic Driver services +..................... + + Methods: registerPort, registerInterface + + registerPort is called by a portDriver. registerInterface is called by a portDriver + or an interposeInterface. + + Each port driver provides a configuration command that is executed for each port + instance. The configuration command performs port specific initializations, calls + registerPort, and registerInterface for each interface it implements. + +Attribute Retrieval +................... + + Methods: isMultiDevice, canBlock, getAddr, getPortName, isConnected, isEnabled, + isAutoConnect + + These methods can be called by any code that has access to the asynUser + +Connection services +................... + + Methods: enable,autoConnect,setAutoConnectTimeout + + These methods can be called by any code that has access to the asynUser. + + These methods can be called to set the enable and autoConnect settings for a port + and/or device. If autoConnect is true then asynManager does the following: + + When the port registers its asynCommon interface, asynManager queues a connection + request. It then 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 + function pasynManager->setAutoConnectTimeout(double timeout). This function can + be accessed from the iocsh shell with the 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 means that it + is very likely that the pasynCommon->connect() call will occur as soon as the + asynCommon interface is registered, which means that the driver must have already + done all initialization required for the asynCommon->connect() callback before + it registers the asynCommon interface. If the port does not connect initially, or + if it subsequently disconnects, then asynManager will queue a connection request + every 20 seconds. If autoConnect is true and port/device is enabled but the device + is not connected, then queueManager calls calling asynCommon:connect just before + it calls processCallback. + +Exception services +.................... + + Methods: exceptionCallbackAdd, exceptionCallbackRemove, exceptionConnect, exceptionDisconnect + + Device support code calls exceptionCallbackAdd and exceptionCallbackRemove. The + complete list of exceptions is defined in asynDriver.h as "enum asynException". + + Whenever a port driver connects or disconnects, normally as a result of a call to + asynCommon:connect or asynCommon:disconnect, it must also call exceptionConnect + or exceptionDisconnect. + +Interrupt services +.................. + + Methods: registerInterruptSource, getInterruptPvt, createInterruptNode, freeInterruptNode, + addInterruptUser, removeInterruptUser, interruptStart, interruptEnd + + Interrupt just means: "I have a new value." Many asyn interfaces, e.g. asynInt32, + provide interrupt support. These interfaces provide methods addInterruptUser and + removeInterruptUser. Device support calls addInterruptUser if it wants to be called + whenever an interrupt occurs. Drivers or other code that implements the interface + calls the registered users when it has new data. asynManager provides services that + help drivers implement thread-safe support for interrupts. + + A driver that supports interrupts calls registerInterruptSource for each interface + that has associated interrupts. It calls interruptStart to obtain a list of all + registered users and interruptEnd after it calls the registered users. The driver + is also responsible for calling addInterruptUser and removeInterruptUser. + + If any calls are made to addInterruptUser or removeInterruptUser between the calls + to interruptStart and interruptEnd, asynManager puts the request on a list and processes + the request after interruptEnd is called. + + Many standard interfaces, e.g. asynInt32, provide methods registerInterruptUser, + cancelInterruptUser. These interfaces also provide an auxilliary interface, e.g. + asynInt32Base, and code which implements registerInterruptUser and cancelInterruptUser. + + On operating systems like vxWorks or RTEMS interruptStart,interruptEnd MUST NOT + be called from interupt level. + +Timestamp services +.................. + + Methods: updateTimeStamp, getTimeStamp, setTimeStamp, registerTimeStampSource, unregisterTimeStampSource. + + These methods provide support for setting a timestamp for a port. This timestamp + is typically used to set the pasynUser->timestamp field that is passed to device + support on read or callback operations. Device support uses the pasynUser->timestamp + field to set the record TIME field. This will then be the record timestamp if the + record TSE field is -2. asynManager provides a default timestamp source function + which just calls epicsTimeGetCurrent(). However, registerTimeStampSource can be + used to supply a different user-provided timestamp source function, for example + one that calls epicsTimeGetEvent(), or some other site-specific timestamp source. + unregisterTimeStampSource reverts to the default timestamp source in pasynManager. + +General purpose freelist service +................................ + + Methods: memMalloc, memFree + + These methods do not require an asynUser. They are provided for code that must continually + allocate and free memory. Since memFree puts the memory on a free list instead of + calling free, they are more efficient that calloc/free and also help prevent memory + fragmentation. + +Interpose service +................. + + Method: interposeInterface + + Code that calls interposeInterface implements an interface which is either not supported + by a port driver or that is "interposed" between the caller and the port driver. + For example asynInterposeEos interposes asynOctet. It performs end of string processing + for port drivers that do not support it. + + interposeInterface is recursive, i.e. an arbitrary number of interpose layers can + exist above a single port,addr. + +Multiple Device vs Single Device Port Drivers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When a low level driver calls registerPort, it declares if it handles multiple devices. +This determines how the addr argument to connectDevice is handled and what getAddr +returns. + + **multiDevice false** + + The addr argument to connectDevice is ignored and getAddr always returns -1 + + **multiDevice true** + + If connectDevice is called with addr<0, the connection is to the port and getAddr + always returns -1. If addr>=0, then the caller is connected to the device at + the specified address. getAddr will return this address. An asynUser connected to + the port can issue requests that affect all address on the port. For example disabling + access to the port prevents access to all addresses on the port. + +Connection Management +~~~~~~~~~~~~~~~~~~~~~ + +asynManager keeps track of the following states: + + **connection** + + Is the port or device connected? This state is initialized to disconnected. + + **enabled** + + Is the port or device enabled? This state is initialized to enabled. + + **autoConnect** + + Does asynManager automatically attempt to connect if it finds the port or device + disconnected? This is initialized to the state specified in the call to registerPort. + +If the port does not support multiple devices, then port and device status are the +same. If the port does support multiple devices, then asynManager keeps track of +the states for the port and for every device connected to the port. + +Whenever any of the states change for a port or device, then all users that previously +called exceptionCallbackAdd for that port or device are called. + +Low level drivers must call pasynManager:exceptionConnect whenever they connect +to a port or port,addr and exceptionDisconnect whenever they disconnect. + + +Protecting a Thread from Blocking +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The methods asynManager:report and asynCommon:report can be called by any thread, +but the caller is blocked until the report finishes. lockPort, unlockPort, queueLockPort, +queueUnlockPort, and most port methods may block. The other asynManager methods +can be called by any thread including portThread. None of these methods block. + +Unless stated otherwise the methods for other interfaces must only be called by +processCallback or by calls between lockPort/unlockPort, or queueLockPort/queueUnlockPort. + +Interface methods registerInterruptUser and cancelInterruptUser must never block. +The registerInterruptUser callback must not block because it could be called by +a non blocking driver. + +portThread +~~~~~~~~~~ + +If a driver calls asynManager:registerPort with the ASYN_CANBLOCK attributes bit +set, then asynManager creates a thread for the port. Each portThread has its own +set of queues for the calls to queueRequest. Four queues are maintained. One queue +is used only for asynCommon:connect and asynCommon:disconnect requests. The other +queues provide different priorities: low, medium, and high. queueRequests to any +queue other then the connection queue will be rejected if the port is not connected. +portThread runs forever implementing the following algorithm: + +#. Wait for work by calling epicsEventMustWait. Other code such as queueRequest call + epicsEventSignal. +#. If the port is disabled, go back to 1. +#. For every element in queue, asynQueuePriorityConnect: + + - Removes the element from the queue. + - Calls the user's callback +#. For each element of the queues asynQueuePriorityHigh, ...,asynQueuePriorityLow. + + - If disabled, skip this element. + - If not connected and autoConnect is true for the device, then attempt to connect + to the device. + - If not connected, skip this element. + - If blocked by another thread, skip this element. + - If not blocked and user has requested blocking, then blocked. + - Remove from queue and: + + * lock port + * call user callback + * unlock port + +The actual code is more complicated because it unlocks before it calls code outside +asynManager. This means that the queues can be modified and exceptions may occur. + +Overview of Queuing +~~~~~~~~~~~~~~~~~~~ + +When discussing queuing it is useful to think of 3 components of asyn: + +#. asynManager. This is the core part of asyn. It knows nothing about EPICS records. + In fact it is completely independent of EPICS except that it uses libCom for OS-independent + things like mutexes, message queues, events, etc. The queuing it provides is for + callback requests to communicate with asynchronous drivers (ASYN_CANBLOCK) via pasynManager->queueRequest(). +#. Standard asyn device support (devEpics directory). This is the only part of asyn + that knows about EPICS records and depends on EPICS components other than libCom. + It supports callbacks from the driver under 3 conditions: + + - Input records with SCAN=I/O Intr + - Input records with periodic scanning (asynInt32Average and asynFloat64Average only) + - Output records with asyn:READBACK=1. + + The callback values can be placed in a ring buffer so that values are not lost if + the callbacks happen faster than the record can process. The size of the ring buffer + can be controlled with the asyn:FIFO info tag. The default is 10 for scalar records. + The default is 0 for devAsynOctet, waveform, stringin, stringout, lsi, lso, printf + and scalcout records. If the ring buffer is in use then each driver callback results + in pushing a new value into the buffer and a request to process the record in a + separate callback thread. If the ring buffer is full then the oldest value in the + queue is discarded and the new value is added. This guarantees that the record will + eventually have the value of the most recent callback, but it may skip some before + this. If ASYN_TRACE_WARNING is set then a warning message is printed. The driver + callbacks do not block waiting for the record to process. +#. asynPortDriver. asynPortDriver does not support queueing. It does have a parameter + library that stores the most recent value of scalar parameters. It does not store + values for array parameters. + +Theory of Operation +------------------- + +Initialization +~~~~~~~~~~~~~~ +During initialization, port drivers register each communication port as well as +all supported interfaces. + +User code creates an asynUser, which is a "handle" for accessing asynDriver facilities, +by calling +:: + + pasynManager->createAsynUser(processCallback, timeoutCallback); + +An asynUser has the following features: + +- An asynUser is the means by which asynManager manages multiple requests for accessing + a port. +- processCallback,which is used by queueRequest described below, is the addresss + of a user supplied callback routine. +- timeoutCallback is the address of caller supplied callback that will be called + if a queueRequest remains on the queue too long. +- Device support code should create an asynUser for each "atomic" access to low + level drivers, i.e. a set of calls that must not be interlaced with other calls + to the low level drivers. For example device support for EPICS record support should + create an asynUser for each record instance. +- Device support code should NOT try to share an asynUser between multiple sources + of requests for access to a port. If this is done then device support must itself + handle contention issues that are already handled by asynManager. + +User code connects to a low level driver via a call to +:: + + status = pasynManager->connectDevice(pasynUser, portName, addr); + + +This call must specify the name of the port and the address of the device. It then +calls findInterface to locate the interfaces with which it calls the driver. For example +:: + + pasynInterface = pasynManager->findInterface(pasynUser, asynOctetType, 1); + +Requesting access to a port +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- queueRequest + + The processCallback passed to createAsynUser makes calls to the port interfaces. + +- lockPort/unlockPort, queueLockPort/queueUnlockPort + + The caller can make calls to the port interfaces while the lock is held. These calls + and calls to the port may block and thus should NOT be used by code that should + not block, e.g. synchronous device support for EPICS records. + +queueRequest - Flow of Control +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +User code requests access to a port by calling +:: + + status = pasynManager->queueRequest(pasynUser, priority, timeout); + +This results in either processCallback or timeoutCallback being called. Most requests +to a port must be made from processCallback. queueRequest does not block. If queueRequest +is called for a port that can block the request is queued to a thread dedicated +to the port. If queueRequest is called for a port does not block it just calls processCallback. +guarantee is valid only if low level drivers are only accessed by calling queueRequest, +lockPort/unlockPort, and/or queueLockPort/queueUnlockPort + +The following examples are based on EPICS IOC record/device support. + +The first example shows access to a port that can block. + +.. figure:: AsynFlow.jpg + :align: center + + **Figure 1: Asynchronous Control Flow** + +The sequence of record device support events that occurs starting with an application +thread is pictured above in Figure 1, and explained below in the following steps: + +#. Record processing calls device support with PACT 0 (Processing is not active). +#. Device support calls queueRequest. +#. queueRequest places the request on the driver work queue. The application thread + is now able to go on and perform other operations. Subsequent operations for this + I/O request are handled in the port driver thread. +#. The portThread removes the I/O request from the work queue. +#. The portThread calls the processCallback located in Record device support. +#. processCallback calls the low-level driver. The low-level driver read or write + routine blocks until the I/O completes or until a timeout occurs. The low-level + driver routine returns the results of the I/O operation to processCallback. +#. processCallback requests that the record be processed. NOTE: The process request + will be made by one of the standard callback requests rather than the port thread. +#. Record support calls device support again, this time with PACT 1(processing is + active). Device support updates fields in the record and returns to record support + which completes record processing. + +The second example shows access to a port that cannot block. + +.. figure:: AsynSynFlow.jpg + :align: center + + **Figure 2: Synchronous Control Flow** + +The sequence of record device support events that occurs starting with an application +thread is pictured above in Figure 2, and explained below in the following steps: + +#. Record processing calls device support. +#. Device support calls queueRequest. +#. Since the port is synchronous, i.e. can not block, queueRequest locks the port + and then calls the processCallback. +#. processCallback calls the low-level driver read or write routine. The low-level + driver routine returns the results of the I/O operation to processCallback. +#. processCallback returns to queueRequest, which unlocks the port and returns to + device support, which returns to record support, which completes record processing. + +asynDriver Structures and Interfaces +------------------------------------ + +asynDriver.h describes the following: + +- asynStatus - An enum that describes the status returned by many methods. +- asynException - An enum that describes exceptions. +- asynQueuePriority - An enum that describes the queue priorities. +- asynUser - A struture that contains generic information and is the "handle" for calling most methods. +- asynInterface - a structure that describes an interface. +- userCallback - a typedef for the user process callback function described above. +- exceptionCallback - a typedef for a user callback to be called when exceptions occur. +- timeStampCallback - a typedef for a user callback function that will be called by updateTimeStamp. +- asynManager - An interface for communicating with asynDriver. +- asynCommon - An interface providing methods that must be implemented by all low level drivers. +- asynTrace - An interface plus associated functions and definitions that implement the trace facility. + + +asynStatus +~~~~~~~~~~ + +Defines the status returned by most methods. If a method returns a status other +than asynSuccess, and one of the arguments to the method is pasynUser, then the +method is expected to write a message into pasynUser->errorMessage. +:: + + typedef enum { + asynSuccess,asynTimeout,asynOverflow,asynError,asynDisconnected,asynDisabled + } asynStatus + + +.. list-table:: asynStatus + :widths: 20 80 + + * - asynSuccess + - The request was successful. + * - asynTimeout + - The request failed with a timeout. + * - asynOverflow + - The driver has lost input data. This can happen if an internal buffer or the user + supplied buffer is too small. Whenever possible, low level drivers should be written + so that the user can read input in small pieces. + * - asynError + - Some other error occured. + * - asynDisconnected + - The request failed because the port is not connected. + * - asynDisabled + - The request failed because the port or device is disabled. + +asynException +~~~~~~~~~~~~~ +Defines the exceptions for method exceptionOccurred +:: + + typedef enum { + asynExceptionConnect,asynExceptionEnable,asynExceptionAutoConnect, + asynExceptionTraceMask,asynExceptionTraceIOMask,asynExceptionTraceInfoMask, + asynExceptionTraceFile,asynExceptionTraceIOTruncateSize + } asynException; + +.. list-table:: asynException + :widths: 20 80 + + * - asynExceptionConnect + - The connection state of the port or device has changed. + * - asynExceptionEnable + - The enable state of the port or device has changed. + * - asynExceptionAutoConnect + - The autoConnect state of the port or device has changed. + * - asynExceptionTraceMask + - The traceMask for the port or device has changed. + * - asynExceptionTraceIOMask + - The traceIOMask for the port or device has changed. + * - asynExceptionTraceInfoMask + - The traceInfoMask for the port or device has changed. + * - asynExceptionTraceFile + - The trace file for the port or device has changed. + * - asynExceptionTraceIOTruncateSize + - The traceIOTruncateSize for the port or device has changed. + +asynQueuePriority +~~~~~~~~~~~~~~~~~ +This defines the priority passed to queueRequest. +:: + + typedef enum { + asynQueuePriorityLow,asynQueuePriorityMedium,asynQueuePriorityHigh, + asynQueuePriorityConnect + } asynQueuePriority; + +.. list-table:: asynQueuePriority + :widths: 20 80 + + * - asynQueuePriorityLow + - Lowest queue priority. + * - asynQueuePriorityMedium + - Medium queue priority. + * - asynQueuePriorityHigh + - High queue priority. + * - asynQueuePriorityConnect + - Queue a connect or disconnect request. This priority must be used for and only for + connect/disconnect requests. + +asynUser +~~~~~~~~ +Describes a structure that user code passes to most asynManager and driver methods. +Code must allocate and free an asynUser by calling asynManager:createAsynUser (or +asynManager:duplicateAsynUser) and asynManager:freeAsynUser. +:: + + 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; + /* The following is for use by driver */ + void *drvUser; + /* The following is normally set by driver via asynDrvUser->create() */ + int reason; + epicsTimeStamp timestamp; + /* The following are for additional information from method calls */ + int auxStatus; /* For auxillary status*/ + int alarmStatus; /* Typically for EPICS record alarm status */ + int alarmSeverity; /* Typically for EPICS record alarm severity */ + } asynUser; + +.. list-table:: asynUser + :widths: 20 80 + + * - errorMessage + - When a method returns asynError it should put an error message into errorMessage + via a call to + :: + + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "",...) + + The error message should *not* end with (nor contain) a newline character + sequence (e.g. ``\n``). It is up to user code to decide whether and how to + display the error message. Keeping newlines out of the error message make it easy + for user code to embed the error message in another message or output format. + * - errorMessageSize + - The size of errorMessage. The user can not change this value. + * - timeout + - The number of seconds before timeout for I/O requests. This is set by the user and + can be changed between calls to a driver. If a call to a low level driver results + in the driver making many I/O requests this is the time for each I/O request. + The meaning is as follows: + + > 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. + * - userPvt + - For use by the user. The user should set this immediately after the call to pasynManager->createAsynUser. + + If this is changed while asynUser is queued, the results are undefined, e.g. it + could cause a crash. + * - userData + - Also for use by the user. + * - drvUser + - A driver can use this to hold asynUser specific data. The asynDrvUser interface + is used for communication between asynUser and the driver. + * - reason + - Drivers and asynUsers can use this as a general purpose field. By convention it + is used to determine what "command" is being sent over a particular interface. For + example an A/D driver implementing the asynInt32 interface might define reason=0 + to mean "return the A/D conversion", while reason=1 might mean "return the amplifier + gain". Typically drivers implement the asynDrvUser interface, and use this to convert + from descriptive strings for commands (e.g. "DATA" or "GAIN" in this example) to + the enum "reason". A driver that is calling an interrupt users often uses reason + to decide if the users callback should be called. Values of reason less than 0 are + reserved for standard meanings. For example ASYN_REASON_SIGNAL is used to mean "out + of band" request. The devGpib support uses this to report SRQs. + * - timestamp + - Devices which provide their own time stamps use this field to provide the time value + for records whose TSE field is set to "-2". + * - auxStatus + - Any method can provide additional return information in auxStatus. The meaning is + determined by the method. Callbacks can use auxStatus to set record alarm status + in device support callback functions. + * - alarmStatus + - Any method can provide additional return information in alarmStatus. The meaning + is determined by the method. Callbacks can use alarmStatus to set record alarm status + in device support callback functions. + * - alarmSeverity + - Any method can provide additional return information in alarmStatus. The meaning + is determined by the method. Callbacks can use alarmSeverity to set record alarm + severity in device support callback functions. + + +asynInterface +~~~~~~~~~~~~~ +This defines an interface registered with asynPortManager:registerPort or asynManager:interposeInterface. +:: + + typedef struct asynInterface{ + const char *interfaceType; /*For example, asynCommonType */ + void *pinterface; /*For example, pasynCommon */ + void *drvPvt; + } asynInterface; + +.. list-table:: asynInterface + :widths: 20 80 + + * - interfaceType + - A character string describing the interface. + * - pinterface + - A pointer to the interface. The user must cast this to the correct type. + * - drvPvt + - For the exclusive use of the code that called registerPort or interposeInterface. + +asynManager +~~~~~~~~~~~ +This is the main interface for communicating with asynDriver. +:: + + /*registerPort attributes*/ + #define ASYN_MULTIDEVICE 0x0001 + #define ASYN_CANBLOCK 0x0002 + + /*standard values for asynUser.reason*/ + #define ASYN_REASON_SIGNAL -1 + + #define ASYN_REASON_RESERVED_LOW 0x70000000 + #define ASYN_REASON_RESERVED_HIGH 0x7FFFFFFF + + #define ASYN_REASON_QUEUE_EVEN_IF_NOT_CONNECTED ASYN_REASON_RESERVED_LOW + + typedef void (*userCallback)(asynUser *pasynUser); + typedef void (*exceptionCallback)(asynUser *pasynUser,asynException exception); + typedef void (*timeStampCallback)(void *userPvt, epicsTimeStamp *pTimeStamp); + + 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); + asynUser *(*duplicateAsynUser)(asynUser *pasynUser, + userCallback queue,userCallback timeout); + asynStatus (*freeAsynUser)(asynUser *pasynUser); + void *(*memMalloc)(size_t size); + void (*memFree)(void *pmem,size_t size); + asynStatus (*isMultiDevice)(asynUser *pasynUser, + const char *portName,int *yesNo); + /* addr = (-1,>=0) => connect to (port,device) */ + asynStatus (*connectDevice)(asynUser *pasynUser, + const char *portName,int addr); + asynStatus (*disconnect)(asynUser *pasynUser); + asynStatus (*exceptionCallbackAdd)(asynUser *pasynUser, + exceptionCallback callback); + asynStatus (*exceptionCallbackRemove)(asynUser *pasynUser); + asynInterface *(*findInterface)(asynUser *pasynUser, + const char *interfaceType,int interposeInterfaceOK); + asynStatus (*queueRequest)(asynUser *pasynUser, + asynQueuePriority priority,double timeout); + asynStatus (*cancelRequest)(asynUser *pasynUser,int *wasQueued); + asynStatus (*blockProcessCallback)(asynUser *pasynUser, int allDevices); + asynStatus (*unblockProcessCallback)(asynUser *pasynUser, int allDevices); + asynStatus (*lockPort)(asynUser *pasynUser); + asynStatus (*unlockPort)(asynUser *pasynUser); + asynStatus (*queueLockPort)(asynUser *pasynUser); + asynStatus (*queueUnlockPort)(asynUser *pasynUser); + asynStatus (*setQueueLockPortTimeout)(asynUser *pasynUser, double timeout); + asynStatus (*canBlock)(asynUser *pasynUser,int *yesNo); + asynStatus (*getAddr)(asynUser *pasynUser,int *addr); + asynStatus (*getPortName)(asynUser *pasynUser,const char **pportName); + /* drivers call the following*/ + asynStatus (*registerPort)(const char *portName, + int attributes,int autoConnect, + unsigned int priority,unsigned int stackSize); + asynStatus (*registerInterface)(const char *portName, + asynInterface *pasynInterface); + asynStatus (*exceptionConnect)(asynUser *pasynUser); + asynStatus (*exceptionDisconnect)(asynUser *pasynUser); + /*any code can call the following*/ + asynStatus (*interposeInterface)(const char *portName, int addr, + asynInterface *pasynInterface, + asynInterface **ppPrev); + asynStatus (*enable)(asynUser *pasynUser,int yesNo); + asynStatus (*autoConnect)(asynUser *pasynUser,int yesNo); + asynStatus (*isConnected)(asynUser *pasynUser,int *yesNo); + asynStatus (*isEnabled)(asynUser *pasynUser,int *yesNo); + asynStatus (*isAutoConnect)(asynUser *pasynUser,int *yesNo); + asynStatus (*setAutoConnectTimeout)(double timeout); + asynStatus (*waitConnect)(asynUser *pasynUser, double timeout); + /*The following are methods for interrupts*/ + asynStatus (*registerInterruptSource)(const char *portName, + asynInterface *pasynInterface, void **pasynPvt); + asynStatus (*getInterruptPvt)(asynUser *pasynUser, + const char *interfaceType, void **pasynPvt); + interruptNode *(*createInterruptNode)(void *pasynPvt); + asynStatus (*freeInterruptNode)(asynUser *pasynUser,interruptNode *pnode); + asynStatus (*addInterruptUser)(asynUser *pasynUser, + interruptNode*pinterruptNode); + asynStatus (*removeInterruptUser)(asynUser *pasynUser, + interruptNode*pinterruptNode); + asynStatus (*interruptStart)(void *pasynPvt,ELLLIST **plist); + asynStatus (*interruptEnd)(void *pasynPvt); + /* Time stamp functions */ + 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); + + const char *(*strStatus)(asynStatus status); + } asynManager; + epicsShareExtern asynManager *pasynManager; + +.. list-table:: asynManager + :widths: 20 80 + + * - report + - Reports status about the asynPortManager. If portName is non-NULL it reports for + a specific port. If portName is NULL then it reports for each registered port. It + also calls asynCommon:report for each port being reported. + * - createAsynUser + - Creates an asynUser. The caller specifies two callbacks, process and timeout. These + callback are only called as a result of a queueRequest. The timeout callback is + optional. errorMessageSize characters are allocated for errorMessage. The amount + of storage can not be changed. This method doesn't return if it is unable to allocate + the storage. + * - duplicateAsynUser + - Creates an asynUser by calling createAsynUser. It then initializes the new asynUser + as follows: The fields timeout, userPvt, userData, and drvUser are initialized with + values taken from pasynUser. Its connectDevice state is the same as that for pasynUser. + * - freeAsynUser + - Free an asynUser. The user must free an asynUser only via this call. If the asynUser + is connected to a port, asynManager:disconnect is called. If the disconnect fails, + this call will also fail. The storage for the asynUser is saved on a free list and + will be reused in later calls to createAsynUser or duplicateAsynUser. Thus continually + calling createAsynUser (or duplicateAsynUser) and freeAsynUser is efficient. + * - memMalloc / memFree + - Allocate/Free memory. memMalloc/memFree maintain a set of freelists of different + sizes. Thus any application that needs storage for a short time can use memMalloc/memFree + to allocate and free the storage without causing memory fragmentation. The size + passed to memFree MUST be the same as the value specified in the call to memMalloc. + * - isMultiDevice + - Answers the question "Does the port support multiple devices?" This method can be + called before calling connectDevice. + * - connectDevice + - Connect the asynUser structure to a device specified by portName, addr. The port + Name is the same as that specified in a call to registerPort. The call will fail + if the asynUser is already connected to a device. If the port does not support multiple + devices, than addr is ignored. connectDevice only connects the asynUser to the port + driver for the portName,addr. The port driver may or may not be connected to the + actual device. Thus, connectDevice and asynCommon:connect are completely different. + + See the Theory of Operation section for a description of the difference between + single and multi-device port drivers. + * - disconnect + - Disconnect the asynUser from the port,addr to which it is connected via a previous + call to connectDevice. The call will fail if the asynUser is queued or locked, or + has a callback registered via exceptionCallbackAdd. Note that asynManager:disconnect + and asynCommon:disconnect are completely different. + * - exceptionCallbackAdd + - Callback will be called whenever one of the exceptions defined by asynException + occurs. The callback can call isConnected, isEnabled, or isAutoConnect to find the + connection state. asynTrace provides methods to find out the current trace settings. + * - exceptionCallbackRemove + - Callback is removed. This must be called before disconnect. + * - findInterface + - Find a driver interface. If interposeInterfaceOK is true, then findInterface returns + the last interface registered or interposed. Otherwise, the interface registered + by registerPort is returned. It returns 0 if the interfaceType is not supported. + + The user needs the address of the driver's interface and of pdrvPvt so that calls + can be made to the driver. For example + :: + + asynInterface *pasynInterface; + asynOctet *pasynOctet; + void *pasynOctetPvt; + ... + pasynInterface = pasynManager->findInterface( + pasynUser,asynOctetType,1); + if(!pasynInterface) { /*error do something*/} + pasynOctet = (asynOctet *)pasynInterface->pinterface; + pasynOctetPvt = pasynInterface->pdrvPvt; + ... + /* The following call must be made from a callback */ + pasynOctet->read(pasynOctetPvt,pasynUser,... + + * - queueRequest + - When registerPort is called, the caller must specify if it can block, i.e. attribute + bit ASYN_CANBLOCK is set or cleared. If the port has been registered with ASYN_CANBLOCK + true then the request is put on a queue for the thread associated with the queue. + If the port has been registered with ASYN_CANBLOCK false then queueRequest locks + the port and calls the process callback. In either case the process callback specified + in the call to createAsynUser is called. + + If the asynUser is already on a queue, asynError is returned. The timeout starts + when the request is queued. A value less than or equal to 0.0 means no timeout. + The request is removed from the queue before the callback is called. Callbacks are + allowed to make requests to asynManager such as queueRequest, blockProcessCallback, + etc. It is even permissible to call freeAsynUser from a callback but the request + will be delayed until after the callback completes. + + The priority asynQueuePriorityConnect must be used for asynCommon:connect and asynCommon:disconnect + calls, and must NOT be used for any other calls. + + If a timeout callback was not passed to createAsynUser and a queueRequest with a + non-zero timeout is requested, the request fails. + + Attempts to queue a request other than a connection request to a disconnected port + will fail unless the reason is ASYN_REASON_QUEUE_EVEN_IF_NOT_CONNECTED. + * - cancelRequest + - If a asynUser is queued, remove it from the queue. If either the process or timeout + callback is active when cancelRequest is called than cancelRequest will not return + until the callback completes. + * - blockProcessCallback / unblockProcessCallback + - blockProcessCallback is a request to prevent acccess to a device or port by other + asynUsers between queueRequests. blockProcessCallback can be called from a processCallback + or when the asynUser has no request queued. When called from processCallback blocking + starts immediately, otherwise blocking starts the next time processCallback is called. + Blocking means that no other asynUser's processCallback will be called until unblockProcessCallback + is called. Note the following restrictions for blockProcessCallback: + + - blockProcessCallback only works with drivers that can block and an error is returned + if it is called for non-blocking drivers. + - queueRequests that specify a priority of asynQueuePriorityConnect are not blocked. + + It is permissible to simultaneously block allDevices and also the device to which + the asynUser is connected. + * - lockPort / unlockPort + - Lock access to a port driver. This is used by code that is willing to block while + making calls to a port driver. The code can call lockPort, make an arbitrary number + of calls to the port driver, and than call unlockPort. Other code that calls queueRequest + and/or lockPort will be delayed between the calls to lockPort and unlockPort. + * - queueLockPort / queueUnlockPort + - Lock access to a port driver. This is used by code that is willing to block while + making calls to a port driver. The code can call queueLockPort, make an arbitrary + number of calls to the port driver, and than call queueUnlockPort. Other code that + calls queueRequest and/or lockPort will be delayed between the calls to queueLockPort + and queueUnlockPort. The difference between lockPort and queueLockPort is that queueLockPort + queues a request to lock the port, using the same queues as queueRequest. This means + that a thread that repeatedly calls queueLockPort without sleeping between calls + will still allow other threads to access the port. This is not true with lockPort, + which will take a mutex as soon as the port is free, and can prevent other threads + from accessing the port at all. + * - setQueueLockPortTimeout + - Sets the timeout passed to queueRequest() in queueLockPort(). The default value + of 2.0 seconds is set when the port is created. This function can be used to change + that value. Note that if the pasynUser->timeout value passed to queueLockPort + is larger than the current value then this larger timeout value is used. + * - canBlock + - yesNo is set to (0,1), i.e. (false,true) if calls to the low level driver can block. + The value is determined by the attributes passed to registerPort. + * - getAddr + - \*addr is set equal to the address which the user specified in the call to connectDevice + or -1 if the port does not support multiple devices. + + See the Theory of Operation section for a description of the difference between + single and multi-device port drivers. + * - getPortName + - \*pportName is set equal to the name of the port to which the user is connected. + * - registerPort + - This method is called by drivers. A call is made for each port instance. Attributes + is a set of bits. Currently two bits are defined: ASYN_MULTIDEVICE and ASYN_CANBLOCK. + The driver must specify these properly. autoConnect, which is (0,1) for (no,yes), + provides the initial value for the port and all devices connected to the port. priority + and stacksize are only relevant if ASYN_CANBLOCK=1, in which case asynManager uses + these values when it creates the port thread with epicsThreadCreate(). If priority + is 0, then the default value epicsThreadPriorityMedium will be assigned. If stackSize + is 0, the default value of epicsThreadGetStackSize(epicsThreadStackMedium) will + be assigned. The portName argument specifies the name by which the upper levels + of the asyn code will refer to this communication interface instance. The registerPort + method makes an internal copy of the string to which the name argument points. + * - registerInterface + - This is called by port drivers for each supported interface. This method *does + not* make a copy of the asynInterface to which the pasynInterface argument + points. Callers must store the asynInteface in a location which is retained for + the lifetime of the port. This is commonly done by placing the asynInterface structure + in the 'driver private' structure. + * - exceptionConnect + - This method must be called by the driver when and only when it connects to a port + or device. + * - exceptionDisconnect + - This method must be called by the driver when and only when it disconnects from + a port or device. + * - interposeInterface + - This is called by a software layer between client code and the port driver. For + example, if a device echos writes then a software module that issues a read after + each write could be created and call interposeInterface for interface asynOctet. + + Multiple interposeInterface calls for a port/addr/interface can be issued. \*ppPrev + is set to the address of the previous asynInterface. Thus the software module that + last called interposeInterface is called by user code. It in turn can call the software + module that was the second to last to call interposeInterface. This continues until + the actual port driver is called. + + interposeInterface can also be called with an asynInterface that has not been previously + registered or replaced. In this case \*ppPrev will be null. Thus, new interfaces + that are unknown to the low level driver can be implemented. + * - enable + - If enable is set yes, then queueRequests are not dequeued unless their queue timeout + occurs. + * - autoConnect + - If autoConnect is true and the port or device is not connected when a user callback + is scheduled to be called, asynManager calls pasynCommon->connect. See the discussion + of Flow of Control below for details. + * - isConnected + - \*yesNo is set to (0,1) if the port or device (is not, is) connected. + * - isEnabled + - \*yesNo is set to (0,1) if the port or device (is not, is) enabled. + * - isAutoConnect + - \*yesNo is set to (0,1) if the portThread (will not, will) autoConnect for the port + or device. + * - setAutoConnectTimeout + - Changes the timeout when waiting for the initial connection callback from port drivers. + This callback occurs in response to asynManager queueing a connection request, which + happens when the port driver registers its asynCommon interface. The default timeout + is 0.5 seconds. + * - waitConnect + - Wait for up to timeout seconds for the port/device to connect. + * - registerInterruptSource + - If a low level driver supports interrupts it must call this for each interface that + supports interrupts. pasynPvt must be the address of a void * that will be given + a value by registerInterruptSource. This argument is passed interruptStart and interruptEnd. + * - getInterruptPvt + - Any code that wants to call createInterruptNode but does not know the adresss of + pasynPvt can find it via this method. The caller must be connected to a device, + i.e. must have called connectDevice. If the caller is not connected, getInterruptPvt + returns asynError. + * - createInterruptNode / freeInterruptNode + - These methods are the only way a user can allocate and free an interruptNode. pasynPvt + is the value obtained from getInterruptPvt. createInterruptNode/freeInterruptNode + are separate methods rather than being done automatically by addInterruptUser/removeInterruptUser + so that addInterruptUser/removeInterruptUser can be efficient. + * - addInterruptUser / removeInterruptUser + - Code that implements registerInterruptUser/cancelInterruptUser must call addInterruptUser/removeInterruptUser + to add and remove users from the list or else calls to interruptStart/interruptEnd + will not work. This is an efficient operation so that a user can repeatedly call + registerInterruptUser / cancelInterruptUser. If either of these is called while a + interrupt is being processed, i.e. between calls to interruptStart/interruptEnd, + the call will block until interruptEnd is called. The process callback for the asynUser + specified in the call to addInterruptUser must not call removeInterruptUser or it + will block forever. + * - interruptStart / interruptEnd + - The code that implements interrupts is interface dependent. The only service asynManager + provides is a thread-safe implemention of the user list. When the code wants to + call the callback specified in the calls to registerInterruptUser, it calls interruptStart + to obtain the list of callbacks. When it is done it calls interruptEnd. If any requests + are made to addInterruptUser/removeInterruptUser between the calls to interruptStart + and interruptEnd, asynManager delays the requests until interruptEnd is called. + * - registerTimeStampSource + - Registers a user-defined time stamp callback function. + * - unregisterTimeStampSource + - Unregisters any user-defined timestamp callback function and reverts to the default + timestamp source function in asynManager, which simply calls epicsTimeGetCurrent(). + * - updateTimeStamp + - Set the current time stamp for this port by calling either the default timestamp + source, or a user-defined timestamp source that was registered with registerTimeStampSource. + * - getTimeStamp + - Get the current time stamp for this port that was returned by the most recent call + to updateTimeStamp. + * - setTimeStamp + - Set the current time stamp for this port directly from the timestamp value passed + to this function. + * - strStatus + - Returns a descriptive string corresponding to the asynStatus value. + +asynCommon +~~~~~~~~~~ +asynCommon describes the methods that must be implemented by drivers. +:: + + /* Device Interface supported by ALL asyn drivers*/ + #define asynCommonType "asynCommon" + typedef struct asynCommon { + void (*report)(void *drvPvt,FILE *fp,int details); + /*following are to connect/disconnect to/from hardware*/ + asynStatus (*connect)(void *drvPvt,asynUser *pasynUser); + asynStatus (*disconnect)(void *drvPvt,asynUser *pasynUser); + }asynCommon; + +.. list-table:: asynCommon + :widths: 20 80 + + * - report + - Generates a report about the hardware device. This is the only asynCommon method + that does not have to be called by the queueRequest callback or between calls to + lockPort/unlockPort. + * - connect + - Connect to the hardware device or communication path. The queueRequest must specify + priority asynQueuePriorityConnect. + * - disconnect + - Disconnect from the hardware device or communication path. The queueRequest must + specify priority asynQueuePriorityConnect. + +asynCommonSyncIO +~~~~~~~~~~~~~~~~ +asynCommonSyncIO provides a convenient interface for software that needs to perform +"synchronous" operations to an asyn device, i.e. that blocks while waiting for the +port to be available and for the operation to complete. The code does not need to +handle callbacks or understand the details of the asynManager and asynCommon interfaces. +:: + + typedef struct asynCommonSyncIO { + asynStatus (*connect)(const char *port, int addr, + asynUser **ppasynUser, const char *drvInfo); + asynStatus (*disconnect)(asynUser *pasynUser); + asynStatus (*connectDevice)(asynUser *pasynUser); + asynStatus (*disconnectDevice)(asynUser *pasynUser); + asynStatus (*report)(asynUser *pasynUser, FILE *fd, int details); + } asynCommonSyncIO; + epicsShareExtern asynCommonSyncIO *pasynCommonSyncIO; + +Note that there is a potential for confusion in the connect* and disconnect* function +names of this interface. For consistency with the other SyncIO interfaces, connect +calls pasynManager->connectDevice, disconnect calls pasynManager->disconnect, +connectDevice calls asynCommon->connect, and disconnectDevice calls asynCommon->disconnect. + +asynDrvUser +~~~~~~~~~~~ +asynDrvUser provides methods that allow an asynUser to communicate user specific +information to/from a port driver +:: + + #define asynDrvUserType "asynDrvUser" + typedef struct asynDrvUser { + /*The following do not have to be called via queueRequest callback*/ + asynStatus (*create)(void *drvPvt,asynUser *pasynUser, + const char *drvInfo, const char **pptypeName,size_t *psize); + asynStatus (*getType)(void *drvPvt,asynUser *pasynUser, + const char **pptypeName,size_t *psize); + asynStatus (*destroy)(void *drvPvt,asynUser *pasynUser); + }asynDrvUser; + +.. list-table:: asynDrvUser + :widths: 20 80 + + * - create + - The user, i.e. device support calls create. The driver can create any resources + it needs. It can use pasynUser->drvUser to provide access to the resources. If + the asynUser and the driver both know how to access the resources they must agree + about the name for the resource and a size. If pptypeName is not null the driver + can give a value to \*pptypeName. If psize is not null the driver can give a value + to \*psize. Unless asynUser receives a typeName and size that it recognizes it must + not access asynUser.drvUser. + * - getType + - If other code, e.g. an interposeInterface wants to access asynUser.drvUser it must + call this and verify that typeName and size are what it expects. + * - destroy + - Destroy the resources created by create and set asynUser.drvUser null. + +asynLockPortNotify +~~~~~~~~~~~~~~~~~~ +This is provided for port drivers that are an asynUser of another port driver. For +example a serial bus driver can be implemented by connecting to a standard serial +port to perform the actual I/O. When the serial bus port is locked, either by the +requester calling lockPort or because a queueRequest was dequeued, then the serial +bus driver needs to lock the associated serial port. + +The serial bus driver registers interface asynLockPortNotify. Whenever the serial +bus port is locked, asynManager calls pasynLockPortNotify.lock. The serial bus driver +calls asynManager.lockPort for the serial port to which it is connected. Similarly +for unlockPort. Thus while the serial bus port is locked, the serial bus is also +locked. + +asynLockPortNotify is used only by asynManager itself. It is not put in the list +of interfaces for the port. + +asynLockPortNotify is +:: + + #define asynLockPortNotifyType "asynLockPortNotify" + typedef struct asynLockPortNotify { + asynStatus (*lock)(void *drvPvt,asynUser *pasynUser); + asynStatus (*unlock)(void *drvPvt,asynUser *pasynUser); + } asynLockPortNotify; + +.. list-table:: asynLockPortNotify + :widths: 20 80 + + * - lock + - Called when asynManager.lockPort is called. The driver normally calls asynManager.lockPort + for the port to which it is connected. + * - unlock + - Called when asynManager.unlockPort is called. The driver normally calls asynManager.unlockPort + for the port to which it is connected. + +asynOption +~~~~~~~~~~ +asynOption provides a generic way of setting driver specific options. For example +the serial port driver uses this to specify baud rate, stop bits, etc. +:: + + #define asynOptionType "asynOption" + /*The following are generic methods to set/get device options*/ + typedef struct asynOption { + asynStatus (*setOption)(void *drvPvt, asynUser *pasynUser, + const char *key, const char *val); + asynStatus (*getOption)(void *drvPvt, asynUser *pasynUser, + const char *key, char *val, int sizeval); + }asynOption; + +.. list-table:: asynOption + :widths: 20 80 + + * - setOption + - Set value associated with key. + * - getOption + - Get value associated with key. + +asynTrace +~~~~~~~~~ +asynDriver provides a trace facility with the following attributes: + +- Tracing is turned on/off for individual devices, i.e. a portName, addr. +- Trace has a global trace mask for asynUsers not connected to a port or port, addr. +- The output is sent to a file or to stdout or to errlog. +- A mask determines the type of information that can be displayed. The various choices + can be ORed together. The default value of this mask when a port is created is ASYN_TRACE_ERROR. + + - ASYN_TRACE_ERROR Run time errors are reported, e.g. timeouts. + - ASYN_TRACEIO_DEVICE Device support reports I/O activity. + - ASYN_TRACEIO_FILTER Any layer between device support and the low level driver + reports any filtering it does on I/O. + - ASYN_TRACEIO_DRIVER Low level driver reports I/O activity. + - ASYN_TRACE_FLOW Report logic flow. Device support should report all queue requests, + callbacks entered, and all calls to drivers. Layers between device support and low + level drivers should report all calls they make to lower level drivers. Low level + drivers report calls they make to other support. + - ASYN_TRACE_WARNING Report warnings, i.e. conditions that are between ASYN_TRACE_ERROR + and ASYN_TRACE_FLOW. +- Another mask determines how message buffers are printed. The various choices can + be ORed together. The default value of this mask when a port is created is ASYN_TRACEIO_NODATA. + + - ASYN_TRACEIO_NODATA Don't print any data from the message buffers. + - ASYN_TRACEIO_ASCII Print with a "%s" style format. + - ASYN_TRACEIO_ESCAPE Call epicsStrPrintEscaped. + - ASYN_TRACEIO_HEX Print each byte with " %2.2x". +- Another mask determines what information is printed at the beginning of each message. + The various choices can be ORed together. The default value of this mask when a + port is created is ASYN_TRACEINFO_TIME. + + - ASYN_TRACEINFO_TIME prints 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 or asynPrintIO statement occurs. + - ASYN_TRACEINFO_THREAD prints the thread name, thread ID and thread priority, i.e. + [epicsThreadGetNameSelf(), epicsThreadGetIdSelf(), epicsThreadGetPrioritySelf()]. + + +In order for the trace facility to perform properly; device support and all drivers +must use the trace facility. Device and driver support can directly call the asynTrace +methods. The asynPrint and asynPrintIO macros are provided so that it is easier +for device/driver support. Support can have calls like +:: + + asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s Calling queueRequest\n", someName); + +The asynPrintIO call is designed for device support or drivers that issue read or +write requests. They make calls like +:: + + asynPrintIO(pasynUser,ASYN_TRACEIO_DRIVER,data,nchars,"%s nchars %d",someName,nchars); + +The asynTrace methods are implemented by asynManager. These methods can be used +by any code that has created an asynUser and is connected to a device. All methods +can be called by any thread. That is, an application thread and/or a portThread. +If a thread performs all I/O via calls to print or printIO, then it does not have +to call lock or unlock. If it does want to do its own I/O, it must lock before any +I/O and unlock after. For example: +:: + + pasynTrace->lock(pasynUser); + fd = pasynTrace->getTraceFile(pasynUser); + /*perform I/O to fd */ + pasynTrace->unlock(pasynUser); + +If the asynUser is not connected to a port, i.e. pasynManager->connectDevice +has not been called, then a "global" device is assumed. This is useful when asynPrint +is called before connectDevice. + +This is the asynTrace interface: +:: + + /*asynTrace is implemented by asynManager*/ + /*All asynTrace methods can be called from any thread*/ + /* traceMask definitions*/ + #define ASYN_TRACE_ERROR 0x0001 + #define ASYN_TRACEIO_DEVICE 0x0002 + #define ASYN_TRACEIO_FILTER 0x0004 + #define ASYN_TRACEIO_DRIVER 0x0008 + #define ASYN_TRACE_FLOW 0x0010 + #define ASYN_TRACE_WARNING 0x0020 + + /* traceIO mask definitions*/ + #define ASYN_TRACEIO_NODATA 0x0000 + #define ASYN_TRACEIO_ASCII 0x0001 + #define ASYN_TRACEIO_ESCAPE 0x0002 + #define ASYN_TRACEIO_HEX 0x0004 + + /* traceInfo mask definitions*/ + #define ASYN_TRACEINFO_TIME 0x0001 + #define ASYN_TRACEINFO_PORT 0x0002 + #define ASYN_TRACEINFO_SOURCE 0x0004 + #define ASYN_TRACEINFO_THREAD 0x0008 + + /* asynPrint and asynPrintIO are macros that act like + int asynPrintSource(asynUser *pasynUser,int reason, __FILE__, __LINE__, const char *format, ... ); + int asynPrintIOSource(asynUser *pasynUser,int reason, + const char *buffer, size_t len, __FILE__, __LINE__, const char *format, ... ); + */ + typedef struct asynTrace { + /* lock/unlock are only necessary if caller performs I/O other than */ + /* by calling asynTrace methods */ + asynStatus (*lock)(asynUser *pasynUser); + asynStatus (*unlock)(asynUser *pasynUser); + asynStatus (*setTraceMask)(asynUser *pasynUser,int mask); + int (*getTraceMask)(asynUser *pasynUser); + asynStatus (*setTraceIOMask)(asynUser *pasynUser,int mask); + int (*getTraceIOMask)(asynUser *pasynUser); + asynStatus (*setTraceInfoMask)(asynUser *pasynUser,int mask); + int (*getTraceInfoMask)(asynUser *pasynUser); + asynStatus (*setTraceFile)(asynUser *pasynUser,FILE *fp); + FILE *(*getTraceFile)(asynUser *pasynUser); + asynStatus (*setTraceIOTruncateSize)(asynUser *pasynUser,size_t size); + size_t (*getTraceIOTruncateSize)(asynUser *pasynUser); + #if defined(__GNUC__) && (__GNUC__ < 3) + /* GCC 2.95 does not allow EPICS_PRINTF_STYLE on function pointers */ + int (*print)(asynUser *pasynUser,int reason, const char *pformat, ...); + int (*printSource)(asynUser *pasynUser,int reason, const char *fileName, int line, const char *pformat, ...); + int (*vprint)(asynUser *pasynUser,int reason, const char *pformat, va_list pvar); + int (*vprintSource)(asynUser *pasynUser,int reason, const char *file, int line, const char *pformat, va_list pvar); + int (*printIO)(asynUser *pasynUser,int reason, + const char *buffer, size_t len,const char *pformat, ...); + int (*printIOSource)(asynUser *pasynUser,int reason, + const char *buffer, size_t len,const char *file, int line, const char *pformat, ...); + int (*vprintIO)(asynUser *pasynUser,int reason, + const char *buffer, size_t len,const char *pformat, va_list pvar); + int (*vprintIOSource)(asynUser *pasynUser,int reason, + const char *buffer, size_t len,const char *file, int line, const char *pformat, va_list pvar); + #else + int (*print)(asynUser *pasynUser,int reason, const char *pformat, ...) EPICS_PRINTF_STYLE(3,4); + int (*printSource)(asynUser *pasynUser,int reason, const char *fileName, int line, const char *pformat, ...) EPICS_PRINTF_STYLE(5,6); + int (*vprint)(asynUser *pasynUser,int reason, const char *pformat, va_list pvar) EPICS_PRINTF_STYLE(3,0); + int (*vprintSource)(asynUser *pasynUser,int reason, const char *file, int line, const char *pformat, va_list pvar) EPICS_PRINTF_STYLE(5,0); + int (*printIO)(asynUser *pasynUser,int reason, + const char *buffer, size_t len,const char *pformat, ...) EPICS_PRINTF_STYLE(5,6); + int (*printIOSource)(asynUser *pasynUser,int reason, + const char *buffer, size_t len,const char *file, int line, const char *pformat, ...) EPICS_PRINTF_STYLE(7,8); + int (*vprintIO)(asynUser *pasynUser,int reason, + const char *buffer, size_t len,const char *pformat, va_list pvar) EPICS_PRINTF_STYLE(5,0); + int (*vprintIOSource)(asynUser *pasynUser,int reason, + 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; + +.. list-table:: asynTrace + :widths: 20 80 + + * - lock/unlock + - These are only needed for code that call asynTrace.print or asynTrace.printIO instead + of asynPrint and asynPrintIO. + + print, and printIO both lock while performing their operations. The get methods + do not lock (except for getTraceFile) and they are safe. Except for setTraceFile + the set methods do not block, since worst that can happen is that the user gets + a little more or a little less output. + * - setTraceMask + - Set the trace mask. Normally set by the user requesting it via a shell command or + the devTrace device support. Setting the trace mask for a port also sets the trace + mask for all devices connected to that port + * - getTraceMask + - Get the trace mask. Device support that wants to issue trace messages calls this + to see what trace options have been requested. + * - setTraceIOMask + - Set the traceIO mask. Normally set by the user requesting it via a shell command + or the devTrace device support. Setting the traceIO mask for a port also sets the + traceIO mask for all devices connected to that port + * - getTraceIOMask + - Get the traceIO mask. Support that wants to issue its own IO messages instead of + calling asynPrintIO should call this and honor the mask settings. Most code will + not need it. + * - setTraceInfoMask + - Set the traceInfo mask. Normally set by the user requesting it via a shell command + or the devTrace device support. Setting the traceInfo mask for a port also sets + the traceInfo mask for all devices connected to that port + * - getTraceInfoMask + - Get the traceInfo mask. Support that wants to issue its own IO messages instead + of calling asynPrint should call this and honor the mask settings. Most code will + not need it. + * - setTraceFile + - Set the stream to use for output. A NULL argument means use errlog. Normally set + by the user requesting it via a shell command or by the devTrace device support. + If the current output stream is none of (NULL, stdout, stderr) then the current + output stream is closed before the new stream is used. + * - getTraceFile + - Get the file descriptor to use for output. Device support that wants to issue its + own IO messages instead of calling asynPrintIO should call this and honor the mask + settings. In this case, lock must have been called first. Most code will not need + it. If the return value is 0, then ouput should be directed to errlog. + * - setTraceIOTruncateSize + - Determines how much data is printed by printIO. In all cases it determines how many + bytes of the buffer are displayed. The actual number of characters printed depends + on the traceIO mask. For example ASYN_TRACEIO_HEX results in 3 characters being + printed for each byte. Normally set by the user requesting it via a shell command + or the devTrace device support. + * - getTraceIOTruncateSize + - Get the current truncate size. Called by asynPrintIO. Code that does its own I/O + should also support the traceIO mask. + * - print + - If reason ORed with the current traceMask is not zero, then the message is printed. + This method is provided for backwards compatibility. The asynPrint macro now calls + printSource(). + * - printSource + - If reason ORed with the current traceMask is not zero, then the message is printed. + Most code should call asynPrint instead of calling this method. This method is the + same as print() but with the additional **file** and **line** arguments. + * - vprint + - This is the same as print, but using a va_list as its final argument. + * - vprintSource + - This is the same as printSource, but using a va_list as its final argument. + * - printIO + - If reason ORed with the current traceMask is not zero then the message is printed. + If len is >0, then the buffer is printed using the traceIO mask and getTraceIOTruncateSize. + This method is provided for backwards compatibility. The asynPrintIO macro now calls + printIOSource(). + * - printIOSource + - If reason ORed with the current traceMask is not zero then the message is printed. + If len is >0, then the buffer is printed using the traceIO mask and getTraceIOTruncateSize. + Most code should call asynPrintIO instead of calling this method. This method is + the same as printIO() but with the additional **file** and **line** arguments. + * - vprintIO + - This is the same as printIO, but using a va_list as its final argument. + * - vprintIOSource + - This is the same as printIOSource, but using a va_list as its final argument. + +Standard Message Based Interfaces +--------------------------------- + +These are interfaces for communicating with message based devices, where message +based means that the device communicates via octet strings, i.e. arrays of 8 bit +bytes. Three interfaces are provided: asynOctet, asynOctetBase, and asynOctetSyncIO. +asynOctet is generic message based interface. asynOctetBase is an interface used +by port drivers that implement asynOctet. It's primary purpose is to help with interrupt +support. asynOctetSyncIO provides a synchronous inteface to asynOctet and can be +used by code that is willing to block. + +asynOctet +~~~~~~~~~ + +asynOctet describes the methods implemented by drivers that use octet strings for +sending commands and receiving responses from a device. + +NOTE: The name octet is used instead of ASCII because it implies that communication +is done via 8-bit bytes. +:: + + #define ASYN_EOM_CNT 0x0001 /*Request count reached*/ + #define ASYN_EOM_EOS 0x0002 /*End of String detected*/ + #define ASYN_EOM_END 0x0004 /*End indicator detected*/ + + typedef void (*interruptCallbackOctet)(void *userPvt, asynUser *pasynUser, + char *data,size_t numchars, int eomReason); + + typedef struct asynOctetInterrupt { + asynUser *pasynUser; + int addr; + interruptCallbackOctet callback; + void *userPvt; + }asynOctetInterrupt; + + + #define asynOctetType "asynOctet" + typedef struct asynOctet{ + asynStatus (*write)(void *drvPvt,asynUser *pasynUser, + const char *data,size_t numchars,size_t *nbytesTransfered); + asynStatus (*read)(void *drvPvt,asynUser *pasynUser, + char *data,size_t maxchars,size_t *nbytesTransfered, + int *eomReason); + asynStatus (*flush)(void *drvPvt,asynUser *pasynUser); + asynStatus (*registerInterruptUser)(void *drvPvt,asynUser *pasynUser, + interruptCallbackOctet callback, void *userPvt, + void **registrarPvt); + asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser, + void *registrarPvt); + asynStatus (*setInputEos)(void *drvPvt,asynUser *pasynUser, + const char *eos,int eoslen); + asynStatus (*getInputEos)(void *drvPvt,asynUser *pasynUser, + char *eos, int eossize, int *eoslen); + asynStatus (*setOutputEos)(void *drvPvt,asynUser *pasynUser, + const char *eos,int eoslen); + asynStatus (*getOutputEos)(void *drvPvt,asynUser *pasynUser, + char *eos, int eossize, int *eoslen); + }asynOctet; + /* asynOctetBase does the following: + calls registerInterface for asynOctet. + Implements registerInterruptUser and cancelInterruptUser + Provides default implementations of all methods. + registerInterruptUser and cancelInterruptUser can be called + directly rather than via queueRequest. + */ + + #define asynOctetBaseType "asynOctetBase" + typedef struct asynOctetBase { + asynStatus (*initialize)(const char *portName, + asynDriverasynInterface *pasynOctetInterface, + int processEosIn,int processEosOut,int interruptProcess); + void (*callInterruptUsers)(asynUser *pasynUser,void *pasynPvt, + char *data,size_t *nbytesTransfered,int *eomReason); + } asynOctetBase; + epicsShareExtern asynOctetBase *pasynOctetBase; + + +.. list-table:: asynOctet + :widths: 20 80 + + * - write + - Send a message to the device. \*nbytesTransfered is the number of 8-bit bytes sent + to the device. Interpose or driver code may add end of string terminators to the + message but the extra characters are not included in \*nbytesTransfered. + * - read + - Read a message from the device. \*nbytesTransfered is the number of 8-bit bytes read + from the device. If read returns asynSuccess than eomReason ( some combination of + ASYN_EOM_CNT, ASYN_EOM_EOS, and ASYN_EOM_END)tells why the read completed. Interpose + or driver code may strip end of string terminators from the message. If it does + the first eos character will be replaced by null and the eos characters will not + be included in nbytesTransfered. + * - flush + - Flush the input buffer. + * - registerInterruptUser + - Register a user that will be called whenever a new message is received. NOTE: The + callback must not block and must not call registerInterruptUser or cancelInterruptUser. + * - cancelInterruptUser + - Cancel a registered user. + * - setInputEos + - Set End Of String for input. For example "\\n". Note that gpib drivers usually accept + at most a one character terminator. + * - getInputEos + - Get the current End of String. + * - setOutputEos + - Set End Of String for output. + * - getOutputEos + - Get the current End of String. + +asynOctetBase is an interface and implementation for drivers that implement interface +asynOctet. asynOctetBase implements registerInterruptUser and cancelInterruptUser. + +For single device support, it can optionally implement interrupt support. A driver +that implements interrupts must call registerInterruptSource. If it asks asynOctetBase +to handle interrupts it calls asynOctetBase:callInterruptUsers when it has new data. + +For single device support asynOctetBase can optionally call asynInterposeEosConfig +to handle end of string processing for input and/or output. + +Any null method in the interface passed to initialize are replaced by a method supplied +by asynOctetBase. + +For an example of how to use asynOctetBase look at ``asyn/testApp/src/echoDriver.c`` + +.. list-table:: asynOctetBase + :widths: 20 80 + + * - initialize + - After a driver calls registerPort it can call + :: + + pasynOctetBase->initialize(... + + Any null methods in the asynInterface are replaced by default implementations. If + the port is not multi-device and either processEosIn or processEosOut is specified, + asynInterposeEosConfig is called. If the port is not multi-device and interruptProcess + is specified, then whenever read is called, asynBase calls all the registered interrupt + users. asynOctetBase can not implement processEosIn, processEosOut, and interruptProcess + if the port is a multi-device port. Since this method is called only during initialization + it can be called directly rather than via queueRequest. + * - callInterruptUsers + - Calls the callbacks registered via registerInterruptUser. + +asynOctetSyncIO +~~~~~~~~~~~~~~~ + +asynOctetSyncIO provides a convenient interface for software that needs to perform +"synchronous" I/O to an asyn device, i.e. that starts an I/O operation and then +blocks while waiting for the response. The code does not need to handle callbacks +or understand the details of the asynManager and asynOctet interfaces. Examples +include motor drivers running in their own threads, SNL programs, and the shell +commands described later in this document. +:: + + typedef struct asynOctetSyncIO { + asynStatus (*connect)(const char *port, int addr, + asynUser **ppasynUser, const char *drvInfo); + asynStatus (*disconnect)(asynUser *pasynUser); + asynStatus (*write)(asynUser *pasynUser, + char const *buffer, size_t buffer_len, + double timeout,size_t *nbytesTransfered); + asynStatus (*read)(asynUser *pasynUser, char *buffer, size_t buffer_len, + double timeout, size_t *nbytesTransfered,int *eomReason); + asynStatus (*writeRead)(asynUser *pasynUser, + const char *write_buffer, size_t write_buffer_len, + char *read_buffer, size_t read_buffer_len, + double timeout, + size_t *nbytesOut, size_t *nbytesIn, int *eomReason); + asynStatus (*flush)(asynUser *pasynUser); + asynStatus (*setInputEos)(asynUser *pasynUser, + const char *eos,int eoslen); + asynStatus (*getInputEos)(asynUser *pasynUser, + char *eos, int eossize, int *eoslen); + asynStatus (*setOutputEos)(asynUser *pasynUser, + const char *eos,int eoslen); + asynStatus (*getOutputEos)(asynUser *pasynUser, + char *eos, int eossize, int *eoslen); + asynStatus (*writeOnce)(const char *port, int addr, + char const *buffer, size_t buffer_len, double timeout, + size_t *nbytesTransfered, const char *drvInfo); + asynStatus (*readOnce)(const char *port, int addr, + char *buffer, size_t buffer_len, double timeout, + size_t *nbytesTransfered,int *eomReason, const char *drvInfo); + asynStatus (*writeReadOnce)(const char *port, int addr, + const char *write_buffer, size_t write_buffer_len, + char *read_buffer, size_t read_buffer_len, + double timeout, + size_t *nbytesOut, size_t *nbytesIn, int *eomReason, + const char *drvInfo); + asynStatus (*flushOnce)(const char *port, int addr,const char *drvInfo); + asynStatus (*setInputEosOnce)(const char *port, int addr, + const char *eos,int eoslen,const char *drvInfo); + asynStatus (*getInputEosOnce)(const char *port, int addr, + char *eos, int eossize, int *eoslen,const char *drvInfo); + asynStatus (*setOutputEosOnce)(const char *port, int addr, + const char *eos,int eoslen,const char *drvInfo); + asynStatus (*getOutputEosOnce)(const char *port, int addr, + char *eos, int eossize, int *eoslen,const char *drvInfo); + } asynOctetSyncIO; + epicsShareExtern asynOctetSyncIO *pasynOctetSyncIO; + +.. list-table:: asynOctetSyncIO + :widths: 20 80 + + * - connect + - Connects to an asyn port and address, returns a pointer to an asynUser structure. + * - disconnect + - Disconnect. This frees all resources allocated by connect. + * - write + - Calls asynOctet->write and waits for the operation to complete or time out. + * - read + - Calls asynOctet->read. Waits for the operation to complete or time out. + * - writeRead + - Calls pasynOctet->flush, pasynOctet->write, and asynOctet->read. Waits + for the operations to complete or time out. + * - flush + - Calls pasynOctet->flush + * - setInputEos + - Calls pasynOctet->setInputEos + * - getInputEos + - Calls pasynOctet->getInputEos + * - setOutputEos + - Calls pasynOctet->setOutputEos + * - getOutputEos + - Calls pasynOctet->getOutputEos + * - writeOnce + - This does a connect, write, and disconnect. + * - readOnce + - This does a connect, read, and disconnect. + * - readOnce + - This does a connect, read, and disconnect. + * - writeReadOnce + - This does a connect, writeRead, and disconnect. + +End of String Support +~~~~~~~~~~~~~~~~~~~~~ +asynOctet provides methods for handling end of string (message) processing. It does +not specify policy. Device support code, interpose layers, or low level drivers +can all handle EOS processing. An application developer must decide what policy +will be followed for individual devices. The policy will be determined by the device, +the device support, and the driver. + +Standard Register Based Interfaces +---------------------------------- +Introduction +~~~~~~~~~~~~ + +This section describes interfaces for register based devices. Support is provided +for: + +- Int32 - registers appear as 32 integers +- Int64 - registers appear as 64 integers +- UInt32Digital - registers appear a 32 bit unsigned integers and masks can be used + to address specific bits. +- Float64 - registers appear as double precision floats. +- Int8Array - Arrays of 8 bit integers. +- Int16Array - Arrays of 16 bit integers. +- Int32Array - Arrays of 32 bit integers. +- Int64Array - Arrays of 64 bit integers. +- Float32Array - Arrays of single precision floats. +- Float64Array - Arrays of double precision floats. +- Enum - Arrays of strings, integer values and integer severities. +- GenericPointer - void* pointer. + + +Note that hardware may have registers with smaller sizes, e.g. 16 bit registers. +The standard interfaces can still be used by setting the unused bits to 0. + +For all of these interfaces a default implementation and a synchronous inplementation +are provided. Let's use Int32 as an example. + +- asynInt32 - An interface with methods: read, write, getBounds, registerInterruptUser, + and cancelInterruptUser. +- asynInt32Base - An interface used by drivers that implement asynInt32. It also + has an implementation that: + + - registers the asynInt32 interface + - has default methods for read, write, and getBounds. A null method in the interface + passed to initialize is replaced by a method implemented by asynInt32Base. + - implements registerInterruptUser and cancelInterruptUser. The caller should leave + these methods null because asynInt32Base always replaces them by it's implementation. + + Drivers that implement asynInt32 normally call asynInt32Base:initialize. It implements + registerInterruptUser and cancelInterruptUser. If the driver provides interrupt + support it must: + + - Call ``pasynInt32Base->initialize`` + - Call ``pasynManager->registerInterruptSource`` + - Interact with asynManager to call the users that have registered with asynInt32Base:registerInterruptUser. + The driver calls users when there is new data available. + + ``asyn/testEpicsApp/src/int32Driver.c`` provides + an example of how to provide support for interrupts. +- asynInt32SyncIO - A synchronous interface to asynInt32 + +**addr - What does it mean for register based interfaces?** + +Low level register based drivers are normally multi-device. The meaning of addr +is: + +- Int32 - The driver supports an array of Int32 values. addr selects an array element. + For example a 16 channel ADC would support addr 0 through 15. +- Int64 - The driver supports an array of Int64 values. addr selects an array element. +- Int8Array - Each addr is an array of Int8 values. +- Int16Array - Each addr is an array of Int16 values. +- Int32Array - Each addr is an array of Int32 values. +- Int64Array - Each addr is an array of Int64 values. +- Float64 - The driver supports an array of Float64 values. addr selects an array + element. +- Float32Array - Each addr is an array of Float32 values. +- Float64Array - Each addr is an array of Float64 values. +- UInt32Digital - The driver supports an array of UInt32 values. addr selects an + array element. For example a 128 bit digital I/O module appears as an array of four + UInt32 registers. + +Example Drivers +~~~~~~~~~~~~~~~ + +Two examples of drivers that might implement and use the interfaces are: +- Analog to Digital Converter. + + An example is a 16 channel ADC. The driver implements interfaces asynCommon and + asynInt32. It uses interface asynInt32Base. It can call asynManager:interruptStart + and asynManager:interruptEnd to support interrupts. It can use pasynUser->reason + and addr to decide which callbacks to call. ``asyn/testEpicsApp/int32Driver.c`` + is a soft example of how to implement a driver that implements asynInt32 and also + asynFloat64. + +- Digital I/O module + + An example is a 64 bit combination digital input and digital output module. The + driver implements interfaces asynCommon and asynUInt32Digital. It uses interface + asynUInt32DigitalBase. It can call asynManager:interruptStart and asynManager:interruptEnd + to support interrupts. It can use reason, mask, and addr to decide which callbacks + to call. ``asyn/testEpicsApp/uint32DigitalDriver.c`` + is a soft example of a driver that implements asynUInt32Digital. + +asynIntXX (XX=32 or 64) +~~~~~~~~~~~~~~~~~~~~~~~ + +asynIntXX describes the methods implemented by drivers that use integers for communicating +with a device. +:: + + typedef void (*interruptCallbackIntXX)(void *userPvt, asynUser *pasynUser, + epicsIntXX data); + typedef struct asynIntXXInterrupt { + int addr; + asynUser *pasynUser; + interruptCallbackIntXX callback; + void *userPvt; + } asynIntXXInterrupt; + #define asynIntXXType "asynIntXX" + typedef struct asynIntXX { + asynStatus (*write)(void *drvPvt, asynUser *pasynUser, epicsIntXX value); + asynStatus (*read)(void *drvPvt, asynUser *pasynUser, epicsIntXX *value); + asynStatus (*getBounds)(void *drvPvt, asynUser *pasynUser, + epicsIntXX *low, epicsIntXX *high); + asynStatus (*registerInterruptUser)(void *drvPvt,asynUser *pasynUser, + interruptCallbackIntXX callback, void *userPvt, + void **registrarPvt); + asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser, + void *registrarPvt); + } asynIntXX; + + /* asynIntXXBase does the following: + calls registerInterface for asynIntXX. + Implements registerInterruptUser and cancelInterruptUser + Provides default implementations of all methods. + registerInterruptUser and cancelInterruptUser can be called + directly rather than via queueRequest. + */ + + #define asynIntXXBaseType "asynIntXXBase" + typedef struct asynIntXXBase { + asynStatus (*initialize)(const char *portName, + asynInterface *pintXXInterface); + } asynIntXXBase; + epicsShareExtern asynIntXXBase *pasynIntXXBase; + +.. list-table:: asynIntXX + :widths: 20 80 + + * - write + - Write an integer value to the device. + * - read + - Read an integer value from the device. + * - getBounds + - Get the bounds. For example a 16 bit ADC might set low=-32768 and high = 32767. + * - registerInterruptUser + - Registers a callback that will be called whenever new data is available. Since it + can be called directly rather than via a queueRequest this method must not block. + * - cancelInterruptUser + - Cancels the callback. Since it can be called directly rather than via a queueRequest + this method must not block. + +asynIntXXBase is an interface and associated code that is used by drivers that implement +interface asynIntXX. asynIntXXBase provides code to handle registerInterruptUser/cancelInterruptUser. +The driver must itself call the callbacks via calls to asynManager:interruptStart +and asynManager:interruptEnd. + +.. list-table:: asynIntXXBase + :widths: 20 80 + + * - initialize + - After a driver calls registerPort it can call: + :: + + pasynIntXXBase->initialize(... + + Any null methods in the asynInterface are replaced by default implementations. + +The default implementation of each method does the following: + +.. list-table:: asynIntXX + :widths: 20 80 + + * - write + - Reports an error "write is not supported" and returns asynError + * - read + - Reports an error "read is not supported" and returns asynError + * - getBounds + - Reports an error "getBounds is not supported" and returns asynError + * - registerInterruptUser + - registers an interrupt callback. + * - cancelInterruptUser + - Cancels the callback + +asynIntXXSyncIO (XX=32 or 64) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +asynIntXXSyncIO describes a synchronous interface to asynIntXX. The code that calls +it must be willing to block. +:: + + #define asynIntXXSyncIOType "asynIntXXSyncIO" + typedef struct asynIntXXSyncIO { + asynStatus (*connect)(const char *port, int addr, + asynUser **ppasynUser, const char *drvInfo); + asynStatus (*disconnect)(asynUser *pasynUser); + asynStatus (*write)(asynUser *pasynUser, epicsIntXX value,double timeout); + asynStatus (*read)(asynUser *pasynUser, epicsIntXX *pvalue,double timeout); + asynStatus (*getBounds)(asynUser *pasynUser, + epicsIntXX *plow, epicsIntXX *phigh); + asynStatus (*writeOnce)(const char *port, int addr, + epicsIntXX value,double timeout, const char *drvInfo); + asynStatus (*readOnce)(const char *port, int addr, + epicsIntXX *pvalue,double timeout, const char *drvInfo); + asynStatus (*getBoundsOnce)(const char *port, int addr, + epicsIntXX *plow, epicsIntXX *phigh,const char *drvInfo); + } asynIntXXSyncIO; + epicsShareExtern asynIntXXSyncIO *pasynIntXXSyncIO; + +.. list-table:: asynIntXXSyncIO + :widths: 20 80 + + * - connect + - Connects to a port and address, returns a pointer to an asynUser. + * - disconnect + - Disconnect. This frees all resources allocated by connect. + * - write + - Calls pasynIntXX->write and waits for the operation to complete or time out. + * - read + - Calls pasynIntXX->read and waits for the operation to complete or time out. + * - getBounds + - Calls pasynIntXX->getBounds and waits for the operation to complete or time out. + * - writeOnce + - This does a connect, write, and disconnect. + * - readOnce + - This does a connect, read, and disconnect. + * - getBoundsOnce + - This does a connect, getBounds, and disconnect. + +asynUInt32Digital +~~~~~~~~~~~~~~~~~ +asynUInt32Digital describes the methods for communicating via bits of an Int32 register. +:: + + typedef enum { + interruptOnZeroToOne, interruptOnOneToZero, interruptOnBoth + } interruptReason; + + typedef void (*interruptCallbackUInt32Digital)(void *userPvt, + asynUser *pasynUser, epicsUInt32 data); + typedef struct asynUInt32DigitalInterrupt { + epicsUInt32 mask; + int addr; + asynUser *pasynUser; + interruptCallbackUInt32Digital callback; + void *userPvt; + } asynUInt32DigitalInterrupt; + #define asynUInt32DigitalType "asynUInt32Digital" + typedef struct asynUInt32Digital { + asynStatus (*write)(void *drvPvt, asynUser *pasynUser, + epicsUInt32 value, epicsUInt32 mask); + asynStatus (*read)(void *drvPvt, asynUser *pasynUser, + epicsUInt32 *value, epicsUInt32 mask); + asynStatus (*setInterrupt)(void *drvPvt, asynUser *pasynUser, + epicsUInt32 mask, interruptReason reason); + asynStatus (*clearInterrupt)(void *drvPvt, asynUser *pasynUser, + epicsUInt32 mask); + asynStatus (*getInterrupt)(void *drvPvt, asynUser *pasynUser, + epicsUInt32 *mask, interruptReason reason); + asynStatus (*registerInterruptUser)(void *drvPvt, asynUser *pasynUser, + interruptCallbackUInt32Digital callback,void *userPvt,epicsUInt32 mask, + void **registrarPvt); + asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser, + void *registrarPvt); + } asynUInt32Digital; + + /* asynUInt32DigitalBase does the following: + calls registerInterface for asynUInt32Digital. + Implements registerInterruptUser and cancelInterruptUser + Provides default implementations of all methods. + registerInterruptUser and cancelInterruptUser can be called + directly rather than via queueRequest. + */ + + #define asynUInt32DigitalBaseType "asynUInt32DigitalBase" + typedef struct asynUInt32DigitalBase { + asynStatus (*initialize)(const char *portName, + asynInterface *pasynUInt32DigitalInterface); + } asynUInt32DigitalBase; + epicsShareExtern asynUInt32DigitalBase *pasynUInt32DigitalBase; + +.. list-table:: asynUInt32Digital + :widths: 20 80 + + * - write + - Modify the bits specified by mask with the corresponding bits in value. + * - read + - Read the bits specified by mask into value. The other bits of value will be set + to 0. + * - setInterrupt + - Set the bits specified by mask to interrupt for reason. + * - clearInterrupt + - Clear the interrupt bits specified by mask. + * - getInterrupt + - Set each bit of mask that is enabled for reason. + * - registerInterruptUser + - Register a callback that will be called whenever the driver detects a change in + any of the bits specified by mask. Since it can be called directly rather than via + a queueRequest this method must not block. + * - cancelInterruptUser + - Cancels the registered callback. Since it can be called directly rather than via + a queueRequest this method must not block. + +asynUInt32DigitalBase is an interface and associated code that is used by drivers +that implement interface asynUInt32Digital. asynUInt32DigitalBase provides code +to implement registerInterruptUser and cancelInterruptUser. + +.. list-table:: asynUInt32DigitalBase + :widths: 20 80 + + * - initialize + - After a driver calls registerPort it can call: + :: + + pasynUInt32DigitalBase->initialize(... + + Any null methods in the asynInterface are replaced by default implementations. + +The default implementation of each method does the following: + +.. list-table:: asynUInt32Digital + :widths: 20 80 + + * - write + - Reports an error "write is not supported" and returns asynError + * - read + - Reports an error "read is not supported" and returns asynError + * - setInterrupt + - Reports an error "setInterrupt is not supported" and returns asynError + * - clearInterrupt + - Reports an error "clearInterrupt is not supported" and returns asynError + * - getInterrupt + - Reports an error "getInterrupt is not supported" and returns asynError + * - registerInterruptUser + - registers the interrupt user. The low level driver must call the registered callbacks + via calls to asynManager:interruptStart and asynManager:interruptEnd. + * - cancelInterruptUser + - Cancels the callback + +asynUInt32DigitalSyncIO +~~~~~~~~~~~~~~~~~~~~~~~ +asynUInt32DigitalSyncIO describes a synchronous interface to asynUInt32Digital. +The code that calls it must be willing to block. +:: + + #define asynUInt32DigitalSyncIOType "asynUInt32DigitalSyncIO" + typedef struct asynUInt32DigitalSyncIO { + asynStatus (*connect)(const char *port, int addr, + asynUser **ppasynUser, const char *drvInfo); + asynStatus (*disconnect)(asynUser *pasynUser); + asynStatus (*write)(asynUser *pasynUser, + epicsUInt32 value,epicsUInt32 mask,double timeout); + asynStatus (*read)(asynUser *pasynUser, + epicsUInt32 *pvalue,epicsUInt32 mask,double timeout); + asynStatus (*setInterrupt)(asynUser *pasynUser, + epicsUInt32 mask, interruptReason reason,double timeout); + asynStatus (*clearInterrupt)(asynUser *pasynUser, + epicsUInt32 mask,double timeout); + asynStatus (*getInterrupt)(asynUser *pasynUser, + epicsUInt32 *mask, interruptReason reason,double timeout); + asynStatus (*writeOnce)(const char *port, int addr, + epicsUInt32 value,epicsUInt32 mask,double timeout, + const char *drvInfo); + asynStatus (*readOnce)(const char *port, int addr, + epicsUInt32 *pvalue,epicsUInt32 mask,double timeout, + const char *drvInfo); + asynStatus (*setInterruptOnce)(const char *port, int addr, + epicsUInt32 mask, interruptReason reason,double timeout, + const char *drvInfo); + asynStatus (*clearInterruptOnce)(const char *port, int addr, + epicsUInt32 mask,double timeout,const char *drvInfo); + asynStatus (*getInterruptOnce)(const char *port, int addr, + epicsUInt32 *mask, interruptReason reason,double timeout, + const char *drvInfo); + } asynUInt32DigitalSyncIO; + epicsShareExtern asynUInt32DigitalSyncIO *pasynUInt32DigitalSyncIO; + +.. list-table:: asynUInt32DigitalSyncIO + :widths: 20 80 + + * - connect + - Connects to a port and address, returns a pointer to an asynUser structure. + * - disconnect + - Disconnect. This frees all resources allocated by connect. + * - write + - Calls pasynUInt32Digital->write and waits for the operation to complete or time out. + * - read + - Calls pasynUInt32Digital->read and waits for the operation to complete or time out. + * - setInterrupt + - Calls pasynUInt32Digital->setInterrupt and waits for the operation to complete or time out. + * - clearInterrupt + - Calls pasynUInt32Digital->clearInterrupt and waits for the operation to complete or time out. + * - getInterrupt + - Calls pasynUInt32Digital->getInterrupt and waits for the operation to complete or time out. + * - writeOnce,...,getInterruptOnce + - Does a connect, (write,...,getInterrupt), and disconnect. + +asynFloat64 +~~~~~~~~~~~ +asynFloat64 describes the methods for communicating via IEEE double precision float +values. +:: + + typedef void (*interruptCallbackFloat64)(void *userPvt, asynUser *pasynUser, + epicsFloat64 data); + typedef struct asynFloat64Interrupt { + asynUser *pasynUser; + int addr; + interruptCallbackFloat64 callback; + void *userPvt; + } asynFloat64Interrupt; + #define asynFloat64Type "asynFloat64" + typedef struct asynFloat64 { + asynStatus (*write)(void *drvPvt, asynUser *pasynUser, epicsFloat64 value); + asynStatus (*read)(void *drvPvt, asynUser *pasynUser, epicsFloat64 *value); + asynStatus (*registerInterruptUser)(void *drvPvt, asynUser *pasynUser, + interruptCallbackFloat64 callback, void *userPvt,void **registrarPvt); + asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser, + void *registrarPvt); + } asynFloat64; + + /* asynFloat64Base does the following: + calls registerInterface for asynFloat64. + Implements registerInterruptUser and cancelInterruptUser + Provides default implementations of all methods. + registerInterruptUser and cancelInterruptUser can be called + directly rather than via queueRequest. + */ + + #define asynFloat64BaseType "asynFloat64Base" + typedef struct asynFloat64Base { + asynStatus (*initialize)(const char *portName, + asynInterface *pasynFloat64Interface); + } asynFloat64Base; + epicsShareExtern asynFloat64Base *pasynFloat64Base; + +.. list-table:: asynFloat64 + :widths: 20 80 + + * - write + - Write a value. + * - read + - Read a value. + * - registerInterruptUser + - Register a callback that is called whenever new data is available. Since it can + be called directly rather than via a queueRequest this method must not block. + * - cancelInterruptUser + - Cancel the callback. Since it can be called directly rather than via a queueRequest + this method must not block. + +.. list-table:: asynFloat64Base + :widths: 20 80 + + * - initialize + - After a driver calls registerPort it can call: + :: + + pasynFloat64Base->initialize(... + + Any null methods in the asynInterface are replaced by default implementations. + +The default implementation of each method does the following: + +.. list-table:: asynFloat64Base + :widths: 20 80 + + * - write + - Reports an error "write is not supported" and returns asynError + * - read + - Reports an error "read is not supported" and returns asynError + * - registerInterruptUser + - registers the interrupt user. The low level driver must call the registered callbacks + via calls to asynManager:interruptStart and asynManager:interruptEnd. + * - cancelInterruptUser + - Cancels the callback + +asynFloat64SyncIO +~~~~~~~~~~~~~~~~~ +asynFloat64SyncIO describes a synchronous interrace to asynFloat64. The code that +calls it must be willing to block. +:: + + #define asynFloat64SyncIOType "asynFloat64SyncIO" + typedef struct asynFloat64SyncIO { + asynStatus (*connect)(const char *port, int addr, + asynUser **ppasynUser, const char *drvInfo); + asynStatus (*disconnect)(asynUser *pasynUser); + asynStatus (*write)(asynUser *pasynUser,epicsFloat64 value,double timeout); + asynStatus (*read)(asynUser *pasynUser,epicsFloat64 *pvalue,double timeout); + asynStatus (*writeOnce)(const char *port, int addr, + epicsFloat64 value,double timeout,const char *drvInfo); + asynStatus (*readOnce)(const char *port, int addr, + epicsFloat64 *pvalue,double timeout,const char *drvInfo); + } asynFloat64SyncIO; + epicsShareExtern asynFloat64SyncIO *pasynFloat64SyncIO; + +.. list-table:: asynFloat64SyncIO + :widths: 20 80 + + * - connect + - Connects to a port and address, returns a pointer to an asynUser structure. + * - disconnect + - Disconnect. This frees all resources allocated by connect. + * - write + - Calls pasynFloat64->write and waits for the operation to complete or time out. + * - read + - Calls pasynFloat64->read and waits for the operation to complete or time out. + * - writeOnce + - This does a connect, write, and disconnect. + * - readOnce + - This does a connect, read, and disconnect. + +asynXXXArray (XXX=Int8, Int16, Int32, Int64, Float32 or Float64) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +asynXXXArray describes the methods for communicating via 8, 16, 32, or 64-bit integers, +or 32 or 64-bit IEEE float values. +:: + + typedef void (*interruptCallbackXXXArray)( + void *userPvt, asynUser *pasynUser, + epicsXXX *data, size_t nelements); + typedef struct asynXXXArrayInterrupt { + asynUser *pasynUser; + int addr; + interruptCallbackXXXArray callback; + void *userPvt; + } asynXXXArrayInterrupt; + #define asynXXXArrayType "asynXXXArray" + typedef struct asynXXXArray { + asynStatus (*write)(void *drvPvt, asynUser *pasynUser, + epicsXXX *value, size_t nelements); + asynStatus (*read)(void *drvPvt, asynUser *pasynUser, + epicsXXX *value, size_t nelements, size_t *nIn); + asynStatus (*registerInterruptUser)(void *drvPvt, asynUser *pasynUser, + interruptCallbackXXXArray callback, + void *userPvt,void **registrarPvt); + asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser, + void *registrarPvt); + } asynXXXArray; + + /* asynXXXArrayBase does the following: + calls registerInterface for asynXXXArray. + Implements registerInterruptUser and cancelInterruptUser + Provides default implementations of all methods. + registerInterruptUser and cancelInterruptUser can be called + directly rather than via queueRequest. + */ + + #define asynXXXArrayBaseType "asynXXXArrayBase" + typedef struct asynXXXArrayBase { + asynStatus (*initialize)(const char *portName, + asynInterface *pXXXArrayInterface); + } asynXXXArrayBase; + epicsShareExtern asynXXXArrayBase *pasynXXXArrayBase; + +.. list-table:: asynXXXArray + :widths: 20 80 + + * - write + - Write an array of values. + * - read + - Read an array of values. + * - registerInterruptUser + - Register a callback that is called whenever new data is available. + * - cancelInterruptUser + - Cancel the callback + +.. list-table:: asynXXXArrayBase + :widths: 20 80 + + * - initialize + - After a driver calls registerPort it can call: + :: + + pasynXXXArrayBase->initialize(... + + Any null methods in the asynInterface are replaced by default implementations. + +The default implementation of each method does the following: + +.. list-table:: asynXXXArrayBase + :widths: 20 80 + + * - write + - Reports an error "write is not supported" and returns asynError + * - read + - Reports an error "read is not supported" and returns asynError + * - registerInterruptUser + - Registers an interrupt callback. + * - cancelInterruptUser + - Cancels the callback + +asynXXXArraySyncIO +~~~~~~~~~~~~~~~~~~ +asynXXXArraySyncIO describes a synchronous interface to asynXXXArray. The code that +calls it must be willing to block. +:: + + #define asynXXXArraySyncIOType "asynXXXArraySyncIO" + typedef struct asynXXXArraySyncIO { + asynStatus (*connect)(const char *port, int addr, + asynUser **ppasynUser, const char *drvInfo); + asynStatus (*disconnect)(asynUser *pasynUser); + asynStatus (*write)(asynUser *pasynUser, epicsXXX *pvalue,size_t nelem,double timeout); + asynStatus (*read)(asynUser *pasynUser, epicsXXX *pvalue,size_t nelem,size_t *nIn,double timeout); + asynStatus (*writeOnce)(const char *port, int addr, + epicsXXX *pvalue,size_t nelem,double timeout, const char *drvInfo); + asynStatus (*readOnce)(const char *port, int addr, + epicsXXX *pvalue,size_t nelem,size_t *nIn,double timeout, const char *drvInfo); + } asynXXXArraySyncIO; + epicsShareExtern asynXXXArraySyncIO *pasynXXXArraySyncIO; + +.. list-table:: asynXXXArraySyncIO + :widths: 20 80 + + * - connect + - Connects to a port and address, returns a pointer to an asynUser. + * - disconnect + - Disconnect. This frees all resources allocated by connect. + * - write + - Calls pasynXXXArray->write and waits for the operation to complete or time out. + * - read + - Calls pasynXXXArray->read and waits for the operation to complete or time out. + * - writeOnce + - This does a connect, write, and disconnect. + * - readOnce + - This does a connect, read, and disconnect. + +asynEnum +~~~~~~~~ +asynEnum describes the methods implemented by drivers to define the enum strings, +values, and severities for a device. + +This interface is typically used by drivers to set the enum strings and values for +EPICS bi, bo, mbbi, and mbbo records. The strings[] are used to define the ZNAM +and ONAM fields in bi and bo records, and the ZRST, ONST, ...FFST fields in mbbi +and mbbo records. The integer values[] are ignored for bi and bo records, since +these always have the values of 0 and 1 corresponding to the ZNAM and ONAM states. +The integer values[] are used to assign the ZRVL, ONVL, ... FFVL fields for mbbi +and mbbo records. The integer severities[] are used to set the ZSV and OSV fields +of bi and bo records, and the ZRSV, ONSV, ... FFSV fields of mbbi and mbbo records. +The nelements parameter in the write() and read() functions is used by the client +to specify the dimensions of the strings[], values[], and severities[] arrays. The +driver must not access these arrays beyond element nElements-1. The nIn parameter +in the read() is used by the driver to set the actual number of value enum strings, +values, and severities. There is no size limitation on nElements imposed by the +asynEnum interface. However, the bi and bo records limit nElements to 2, and mbbi +and mbbo records limit nElements to 16. There is no size limitation on the strings +imposed by the asynEnum interface. However, the string fields in the bi, bo, mbbo, +and mbbi records are currently limited to 26 characters. + +Clients must ensure that the char* pointers passed in strings[] in the read() function +are either set to NULL or have been allocated by malloc(). The driver read() function +must first call free() if a string pointer contains a non-NULL value. The driver +must then allocate the strings using malloc() before copying the current enum string +values to them. +:: + + typedef void (*interruptCallbackEnum) + void *userPvt, asynUser *pasynUser, + char *strings[], int values[], int severities[], size_t nelements); + typedef struct asynEnumInterrupt { + asynUser *pasynUser; + int addr; + interruptCallbackEnum callback; + void *userPvt; + } asynEnumInterrupt; + #define asynEnumType "asynEnum" + typedef struct asynEnum { + asynStatus (*write)(void *drvPvt, asynUser *pasynUser, + char *strings[], int values[], int severities[], size_t nelements); + asynStatus (*read)(void *drvPvt, asynUser *pasynUser, + char *strings[], int values[], int severities[], size_t nelements, size_t *nIn); + asynStatus (*registerInterruptUser)(void *drvPvt, asynUser *pasynUser, + interruptCallbackEnum callback, void *userPvt, + void **registrarPvt); + asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser, + void *registrarPvt); + } asynEnum; + + /* asynEnumBase does the following: + calls registerInterface for asynEnum. + Implements registerInterruptUser and cancelInterruptUser + Provides default implementations of all methods. + registerInterruptUser and cancelInterruptUser can be called + directly rather than via queueRequest. + */ + + #define asynEnumBaseType "asynEnumBase" + typedef struct asynEnumBase { + asynStatus (*initialize)(const char *portName, + asynInterface *pEnumInterface); + } asynEnumBase; + epicsShareExtern asynEnumBase *pasynEnumBase; + +.. list-table:: asynEnum + :widths: 20 80 + + * - write + - Writes the enum strings, enum values and enum severities to the driver. + * - read + - Reads the enum strings, enum values and enum severities to the driver. + * - registerInterruptUser + - Registers a callback that will be called whenever there are new enum strings, values + and severities. Since it can be called directly rather than via a queueRequest this + method must not block. + * - cancelInterruptUser + - Cancels the callback. Since it can be called directly rather than via a queueRequest + this method must not block. + +asynEnumBase is an interface and associated code that is used by drivers that implement +interface asynEnum. asynEnumBase provides code to handle registerInterruptUser/cancelInterruptUser. +The driver must itself call the callbacks via calls to asynManager:interruptStart +and asynManager:interruptEnd. + +.. list-table:: asynEnumBase + :widths: 20 80 + + * - initialize + - After a driver calls registerPort it can call: + :: + + pasynEnumBase->initialize(... + + Any null methods in the asynInterface are replaced by default implementations. + +The default implementation of each method does the following: + +.. list-table:: asynEnumBase + :widths: 20 80 + + * - write + - Reports an error "write is not supported" and returns asynError + * - read + - Reports an error "read is not supported" and returns asynError + * - registerInterruptUser + - registers an interrupt callback. + * - cancelInterruptUser + - Cancels the callback + +asynEnumSyncIO +~~~~~~~~~~~~~~ +asynEnumSyncIO describes a synchronous interface to asynEnum. The code that calls +it must be willing to block. +:: + + #define asynEnumSyncIOType "asynEnumSyncIO" + typedef struct asynEnumSyncIO { + asynStatus (*connect)(const char *port, int addr, + asynUser **ppasynUser, const char *drvInfo); + asynStatus (*disconnect)(asynUser *pasynUser); + asynStatus (*write)(asynUser *pasynUser, char *strings[], int values[], int severities[], + size_t nElements, double timeout); + asynStatus (*read)(asynUser *pasynUser, char *string[], int values[], int severities[], + size_t nElements, size_t *nIn, double timeout); + asynStatus (*writeOnce)(const char *port, int addr, char *strings[], int values[], int severities[], + size_t nElements, double timeout, const char *drvInfo); + asynStatus (*readOnce)(const char *port, int addr, char *strings[], int values[], int severities[], + size_t nElements, size_t *nIn, double timeout, const char *drvInfo); + } asynEnumSyncIO; + epicsShareExtern asynEnumSyncIO *pasynEnumSyncIO; + +.. list-table:: asynEnumSyncIO + :widths: 20 80 + + * - connect + - Connects to a port and address, returns a pointer to an asynUser. + * - disconnect + - Disconnect. This frees all resources allocated by connect. + * - write + - Calls pasynEnum->write and waits for the operation to complete or time out. + * - read + - Calls pasynEnum->read and waits for the operation to complete or time out. + * - writeOnce + - This does a connect, write, and disconnect. + * - readOnce + - This does a connect, read, and disconnect. + +asynGenericPointer +~~~~~~~~~~~~~~~~~~ +asynGenericPointer describes the methods for communicating via void* pointers. asyn +clients and port drivers must agree on the type of object that is being pointed to! +:: + + typedef void (*interruptCallbackGenericPointer)(void *userPvt, asynUser *pasynUser, + void *pdata); + typedef struct asynGenericPointerInterrupt { + asynUser *pasynUser; + int addr; + interruptCallbackGenericPointer callback; + void *userPvt; + } asynGenericPointerInterrupt; + #define asynGenericPointerType "asynGenericPointer" + typedef struct asynGenericPointer { + asynStatus (*write)(void *drvPvt, asynUser *pasynUser, void *pvalue); + asynStatus (*read)(void *drvPvt, asynUser *pasynUser, void *pvalue); + asynStatus (*registerInterruptUser)(void *drvPvt, asynUser *pasynUser, + interruptCallbackGenericPointer callback, void *userPvt,void **registrarPvt); + asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser, + void *registrarPvt); + } asynGenericPointer; + + /* asynGenericPointerBase does the following: + calls registerInterface for asynGenericPointer. + Implements registerInterruptUser and cancelInterruptUser + Provides default implementations of all methods. + registerInterruptUser and cancelInterruptUser can be called + directly rather than via queueRequest. + */ + + #define asynGenericPointerBaseType "asynGenericPointerBase" + typedef struct asynGenericPointerBase { + asynStatus (*initialize)(const char *portName, + asynInterface *pasynGenericPointerInterface); + } asynGenericPointerBase; + epicsShareExtern asynGenericPointerBase *pasynGenericPointerBase; + +.. list-table:: asynGenericPointer + :widths: 20 80 + + * - write + - Write a value. + * - read + - Read a value. + * - registerInterruptUser + - Register a callback that is called whenever new data is available. Since it can + be called directly rather than via a queueRequest this method must not block. + * - cancelInterruptUser + - Cancel the callback. Since it can be called directly rather than via a queueRequest + this method must not block. + +.. list-table:: asynGenericPointerBase + :widths: 20 80 + + * - initialize + - After a driver calls registerPort it can call: + :: + + pasynGenericPointerBase->initialize(... + + Any null methods in the asynInterface are replaced by default implementations. + +The default implementation of each method does the following: + +.. list-table:: asynGenericPointerBase + :widths: 20 80 + + * - write + - Reports an error "write is not supported" and returns asynError + * - read + - Reports an error "read is not supported" and returns asynError + * - registerInterruptUser + - registers the interrupt user. The low level driver must call the registered callbacks + via calls to asynManager:interruptStart and asynManager:interruptEnd. + * - cancelInterruptUser + - Cancels the callback + +asynGenericPointerSyncIO +~~~~~~~~~~~~~~~~~~~~~~~~ +asynGenericPointerSyncIO describes a synchronous interrace to asynGenericPointer. +The code that calls it must be willing to block. +:: + + #define asynGenericPointerSyncIOType "asynGenericPointerSyncIO" + typedef struct asynGenericPointerSyncIO { + asynStatus (*connect)(const char *port, int addr, + asynUser **ppasynUser, const char *drvInfo); + asynStatus (*disconnect)(asynUser *pasynUser); + asynStatus (*write)(asynUser *pasynUser,void *pvalue,double timeout); + asynStatus (*read)(asynUser *pasynUser,void *pvalue,double timeout); + asynStatus (*writeRead)(asynUser *pasynUser,void *pwrite_buffer,void *pread_buffer,double timeout); + asynStatus (*writeOnce)(const char *port, int addr, + void *pvalue,double timeout,const char *drvInfo); + asynStatus (*readOnce)(const char *port, int addr, + void *pvalue,double timeout,const char *drvInfo); + asynStatus (*writeReadOnce)(const char *port, int addr, + void *pwrite_buffer,void *pread_buffer,double timeout,const char *drvInfo); + } asynGenericPointerSyncIO; + epicsShareExtern asynGenericPointerSyncIO *pasynGenericPointerSyncIO; + +.. list-table:: asynGenericPointerSyncIO + :widths: 20 80 + + * - connect + - Connects to a port and address, returns a pointer to an asynUser structure. + * - disconnect + - Disconnect. This frees all resources allocated by connect. + * - write + - Calls pasynGenericPointer->write and waits for the operation to complete or time out. + * - read + - Calls pasynGenericPointer->read and waits for the operation to complete or time out. + * - writeRead + - Calls pasynGenericPointer->write, then pasynGenericPointer->read. Waits for + the operations to complete or time out. + * - writeOnce + - This does a connect, write, and disconnect. + * - readOnce + - This does a connect, read, and disconnect. + * - writeReadOnce + - This does a connect, writeRead, and disconnect. + +asynStandardInterfacesBase +-------------------------- +asynStandardInterfacesBase is an interface designed as a convenience to minimize +the amount of code that must be written in the initialization routine of a port +driver that uses the standard asyn message-based or register-based interfaces that +are described above. Without asynStandardInterfacesBase a port driver needs to call +asynRegisterInterface(), and possibly asynRegisterInterruptSource() for each interface +that it supports, and handle any errors that may occur in these calls. It also needs +to explicitly include several fields in its drvPvt structure for each interface. +asynStandardInterfacesBase provides an interface that allows port drivers to include +a single structure in its drvPvt structure, and define values in this structure. +It then calls a single function to register all interfaces that it supports, and +to register itself as an interrupt source on one or more of those interfaces. This +can reduce the number of lines of code in the driver initialization routine by a +factor of four or more. + +asynStandardInterfaces structure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The following is the definition of the asynStandardInterfaces structure. Drivers +will normally have a structure of this type contained in their drvPvt structure. +If this structure is initialized to all zeros when drvPvt is created, then all that +is necessary is to fill in the addresses of each of each of the supported interfaces +(in that interface's .pinterface field), and to set the CanInterrupt flag to 1 for +those interfaces that are interrupt sources. +:: + + typedef struct asynStandardInterfaces { + asynInterface common; + + asynInterface drvUser; + + asynInterface option; + + asynInterface octet; + int octetProcessEosIn; + int octetProcessEosOut; + int octetInterruptProcess; + int octetCanInterrupt; + void *octetInterruptPvt; + + asynInterface uInt32Digital; + int uInt32DigitalCanInterrupt; + void *uInt32DigitalInterruptPvt; + + asynInterface int32; + int int32CanInterrupt; + void *int32InterruptPvt; + + asynInterface int64; + int int64CanInterrupt; + void *int64InterruptPvt; + + asynInterface float64; + int float64CanInterrupt; + void *float64InterruptPvt; + + asynInterface int8Array; + int int8ArrayCanInterrupt; + void *int8ArrayInterruptPvt; + + asynInterface int16Array; + int int16ArrayCanInterrupt; + void *int16ArrayInterruptPvt; + + asynInterface int32Array; + int int32ArrayCanInterrupt; + void *int32ArrayInterruptPvt; + + asynInterface int64Array; + int int64ArrayCanInterrupt; + void *int64ArrayInterruptPvt; + + asynInterface float32Array; + int float32ArrayCanInterrupt; + void *float32ArrayInterruptPvt; + + asynInterface float64Array; + int float64ArrayCanInterrupt; + void *float64ArrayInterruptPvt; + + asynInterface genericPointer; + int genericPointerCanInterrupt; + void *genericPointerInterruptPvt; + + asynInterface Enum; + int enumCanInterrupt; + void *enumInterruptPvt; + + } asynStandardInterfaces; + +asynStandardInterfacesBase interface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The following is the definition of the asynStandardInterfacesBase interface. +:: + + typedef struct asynStandardInterfacesBase { + asynStatus (*initialize)(const char *portName, asynStandardInterfaces *pInterfaces, + asynUser *pasynUser, void *pPvt); + } asynStandardInterfacesBase; + + epicsShareExtern asynStandardInterfacesBase *pasynStandardInterfacesBase; + +asynStandardInterfacesBase has a single method, initialize(), which calls registerInterface +or Base->initialize for each interface which has a non-NULL value in its .pinterface +field. It also calls registerInterruptSource for interfaces that are defined and +that have the CanInterrupt flag set to 1. The pasynUser argument to the initialize() +method is used only to provide a place for the method to return an error message +(in pasynUser->errorMessage) so the invoking routine may reuse or free the asynUser +structure when the method has returned. + +The following is an example of the code required in a port driver that uses the +asynStandardInterfacesBase interface. +:: + + #include + ... + typedef struct drvADPvt { + ... + /* The asyn interfaces this driver implements */ + asynStandardInterfaces asynStdInterfaces; + + /* asynUser connected to ourselves for asynTrace */ + asynUser *pasynUser; + ... + } drvADPvt; + ... + /* Structures with function pointers for each of the asyn interfaces */ + static asynCommon ifaceCommon = { + report, + connect, + disconnect + }; + + static asynInt32 ifaceInt32 = { + writeInt32, + readInt32, + getBounds + }; + + static asynInt64 ifaceInt64 = { + writeInt64, + readInt64, + getBounds + }; + + static asynFloat64 ifaceFloat64 = { + writeFloat64, + readFloat64 + }; + + static asynOctet ifaceOctet = { + writeOctet, + NULL, + readOctet, + }; + + static asynDrvUser ifaceDrvUser = { + drvUserCreate, + drvUserGetType, + drvUserDestroy + }; + + static asynGenericPointer ifaceGenericPointer = { + writeADImage, + readADImage + }; + ... + + int simDetectorConfig(const char *portName, int maxSizeX, int maxSizeY, int dataType) + + { + drvADPvt *pPvt; + int status = asynSuccess; + char *functionName = "simDetectorConfig"; + asynStandardInterfaces *pInterfaces; + + pPvt = callocMustSucceed(1, sizeof(*pPvt), functionName); + pPvt->portName = epicsStrDup(portName); + + status = pasynManager->registerPort(portName, + ASYN_MULTIDEVICE | ASYN_CANBLOCK, + 1, /* autoconnect */ + 0, /* medium priority */ + 0); /* default stack size */ + if (status != asynSuccess) { + printf("%s ERROR: Can't register port\n", functionName); + return(asynError); + } + + /* Create asynUser for debugging */ + pPvt->pasynUser = pasynManager->createAsynUser(0, 0); + + pInterfaces = &pPvt->asynStdInterfaces; + + /* Initialize interface pointers */ + pInterfaces->common.pinterface = (void *)&ifaceCommon; + pInterfaces->drvUser.pinterface = (void *)&ifaceDrvUser; + pInterfaces->octet.pinterface = (void *)&ifaceOctet; + pInterfaces->int32.pinterface = (void *)&ifaceInt32; + pInterfaces->int64.pinterface = (void *)&ifaceInt64; + pInterfaces->float64.pinterface = (void *)&ifaceFloat64; + pInterfaces->genericPointer.pinterface = (void *)&ifaceGenericPointer; + + /* Define which interfaces can generate interrupts */ + pInterfaces->octetCanInterrupt = 1; + pInterfaces->int32CanInterrupt = 1; + pInterfaces->int64CanInterrupt = 1; + pInterfaces->float64CanInterrupt = 1; + pInterfaces->genericPointerCanInterrupt = 1; + + status = pasynStandardInterfacesBase->initialize(portName, pInterfaces, + pPvt->pasynUser, pPvt); + if (status != asynSuccess) { + printf("%s ERROR: Can't register interfaces: %s.\n", + functionName, pPvt->pasynUser->errorMessage); + return(asynError); + } + ... + } + +Standard Interpose Interfaces +----------------------------- +asynInterposeEos +~~~~~~~~~~~~~~~~ +This can be used to simulate EOS processing for asynOctet if the port driver doesn't +provide EOS support. If an EOS is specified it looks for the eos on each read. It +is started by the shell command: +:: + + asynInterposeEosConfig port addr processEosIn processEosOut + +where + +- port is the name of the port. +- addr is the address +- processEosIn (0,1) means (do not, do) implement eosIn commands. +- processEosOut (0,1) means (do not, do) implement eosOut commands. + +This command should appear immediately after the command that initializes a port. +Some drivers provide configuration options to call this automatically. + +asynInterposeFlush +~~~~~~~~~~~~~~~~~~ +This can be used to simulate flush processing for asynOctet if the port driver doesn't +provide support for flush. It just reads and discards characters until no more characters +arive before timeout seconds have occured. It is started by the shell command: +:: + + asynInterposeFlushConfig port addr timeout + +where + +- port is the name of the port. +- addr is the address +- timeout is the time to wait for more characters + +This command should appear immediately after the command that initializes a port. + +asynInterposeCom +~~~~~~~~~~~~~~~~ +This provides the ability to configure serial ports on terminal servers using the +RFC 2117 protocol. It is not configured from the iocsh directly, but is rather configured +automatically by the drvAsynIPPort driver if the COM protocol is specified. It supports +the same options as drvAsynSerialPort, i.e. "baud", "bits", "parity", "stop", "crtscts", +and "ixon". + +asynInterposeDelay +~~~~~~~~~~~~~~~~~~ +This can be used to wait for a specified delay after sending each character before +sending the next. Some poorly designed devices require this. It is started by the +shell command: +:: + + asynInterposeDelay port addr delay + +where + +- port is the name of the port. +- addr is the address +- delay is the time to wait after sending each character + +This command should appear immediately after the command that initializes a port. +At run-time the delay can be examined or changed using the asyn option interface +with the `delay` option which is added by this interpose layer. +:: + + asynShowOption port, address, "delay" + asynSetOption port, address, "delay", delay(sec) + +asynInterposeEcho +~~~~~~~~~~~~~~~~~ +This can be used to wait for each character to be echoed by the device before sending +the next character. Some poorly designed devices require this. It is started by +the shell command: +:: + + asynInterposeEcho port addr + +where + +- port is the name of the port. +- addr is the address + +This command should appear immediately after the command that initializes a port. + +Generic Device Support for EPICS records +---------------------------------------- +Generic device support is provided for standard EPICS records. This support should +be usable for a large class of low level register based drivers. For complicated +devices other support is required. This release provides the following: + +- devAsynInt32 - support for drivers that implement interface asynInt32 +- devAsynInt64 - support for drivers that implement interface asynInt64 +- devAsynInt32TimeSeries - waveform record support for drivers that implement callbacks + on interface asynInt32 +- devAsynInt64TimeSeries - waveform record support for drivers that implement callbacks + on interface asynInt64 +- devAsynInt8Array - support for drivers that implement interface asynInt8Array +- devAsynInt16Array - support for drivers that implement interface asynInt16Array +- devAsynInt32Array - support for drivers that implement interface asynInt32Array +- devAsynInt64Array - support for drivers that implement interface asynInt64Array +- devAsynUInt32Digital - support for drivers that implement interface asynUInt32Digital +- devAsynFloat64 - support for drivers that implement interface asynFloat64 +- devAsynFloat64TimeSeries - waveform record support for drivers that implement + callbacks on interface asynFloat64 +- devAsynFloat32Array - support for drivers that implement interface asynFloat32Array +- devAsynFloat64Array - support for drivers that implement interface asynFloat64Array +- devAsynOctet - support for drivers that implement interface asynOctet +- devEpics - This is just a single file devEpics.dbd that includes the dbd files + for the above support. +- asynEpicsUtils.c - This provides utility functions. parseLink(), parseLinkMask() + and parseLinkFree() parse record the record INP and OUT links described below. asynStatusToEpicsAlarm() + converts asynStatus enum values to EPICS record STAT and SEVR values setting record + alarms. + +The support uses the following conventions for DTYP and INP. OUT fields are the +same as INP. +:: + + field(DTYP,"asynXXX") + field(INP,"@asyn(portName,addr,timeout)drvParams") + or + field(INP,"@asynMask(portName,addr,mask,timeout)drvParams") + +where + +- XXX - The name of the type of interface supported. +- portName - The name of the port. +- addr - The address. If addr is not specified the default is 0. +- mask - This is for devAsynUInt32Digital. It is also used by devAsynInt32 to specify + the number of bits of the hardware device for drivers that do not support getBounds(). +- timeout - The timeout value for asynUser.timeout. If not specified the default + is 1.0. +- drvParams - This is passed to the low level driver via the asynDrvUser interface. + It is optional. + +For example: +:: + + field(DTYP,"asynInt32") + field(INP,"@asyn(portA,0,.1)thisIsForDriver") + +asynManager interrupts and EPICS device support +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +All of the device support files can call registerInterruptUser for input records. +The callback is used in one of two ways: + +- Input Records except Average and TimeSeries + + It is used to support SCAN = "I/O Intr". + +- Input records that are averaged, i.e. asynInt32Average or asynFloat64Average. + + These records can be scanned either periodically or with SCAN=I/O Intr. The registerInterruptUser + callback is used to add the current value to the sum of values between record processing. + + If the record is periodically processed, then the average is computed each time + the record processes. If the record is processed before new data have arrived (numAverage==0) + the record is set to UDF/INVALID, UDF is set to TRUE, and the value is left unchanged. + + If the record has SCAN=I/O Intr then the average is computed and the record is processed + each time 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. This means that simulation mode cannot be used with asynInt32Average + or asynFloat64Average device support if SCAN=I/O Intr. This is probably not a significant + limitation. Support for SCAN=I/O Intr was added in R4-34. + +- Input records that are waveform time series, i.e. asynInt32TimeSeries, asynInt64TimeSeries + or asynFloat64TimeSeries. + + These records are normally scanned periodically. The registerInterruptUser callback + is used to append values to the time series. + +Initial values of output records +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The device support for output records on register based interfaces (bo, mbbo, ao, +longout) does an initial read() of the value from the driver in init_record. If +this read() returns asynSuccess then the record value is set to the value returned +from read(). If read() returns anything other than asynSuccess then the record value +is not modified. This mechanism supports "bumpless reboots" where the initial value +of output records will match the current value of the hardware when the IOC starts. +Drivers should only return asynSuccess from the read() function if the value is +known to be valid. Note that this value read from the device will replace the value +in the database when iocInit begins. However, the value read from the device may +in turn be replaced by any value from save/restore, because the auto restore happens +later in iocInit. + +Beginning in R4-30 devAsynOctet was changed to also support the initial readback +for stringout and waveform output records. The initial readback is only done if +the record in the database contains the following line: +:: + + info(asyn:INITIAL_READBACK, "1") + +Enum values for bi, bo, mbbi, and mbbo records +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Beginning in asyn R4-19 support was added for asyn port drivers to control the values +of the enum strings, enum values and enum severities in bi, bo, mbbi, and mbbo records. +This is implemented in the asynInt32 and asynUInt32Digital device support as follows: + +- In the device support init_record function the device support attempts to find + the asynEnum interface in the driver. If it is found then the driver calls pasynEnumSyncIO->read() + to read the current values of the enums from the driver. If the read() returns asynSuccess + then the enum fields are set to the values returned by the driver. If the asynEnum + interface is not supported, or if read() returns anything except asynSuccess then + the enum fields are not modified. +- Device support registers for callbacks on the asynEnum interface. Drivers can + make callbacks to dynamically change the values of enums at run-time. For example, + changing the gain of an ADC might change the allowed choices for the speed, etc. + Device support calls db_post_events(pr, &pr->val, DBE_PROPERTY) when the + enum fields change. This notifies clients that the enum values have changed. Older + clients like medm and edm will not change the enum widgets until the window is closed + and reopened, but newer clients like CSS should dynamically change the enum widgets. + + +Callback updates for output records +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Beginning in asyn R4-26 support was added for updating output records from driver +interrupt callbacks. This feature allows output records to reflect changes in the +underlying hardware that are caused by manual front-panel operation, changes caused +by another output record, etc. + +By default output records do not update when a driver does interrupt callbacks. +However, if the following info tag is added for a record in the database file then +callbacks will be enabled and the output record will be updated whenever the driver +does a callback for that value. +:: + + info(asyn:READBACK, "1") + +If the value of the info tag is 0 or if the info tag is not present then updates +of output records on interrupt callbacks are disabled. + +Buffering of driver callbacks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +It is possible for the time between driver callbacks to be less than the time for +record processing. asyn device support provides a ring-buffer (FIFO) mechanism to +buffer values so that the record will process all callback values from a short burst +of callbacks. For all records except devAsynOctet (stringin, stringout, lsi, lso, +printf, sCalcout and waveform) records the default buffer size is 10 values. For +stringin, stringout, and waveform records the default buffer size is 0, i.e. there +is no buffering. For all record types the size of the buffer can be controlled by +the following info tag for a record in the database file: +:: + + info(asyn:FIFO, "20") + +In this example the buffer size was set to 20. Ring buffer support was added in +asyn R4-10 for all records except stringin, stringout, and waveform. Waveform record +support for numeric arrays was added in asyn R4-25. asynOctet support for stringin, +stringout, and waveform records was added in asyn R4-26. In R4-35 a deadlock issue +with asyn:READBACK was found. To fix this with asynOctet output records a ring buffer +is required. Thus, a minimum ring buffer size of 1 is enforced in the driver for +these records if asyn:REABACK=1 even if asyn:FIFO is not specified. asyn:FIFO can +still be used to select a larger ring buffer size. + +Time stamps +~~~~~~~~~~~ +Beginning in asyn R4-20 support was added for asyn port drivers to set the TIME +field of input records. This is done by setting the TSE field of the record to "-2" +and setting the desired value into the timestamp field of the pasynUser structure +referred to in the device read method or interrupt callback. + +Beginning in asyn R4-22 the timestamp support functions were added to asynManager +to update, get and set the most recent timestamp for the port in asynManager. Support +was also added for user-supplied timestamp source functions. Timestamp support was +also added to asynPortDriver for the base-class read functions and callback functions. + +asynInt32 device support +~~~~~~~~~~~~~~~~~~~~~~~~ + +The following support is available: +:: + + device(ai,INST_IO,asynAiInt32,"asynInt32") + device(ai,INST_IO,asynAiInt32Average,"asynInt32Average") + device(ao,INST_IO,asynAoInt32,"asynInt32") + device(bi,INST_IO,asynBiInt32,"asynInt32") + device(bo,INST_IO,asynBoInt32,"asynInt32") + device(mbbi,INST_IO,asynMbbiInt32,"asynInt32") + device(mbbo,INST_IO,asynMbboInt32,"asynInt32") + device(longin,INST_IO,asynLiInt32,"asynInt32") + device(longout,INST_IO,asynLoInt32,"asynInt32") + +devAsynInt32.c provides EPICS device support for drivers that implement interface +asynInt32. + +For ai and ao records either of the following specifications for the INP and OUT +fields can be used: +:: + + field(INP,"@asyn(portName,addr,timeout) drvParams") + or + field(INP,"@asynMask(portName,addr,nbits,timeout) drvParams") + +The asynMask format allows device support to work with drivers that cannot return +meaningful values from 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. Values will be masked to the specified number of bits. + + nbits < 0 Device is bipolar with a range from -2^(abs(nbits)-1) to 2^((abs(nbits)-1)-1 + +Values read with the asynInt32 interface will be sign extended +using the sign bit (e.g. bit abs(nbits)-1 starting at bit 0). + +- aiRecord + + A value is given to rval. Linear conversions are supported if the driver implements + getBounds, or if nbits is specified as explained above. + + - asynInt32 + + - SCAN "I/O Intr" is supported. If the record is "I/O Intr" scanned + then when the registerInterruptUser callback is called, it saves the value and calls + scanIoRequest. When the record is processed the saved value is put into rval. + - If the record is not "I/O Intr" scanned then each time the record is processed, a new + value is read via a call to pasynInt32->read. + - asynInt32Average + + - The registerInterruptUser callback adds the new value to a + sum and also increments the number of samples. + - When the record is processed the average is computed and the sum and number of samples is set to zero. + - If the record is processed before new data have arrived (numAverage==0) the record is set to UDF/INVALID, + UDF is set to TRUE, and the value is left unchanged. + - The record can be scanned either periodically or with SCAN=I/O Intr. + - If the record has SCAN=I/O Intr then the average is computed and the record is processed each time NumAverage callback readings have + been received. + - The SVAL field in the ai record is used to set NumAverage. + +- aoRecord + + rval is written. Linear conversions are supported if the driver properly implements + getBounds, or if nbits is specified as explained above. + +- longinRecord + + A value is given to val. Each time the record is processed a new value is read. + SCAN "I/O Intr" is supported similar to aiRecord. + +- longoutRecord + + val is written. + +- biRecord + + A value is given to rval. The mask field in the record is not used. Each time the + record is processed a new value is read. SCAN "I/O Intr" is supported similar to + aiRecord. + +- boRecord + + rval is written. The mask field in the record is not used. + +- mbbiRecord + + A value is given to rval. mask is computed from nobt and shft. Each time the record + is processed a new value is read. SCAN "I/O Intr" is supported similar to aiRecord. + +- mbboRecord + + rval is written. mask is computed from nobt and shft. + +Analog Input Example Records +:: + + record(ai,"aiInt32") { + field(SCAN,"I/O Intr") + field(DTYP,"asynInt32") + field(INP,"@asyn($(port),$(addr))") + field(EGUF,"10.0") + field(EGUL,"-10.0") + field(PREC,"3") + } + # This record is for a 12-bit bipolar ADC for a driver that does not + # support getBounds() + record(ai,"aiInt32") { + field(SCAN,"I/O Intr") + field(DTYP,"asynInt32") + field(INP,"@asynMask($(port),$(addr),-12)") + field(EGUF,"10.0") + field(EGUL,"-10.0") + field(PREC,"3") + } + record(ai,"aiInt32Average") { + field(SCAN,"10 second") + field(DTYP,"asynInt32Average") + field(INP,"@asyn($(port),$(addr))") + field(EGUF,"10.0") + field(EGUL,"-10.0") + field(PREC,"3") + } + +Analog Output Example Record +:: + + record(ao,"aoInt32") { + field(DTYP,"asynInt32") + field(OUT,"@asyn($(port),$(addr))") + field(EGUF,"10.0") + field(EGUL,"-10.0") + field(PREC,"3") + } + +Long Input Example Records +:: + + record(longin,"liInt32") { + field(SCAN,"I/O Intr") + field(DTYP,"asynInt32") + field(INP,"@asyn($(port),$(addr))") + } + +Long Output Example Record +:: + + record(longout,"loInt32") { + field(DTYP,"asynInt32") + field(OUT,"@asyn($(port),$(addr))") + } + +Multibit Binary Input Example Records +:: + + record(mbbi,"mbbiInt32") { + field(SCAN,"I/O Intr") + field(DTYP,"asynInt32") + field(INP,"@asyn($(port),$(addr))") + field(NOBT,"2") + field(SHFT,"2") + field(ZRST,"zeroVal") + field(ONST,"oneVal") + field(TWST,"twoVal") + field(THST,"threeVal") + } + +Multibit Binary Output Example Record +:: + + record(mbbo,"mbboInt32") { + field(DTYP,"asynInt32") + field(OUT,"@asyn($(port),$(addr))") + field(NOBT,"2") + field(SHFT,"16") + field(ZRST,"zeroVal") + field(ONST,"oneVal") + field(TWST,"twoVal") + field(THST,"threeVal") + } + +asynInt64 device support +~~~~~~~~~~~~~~~~~~~~~~~~ +asynInt64 device support is available for the ao, ai, longout, and longin records +on all versions of EPICS base. The following support is available in devAsynInt64Misc.dbd. +:: + + device(longin,INST_IO,asynLiInt64,"asynInt64") + device(longout,INST_IO,asynLoInt64,"asynInt64") + device(ai,INST_IO,asynAiInt64,"asynInt64") + device(ao,INST_IO,asynAoInt64,"asynInt64") + +Support for the int64in, int64out, and waveform records is available in EPICS base +3.16.1 and later. That is when the int64in, int64out records were added, and when +the waveform record added support for FTVL=Int64. The following support is available +in devAsynInt64.dbd: +:: + + device(int64in,INST_IO,Int64Out,"asynInt64") + device(int64out,INST_IO,Int64Out,"asynInt64") + +devAsynInt64.c provides EPICS device support for drivers that implement interface +asynInt64. + +- aiRecord + + A 64-bit integer is read from the driver and converted to a 64-bit float. The 64-bit + float can exactly represent integers up to 52 bits. The value is read into the .VAL + field, not the .RVAL field. Linear conversion is limited to .EOFF and .ESLO. Each + time the record is processed a new value is read. SCAN "I/O Intr" is supported. + +- aoRecord + + The 64-bit float .VAL is converted to a 64-bit integer and written to the driver. + The 64-bit float can exactly represent integers up to 52 bits. The value is read + from the .VAL field, not from the .RVAL field. Linear conversion is limited to .EOFF + and .ESLO. + +- longinRecord + + A 64-bit integer is read from the driver and truncated to a 32-bit integer. Each + time the record is processed a new value is read. SCAN "I/O Intr" is supported. + +- longoutRecord + + A 32-bit integer is written to the driver from the .VAL field. + +- int64inRecord + + A value is given to .VAL. Each time the record is processed a new value is read. + SCAN "I/O Intr" is supported similar to aiRecord. + +- int64outRecord + + .VAL is written. + +Int64 Input Example Records. The longin and ai records are the same except for the +record type. +:: + + record(int64in,"Int64In") { + field(SCAN,"I/O Intr") + field(DTYP,"asynInt64") + field(INP,"@asyn($(port),$(addr))") + } + +Int64 Output Example Record. The longout and ao records are the same except for +the record type +:: + + record(int64out,"Int64Out") { + field(DTYP,"asynInt64") + field(OUT,"@asyn($(port),$(addr))") + } + +asynIntXXXArray device support (XXX=8, 16, 32, or 64) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The following support is available: +:: + + device(waveform,INST_IO,asynIntXXXArrayWfIn,"asynIntXXXArrayIn") + device(waveform,INST_IO,asynIntXXXArrayWfOut,"asynIntXXXArrayOut") + +devAsynIntXXXArray.c provides EPICS device support for drivers that implement interface +asynIntXXXArray. It has support for both reading and writing a waveform. SCAN "I/O +Intr" is supported similar to the aiRecord in devAsynInt32 device support. + +asynXXXTimeSeries device support (XXX=Int32, Int64, or Float64) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The following support is available: +:: + + device(waveform,INST_IO,asynInt32TimeSeries,"asynInt32TimeSeries") + device(waveform,INST_IO,asynInt64TimeSeries,"asynInt64TimeSeries") + device(waveform,INST_IO,asynFloat64TimeSeries,"asynFloat64TimeSeries") + +devAsynXXXTimeSeries.c provides EPICS device support to collect a time series of +values into a waveform record. It works with drivers that implement callbacks on +the asynInt32, asynInt64, or asynFloat64 interfaces. This permits more rapid and +efficient acquisition of values from a driver than can be obtained using record +support and database operations. The waveform record RARM field is used to control +acquisition as follows: + +- RARM=1 Erase and start acquisition, i.e. clear the waveform record to 0, set NORD=0, + BUSY=1 and enable callbacks. +- RARM=2 Stop acquisition, set BUSY=0. +- RARM=3 Start acquisition (set BUSY=1) without clearing the waveform or setting + NORD=0. + +asynUInt32Digital device support +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The following support is available: +:: + + device(bi,INST_IO,asynBiUInt32Digital,"asynUInt32Digital") + device(bo,INST_IO,asynBoUInt32Digital,"asynUInt32Digital") + device(longin,INST_IO,asynLiUInt32Digital,"asynUInt32Digital") + device(longout,INST_IO,asynLoUInt32Digital,"asynUInt32Digital") + device(mbbi,INST_IO,asynMbbiUInt32Digital,"asynUInt32Digital") + device(mbbo,INST_IO,asynMbboUInt32Digital,"asynUInt32Digital") + device(mbbiDirect,INST_IO,asynMbbiDirectUInt32Digital,"asynUInt32Digital") + device(mbboDirect,INST_IO,asynMbboDirectUInt32Digital,"asynUInt32Digital") + +devAsynUInt32Digital.c provides EPICS device support for drivers that implement +interface asynUInt32Digital. The INP or OUT field must define asynMask. The mask +specified in the argument to asynMask is used in the calls to asynUInt32Digital +methods. In addition it is used to set the mask fields in bi and bo records and +the mask and shft fields in mbbi, mbbo, mbbiDirect, and mbboDirect records. + +- biRecord + + A value is given to rval. asynInt32 - SCAN "I/O Intr" is supported. If the record + is "I/O Intr" scanned then when the registerInterruptUser callback is called, it + saves the value and calls scanIoRequest. When the record is processed the saved + value is put into rval. If the record is not "I/O Intr" scanned then each time the + record is processed, a new value is read via a call to pasynUInt32Digital->read. + +- boRecord + + rval is written. + +- longinRecord + + A value is given to val. Each time the record is processed a new value is read. + SCAN "I/O Intr" is supported similar to aiRecord. + +- longoutRecord + + val is written. + +- mbbiRecord + + A value is given to rval. Each time the record is processed a new value is read. + SCAN "I/O Intr" is supported similar to aiRecord. + +- mbboRecord + + rval is written. + +- mbbiDirectRecord + + A value is given to rval. Each time the record is processed a new value is read. + SCAN "I/O Intr" is supported similar to aiRecord. + +- mbboDirectRecord + + rval is written. + +Binary Input Example Record +:: + + record(bi,"biUInt32Bit0") { + field(SCAN,"I/O Intr") + field(DTYP,"asynUInt32Digital") + field(INP,"@asynMask( $(port) , 0, 0x1 , 1.0) ") + field(ZNAM,"zero") + field(ONAM,"one") + } + +Binary Output Example Record +:: + + record(bo,"boUInt32Bit2") { + field(DTYP,"asynUInt32Digital") + field(OUT,"@asynMask( $(port) , 0, 0x4 , 1.0) ") + field(ZNAM,"zero") + field(ONAM,"one") + } + +Long Input Example Record +:: + + record(longin,"liUInt32") { + field(SCAN,"I/O Intr") + field(DTYP,"asynUInt32Digital") + field(INP,"@asynMask( $(port) , 0, 0xffffffff , 1.0) ") + } + +Long Output Example Record +:: + + record(longout,"loUInt32") { + field(DTYP,"asynUInt32Digital") + field(OUT,"@asynMask( $(port) , 0, 0xffffffff , 1.0) ") + } + +Multibit Input Example Record +:: + + record(mbbi,"mbbiUInt32") { + field(SCAN,"I/O Intr") + field(DTYP,"asynUInt32Digital") + field(INP,"@asynMask( digital , 0, 0x3 , 1.0) ") + field(ZRST,"zero") + field(ONST,"one") + field(TWST,"two") + field(THST,"three") + field(ZRVL,"0x0") + field(ONVL,"0x1") + field(TWVL,"0x2") + field(THVL,"0x3") + } + +Multibit Output Example Record +:: + + record(mbbo,"mbboUInt32") { + field(DTYP,"asynUInt32Digital") + field(OUT,"@asynMask( digital , 0, 0x7 , 1.0) ") + field(ZRST,"zero") + field(ONST,"one") + field(TWST,"two") + field(THST,"three") + field(FRST,"four") + field(FVST,"five") + field(SXST,"six") + field(SVST,"seven") + field(ZRVL,"0x0") + field(ONVL,"0x1") + field(TWVL,"0x2") + field(THVL,"0x3") + field(FRVL,"0x4") + field(FVVL,"0x5") + field(SXVL,"0x6") + field(SVVL,"0x7") + } + +asynFloat64 device support +~~~~~~~~~~~~~~~~~~~~~~~~~~ +The following support is available: +:: + + device(ai,INST_IO,asynAiFloat64,"asynFloat64") + device(ai,INST_IO,asynAiFloat64Average,"asynFloat64Average") + device(ao,INST_IO,asynAoFloat64,"asynFloat64") + +devAsynFloat64.c provides EPICS device support for drivers that implement interface +asynFloat64. + +- aiRecord + + A value is given to val. Beginning with R4-33 scaling via the ASLO/AOFF record fields, + and smoothing via the SMOO field are supported. + + - asynFloat64 + + - SCAN "I/O Intr" is supported. If the record is "I/O Intr" scanned + then when the registerInterruptUser callback is called, it saves the value and calls + scanIoRequest. When the record is processed the saved value is put into val. + - If the record is not "I/O Intr" scanned then each time the record is processed, a new + value is read via a call to pasynFloat64->read. + - asynFloat64Average + + - The registerInterruptUser callback adds the new value to + a sum and also increments the number of samples. + - When the record is processed the average is computed and the sum and number of samples is set to zero. + - If the record is processed before new data have arrived (numAverage==0) the record is set to UDF/INVALID, + UDF is set to TRUE, and the value is left unchanged. + - The record can be scanned either periodically or with SCAN=I/O Intr. + - If the record has SCAN=I/O Intr then the average is computed and the record is processed each time NumAverage callback readings have + been received. + - The SVAL field in the ai record is used to set NumAverage. + +- aoRecord + + val is written. Beginning with R4-33 scaling via the ASLO/AOFF record fields is + supported. + +asynFloatXXXArray device support (XXX=32 or 64) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The following support is available: +:: + + device(waveform,INST_IO,asynFloatXXXArrayWfIn,"asynFloatXXXArrayIn") + device(waveform,INST_IO,asynFloatXXXArrayWfOut,"asynFloatXXXArrayOut") + +devAsynFloatXXXArray.c provides EPICS device support for drivers that implement +interface asynFloatXXXArray. It has support for both reading and writing a waveform. +SCAN "I/O Intr" is supported similar to the aiRecord in devAsynInt32 device support. + +asynOctet device support +~~~~~~~~~~~~~~~~~~~~~~~~ +The following support is available: +:: + + device(stringin,INST_IO,asynSiOctetCmdResponse,"asynOctetCmdResponse") + device(stringin,INST_IO,asynSiOctetWriteRead,"asynOctetWriteRead") + device(stringin,INST_IO,asynSiOctetRead,"asynOctetRead") + device(stringout,INST_IO,asynSoOctetWrite,"asynOctetWrite") + device(waveform,INST_IO,asynWfOctetCmdResponse,"asynOctetCmdResponse") + device(waveform,INST_IO,asynWfOctetWriteRead,"asynOctetWriteRead") + device(waveform,INST_IO,asynWfOctetRead,"asynOctetRead") + device(waveform,INST_IO,asynWfOctetWrite,"asynOctetWrite") + device(waveform,INST_IO,asynWfOctetWriteBinary,"asynOctetWriteBinary") + 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") + device(scalcout,INST_IO,asynScalcoutOctetWrite,"asynOctetWrite") + +Support for drivers that implement interface asynOctet. The support is for stringin/stringout +lsi/lso, printf, sCalcout, and waveform records. lsi, lso, and printf are only supported +on EPICS base 3.15 and higher. sCalcout is only supported if CALC module is defined +in configure/RELEASE. The waveform support is similar to the string support. The +waveform records must define FTVL to be CHAR or UCHAR, i.e. it must be an array +of octets. The waveform provides the following features not provided by the string +support: + +- Unlimited size - string records hold a maximum of 40 characters. +- Both string and binary data. Beginning in R4-30 asynWfWriteOctet calls strnlen() + to determine the length of the string, and passes this length to the driver, i.e. + does not include the trailing nil. This is consistent with the behavior of the devAsynOctet + for the stringout record. The asynOctetWriteBinary support added in R4-30 always + uses NORD as the length that it passes to the driver, and does not call strnlen(). + +Four types of support are provided: + +- CmdResponse The INP field is of the form: + :: + + field(INP,"@asyn(portName,addr,timeout) cmd") + + During record initialization, cmd is converted by dbTranslateEscape. The resultant + string is the command to send to the device. When the record is processed the command + is sent to the device and the response read into the record. +- WriteRead The INP field is of the form: + :: + + field(INP,"@asyn(portName,addr,timeout) pvname") + + pvname must refer to a field in a record in the same IOC. During record initialization + the pvname is located. When the record is processed dbGet is called to read the + current value of pvname. This value is sent to the device. A read is then issued + and the result stored in the record. For asynSiOctetWriteRead, the value obtained + from pvname is passed through dbTranslateEscape before sending it. For asynWfOctetWriteRead + it is not passed through dbTranslateEscape. +- Write The INP(OUT) field is of the form: + :: + + field(INP,"@asyn(portName,addr,timeout) drvUser") + + drvUser is information that is passed to the portDriver if it implements interface + asynDrvUser. When the record is processed the value stored in the record is sent + to the device. +- Read The INP field is of the form: + :: + + field(INP,"@asyn(portName,addr,timeout) drvUser") + + drvUser is information that is passed to the portDriver if it implements interface + asynDrvUser. When the record is processed a read request is made. The result is + read into the record. + +Record alarms +~~~~~~~~~~~~~ +The generic EPICS device support sets the record alarm status and severity when +errors occur. Beginning in R4-30 the alarmStatus and alarmSeverity fields were added +to the asynUser structure. Drivers can use these fields to explicitly control the +record STAT and SEVERITY fields, independent of the function return status or the +asynUser.auxStatus field. + +If the pasynUser->alarmStatus or pasynUser->alarmSeverity field is zero then +the record alarm status or severity is controlled by the function return status +or the asynUser.auxStatus field. For records that do not use callbacks (not SCAN=I/O +Intr or asynXXXAverage or asynXXXTimeSeries) the status information is passed from +the driver to device support in the asynStatus return of the interface function +call, e.g. pasynInt32->read(). The driver maps the asynStatus values to the record +STAT and SEVR values using the function pasynEpicsUtils->asynUserToEpicsAlarm(). +The SEVR field is currently always set to INVALID_ALARM for any error. The STAT +field is set using following mapping: +:: + + asynSuccess = epicsAlarmNone + asynTimeout = epicsAlarmTimeout + asynOverflow = epicsAlarmHWLimit + asynError = epicsAlarmRead or epicsAlarmWrite + asynDisconnected = epicsAlarmComm + asynDisabled = epicsAlarmDisable + +For records that use callbacks, the status information is passed from the driver +to device support using the pasynUser->auxStatus field in the pasynUser that +is passed in the callback. This feature was added in asyn R4-19. Prior to that release +it was not possible for drivers to control the alarm state of records that used +callbacks. Drivers should set pasynUser->auxStatus to asynSuccess for normal +operation and to another value to indicate a problem. The same mapping described +above is used to control the values of STAT and SEVR. If the pasynUser->alarmStatus +or pasynUser->alarmSeverity fields are non-zero then these values are used to +set the record STAT and SEVR fields, regardless of the value of asynUser.auxStatus. + +asynRecord: Generic EPICS Record Support +---------------------------------------- +A special record type asynRecord is provided. Details are described in ``__. +This section provides a brief description of how to use it. + +Each IOC can load one or more instances of asynRecord. An example is: +:: + + dbLoadRecords("$(ASYN)/db/asynRecord.db","P=asyn,R=Test,PORT=L0,ADDR=15,IMAX=0,OMAX=0") + +The example creates a record with name "asynTest" (formed from the concatenation +of the P and R macros) that will connect to port "L0" and addr 15. After the ioc +is started, it is possible to change PORT and/or ADDR. Thus, a single record can +be used to access all asyn devices connected to the IOC. Multiple records are only +needed if one or more devices need a dedicated record. + +An medm display is available for accessing an asynRecord. It is started as follows: +:: + + cd /medm + medm -x -macro "P=asyn,R=Test" asynRecord.adl + +The following medm display appears. + +.. figure:: asynRecord.png + :align: center + + **asynRecord.adl** + +asynGpib +-------- +GPIB has additional features that are not supported by asynCommon and asynOctet. +asynGpib defines two interfaces. + +- asynGpib - This is the interface that device support calls. It provides the following: + + - A set of GPIB specific methods that device support can call. + - Code that handles generic GPIB functions like SRQ polling. + - A registerPort method which is called by GPIB port drivers. +- asynGpibPort - A set of methods implemented by GPIB drivers + +asynGpibDriver.h +~~~~~~~~~~~~~~~~ +asynGpibDriver.h contains the following definitions: +:: + + /* GPIB Addressed Commands*/ + #define IBGTL "\x01" /* Go to local */ + #define IBSDC "\x04" /* Selective Device Clear */ + #define IBGET "\x08" /* Group Execute Trigger */ + #define IBTCT "\x09" /* Take Control */ + + /* GPIB Universal Commands*/ + #define IBDCL 0x14 /* Device Clear */ + #define IBLLO 0x11 /* Local Lockout */ + #define IBSPE 0x18 /* Serial Poll Enable */ + #define IBSPD 0x19 /* Serial Poll Disable */ + #define IBUNT 0x5f /* Untalk */ + #define IBUNL 0x3f /* Unlisten */ + + /* Talk, Listen, Secondary base addresses */ + #define TADBASE 0x40 /* offset to GPIB listen address 0 */ + #define LADBASE 0x20 /* offset to GPIB talk address 0 */ + #define SADBASE 0x60 /* offset to GPIB secondary address 0 */ + + #define NUM_GPIB_ADDRESSES 32 + #include "asynDriver.h" + #include "asynInt32.h" + #define asynGpibType "asynGpib" + /* GPIB drivers */ + typedef struct asynGpib asynGpib; + typedef struct asynGpibPort asynGpibPort; + /*asynGpib defines methods called by gpib aware users*/ + struct asynGpib{ + /*addressedCmd,...,ren are just passed to device handler*/ + asynStatus (*addressedCmd) (void *drvPvt,asynUser *pasynUser, + const char *data, int length); + asynStatus (*universalCmd) (void *drvPvt,asynUser *pasynUser,int cmd); + asynStatus (*ifc) (void *drvPvt,asynUser *pasynUser); + asynStatus (*ren) (void *drvPvt,asynUser *pasynUser, int onOff); + /* The following are implemented by asynGpib */ + asynStatus (*pollAddr)(void *drvPvt,asynUser *pasynUser, int onOff); + /* The following are called by low level gpib drivers */ + /*srqHappened is passed the pointer returned by registerPort*/ + void *(*registerPort)( + const char *portName, + int attributes,int autoConnect, + asynGpibPort *pasynGpibPort, void *asynGpibPortPvt, + unsigned int priority, unsigned int stackSize); + void (*srqHappened)(void *asynGpibPvt); + }; + epicsShareExtern asynGpib *pasynGpib; + + struct asynGpibPort { + /*asynCommon methods */ + void (*report)(void *drvPvt,FILE *fd,int details); + asynStatus (*connect)(void *drvPvt,asynUser *pasynUser); + asynStatus (*disconnect)(void *drvPvt,asynUser *pasynUser); + /*asynOctet methods passed through from asynGpib*/ + asynStatus (*read)(void *drvPvt,asynUser *pasynUser, + char *data,int maxchars,int *nbytesTransfered, + int *eomReason); + asynStatus (*write)(void *drvPvt,asynUser *pasynUser, + const char *data,int numchars,int *nbytesTransfered); + asynStatus (*flush)(void *drvPvt,asynUser *pasynUser); + asynStatus (*setEos)(void *drvPvt,asynUser *pasynUser, + const char *eos,int eoslen); + asynStatus (*getEos)(void *drvPvt,asynUser *pasynUser, + char *eos, int eossize, int *eoslen); + /*asynGpib methods passed thrtough from asynGpib*/ + asynStatus (*addressedCmd) (void *drvPvt,asynUser *pasynUser, + const char *data, int length); + asynStatus (*universalCmd) (void *drvPvt, asynUser *pasynUser, int cmd); + asynStatus (*ifc) (void *drvPvt,asynUser *pasynUser); + asynStatus (*ren) (void *drvPvt,asynUser *pasynUser, int onOff); + /*asynGpibPort specific methods */ + asynStatus (*srqStatus) (void *drvPvt,int *isSet); + asynStatus (*srqEnable) (void *drvPvt, int onOff); + asynStatus (*serialPollBegin) (void *drvPvt); + asynStatus (*serialPoll) (void *drvPvt, int addr, double timeout,int *status); + asynStatus (*serialPollEnd) (void *drvPvt); + } + +asynGpib +~~~~~~~~ +asynGpib describes the interface for device support code. It provides gpib specific +functions like SRQ handling. It makes calls to asynGpibPort. asynGpib.c implements +asynCommon and asynOctet. It supports asynInt32 by using the methods from asynInt32Base. +asynInt32 is the way asynGpib reports SRQs to asynUsers. + +An asynUser that wishes to receive SRQs calls pasynInt32->registerInterruptUser +and must set asynUser.reason = ASYN_REASON_SIGNAL. Although most gpib controllers +are multidevice drivers, the VXI11 standard allows for a controller (VXI-11.2) that +attached to a single device, i.e. it is a single address port driver. For such controllers, +the use must specify addr = 0 in order to use SRQs. Also see the vxi support below +for more details. + +.. list-table:: asynGpib + :widths: 20 80 + + * - addressedCmd + - The request is passed to the low level driver. + * - universalCmd + - The request is passed to the low level driver. + * - ifc + - The request is passed to the low level driver. + * - ren + - The request is passed to the low level driver. + * - pollAddr + - Set SRQ polling on or off. onOff = (0,1) means (disable, enable) SRQ polling of + specified address. + * - registerPort + - Register a port. When asynGpib receives this request, it calls asynManager.registerPort. + * - srqHappened + - Called by low level driver when it detects that a GPIB device issues an SRQ. + +asynGpibPort +~~~~~~~~~~~~ +asynGpibPort is the interface that is implemented by gpib drivers, e.g. the VXI-11. +It provides: + +.. list-table:: asynGpibPort + :widths: 20 80 + + * - asynCommon methods + - All the methods of asynCommon + * - asynOctet methods + - All the methods of asynOctet + * - addressedCmd + - Issue a GPIB addressed command. + * - universalCmd + - Issue a GPIB universal command. + * - ifc + - Issue a GPIB Interface Clear command. + * - ren + - Issue a GPIB Remote Enable command + * - srqStatus + - If return is asynSuccess then isSet is (0,1) if SRQ (is not, is) active. Normally + only called by asynGpib. + * - srqEnable + - Enable or disable SRQs. Normally only called by asynGpib. + * - serialPollBegin + - Start of serial poll. Normally only called by asynGpib. + * - serialPoll + - Poll the specified address and set status to the response. Normally only called + by asynGpib. + * - serialPollEnd + - End of serial poll. Normally only called by asynGpib. + +Port Drivers +------------ +Local Serial Port +~~~~~~~~~~~~~~~~~ +The drvAsynSerialPort driver supports devices connected to serial ports on the IOC. + +Serial ports are configured with the ``drvAsynSerialPortConfigure`` and ``asynSetOption`` commands: +:: + + drvAsynSerialPortConfigure("portName","ttyName",priority,noAutoConnect,noProcessEosIn) + asynSetOption("portName",addr,"key","value") + +where the arguments are: + +- portName + + - The portName that is registered with asynGpib. +- ttyName + + - The name of the local serial port (e.g. "/dev/ttyS0", "COM1"). +- priority + + - Priority at which the asyn I/O thread will run. If this is zero or + missing,then epicsThreadPriorityMedium is used. +- addr + + - This argument is ignored since serial devices are configured with multiDevice=0. +- noAutoConnect + + - Zero or missing indicates that portThread should automatically + connect. Non-zero if explicit connect command must be issued. +- noProcessEos + + - If 0 then asynInterposeEosConfig is called specifying both processEosIn + and processEosOut. + +The setEos and getEos methods have no effect and return asynError. The read method +blocks until at least one character has been received or until a timeout occurs. +The read method transfers as many characters as possible, limited by the specified +count. asynInterposeEos can be used to support EOS. + +The following table summarizes the drvAsynSerialPort driver asynSetOption keys and +values. When a serial port connects the current values are fetched. + +.. list-table:: Local serial port + :widths: 20 80 + :header-rows: 1 + + * - Key + - Value + * - baud + - 50 75 110 134 150 200 300 600 1200 2400 9600 ... + * - bits + - 8 7 6 5 + * - parity + - none even odd + * - stop + - 1 2 + * - clocal + - Y N + * - crtscts + - N Y + * - ixon + - N Y + * - ixoff + - N Y + * - ixany + - N Y + * - rs485_enable + - N Y + * - rs485_rts_on_send + - N Y + * - rs485_rts_after_send + - N Y + * - rs485_delay_rts_before_send + - msec_delay + * - rs485_delay_rts_after_send + - msec_delay + +On some systems (e.g. Windows, Darwin) the driver accepts any numeric value for +the baud rate, which must, of course be supported by the system hardware. On Linux +the choices are limited to the values like B300, B9600, etc. which are defined in +/usr/include/bits/termios.h. + +The clocal and crtscts parameter names are taken from the POSIX termios serial interface +definition. The clocal parameter controls whether the modem control lines (Data +Terminal Ready, Carrier Detect/Received Line Signal Detect) are used (clocal=N) +or ignored (clocal=Y). The crtscts parameter controls whether the hardware handshaking +lines (Request To Send, Clear To Send) are used (crtscts=Y) or ignored (crtscts=N). + +The vxWorks sioLib serial support does not provide support for modem control lines. +It also uses clocal for what is actually crtscts. For vxWorks the standard serial +support accepts both clocal and crtscts for getOption and setOption. clocal=Y implies +crtscts=N and clocal=N implies crtscts=Y. + +ixon controls XON/OFF flow control on output. If the IOC receives an XOFF character, +it suspends output until an XON character is received. This option is also supported +on ports communicating via the RFC 2217 Telnet protocol. In this case, as noted +in the standard, ixon implies both outbound and inbound flow control. + +ixoff controls XON/OFF flow control on input. The IOC sends XOFF and XON characters +as necessary to prevent input from coming in faster than programs are reading it. +The external device sending the input data must respond to an XOFF character by +suspending transmission, and to an XON character by resuming transmission. + +The ixany flag allows any input character to restart output when output has been +suspended with the XOFF character. Otherwise, only the XON character restarts output. +This flag is not available on all systems, including WIN32. + +The rs485 options are only supported on Linux, only kernels ≥ 2.6.35, and only +on hardware ports that support RS-485. The delay option units are integer milliseconds. + +vxWorks IOC serial ports may need to be set up using hardware-specific commands. +Once this is done, the standard drvAsynSerialPortConfigure and asynSetOption commands +can be issued. For example, the following example shows the configuration procedure +for a port on a GreenSprings octal UART Industry-Pack module on a GreenSprings VIP616-01 +carrier. +:: + + ipacAddVIPC616_01("0x6000,B0000000") + tyGSOctalDrv(1) + tyGSOctalModuleInit("Mod0","232", 0x80, 0, 0) + tyGSOctalDevCreate("/tyGS/0/0","Mod0",0,0,1000,1000) + drvAsynSerialPortConfigure("/tyGS/0/0","/tyGS/0/0",0,0,0) + asynSetOption("/tyGS/0/0",0,"baud","9600") + + For the IP520: + + IP520Drv(1) + IP520ModuleInit("UART_0", "232", 0xC2, 0, 0) + IP520DevCreate("A1", "UART_0", 0, 0, 1000, 1000) + drvAsynSerialPortConfigure("A1","A1",0,0,0) + asynSetOption("A1",0,"baud",9600) + asynOctetSetInputEos( "A1",0,"\r") + asynOctetSetOutputEos("A1",0,"\r") + +TCP/IP or UDP/IP Port +~~~~~~~~~~~~~~~~~~~~~ +The drvAsynIPPort driver supports devices which communicate over a TCP/IP or UDP/IP +connection. A typical example is a device connected through an Ethernet/Serial converter +box. + +TCP/IP or UDP/IP connections are configured with the ``drvAsynIPPortConfigure`` +command: +:: + + drvAsynIPPortConfigure("portName","hostInfo",priority,noAutoConnect,noProcessEos) + +where the arguments are: + +- portName + + - The portName that is registered with asynManager. +- hostInfo + + - The Internet host name, port number, optional local port number, and + optional IP protocol of the device. The format is: + :: + + :[:localPort] [protocol] + + (e.g. "164.54.9.90:4002", "164.54.9.90:4001:10101", "serials8n3:4002", "serials8n3:4002 + TCP" or "164.54.17.43:5186 udp"). If no protocol is specified, TCP will be used. + +Possible protocols are + +- TCP +- TCP& -- Like TCP but use the SO_REUSEPORT socket option. +- UDP +- UDP& -- Like UDP but use the SO_REUSEPORT socket option. +- UDP* -- Send UDP broadcasts. The address portion of the argument must be the network + broadcast address (e.g. "192.168.1.255:1234 UDP*", or "255.255.255.255:1234 UDP*", etc.) +- UDP*& -- Like UDP* but use the SO_REUSEPORT socket option. +- HTTP -- Like TCP but for servers which close the connection after each transaction. +- COM -- For Ethernet/Serial adapters which use the TELNET RFC 2217 protocol. This + allows port parameters (speed, parity, etc.) to be set with subsequent asynSetOption + commands just as for local serial ports. The default parameters are 9600-8-N-1 with + no flow control. + +If the hostInfo argument begins with the characters **unix://** the remainder of the argument +is taken to be the name of a UNIX-domain stream socket. + +`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. + +To receive UDP broadcasts the localPort is the port to listen on, for example: +``drvAsynIPPortConfigure("BD","255.255.255.255:1234:3956 UDP*",0,0,0)``. +If the port is only to be used to receive broadcast messages then +the UDP protocol should be specified. If it is also to be used to send UDP broadcasts +then the UDP* protocol must be specified. In this case the broadcasts will be send +on port "port" and it will listen for broadcast messages on port "localPort". +Note that the localPort should almost never be used for TCP ports because normally +the local host choses an unused random local port that it binds to and passes to +the server. However, there are some unusual servers that only accept a specific +local port or range of local ports, in which case localPort must be specified. +- priority - Priority at which the asyn I/O thread will run. If this is zero or +missing, then epicsThreadPriorityMedium is used. + +- noAutoConnect + + - Zero or missing indicates that portThread should automatically + connect. + - Non-zero if explicit connect command must be issued. +- noProcessEos + + - If 0 then asynInterposeEosConfig is called specifying both processEosIn + and processEosOut. + +Only asynOctet methods write, read, and flush are implemented. Calling the other +methods will result in an error unless asynInterposeEos is used for the other asynOctet +methods. read blocks until at least one character has been received or until a timeout +occurs. read transfers as many characters as possible, limited by the specified +count. + +The following table summarizes the drvAsynIPPort driver asynSetOption keys and values. + + +.. list-table:: TCP/IP or UDP/IP Port + :widths: 10 10 60 + :header-rows: 1 + + * - Key + - Value + - Description + * - disconnectOnReadTimeout + - N Y + - Default=N. If Y then if a read operation times out the driver automatically disconnect + the IP port. + * - hostInfo + - :[:localPort] [protocol] + - The IP port hostInfo specification using the same syntax as drvAsynIPPortConfigure. + This option 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. + +In addition to these key/value pairs if the COM protocol is used then the drvAsynIPPort +driver uses the same key/value pairs as the drvAsynSerialPort driver for specifying +the serial parameters, i.e. "baud", "bits", etc. + +asynInterposeEos and asynInterposeFlush can be used to provide additional functionality. + +TCP/IP Server +~~~~~~~~~~~~~ +The drvAsynIPServerPort driver supports asyn socket servers by listening for TCP/IP +or UDP connections from remote clients. The creates maxClients drvAsynIPPort port +drivers by calling drvAsynIPPortConfigure at initialization. These ports are named +portName:0, portName:1, etc. where portName is the name passed to drvAsynIPServerPortConfigure. + +IP server listeners are configured with the ``drvAsynIPServerPortConfigure`` +command: +:: + + drvAsynIPServerPortConfigure("portName", "serverInfo", maxClients, priority, noAutoConnect, noProcessEos); + +where the arguments are: + +- portName + + - The portName that is registered with asynManager. +- serverInfo + + - The Internet host name and port number to listen for connections + on (e.g. "localhost:4002" for TCP, "localhost:4002 UDP" for UDP). This allows to + specify a host name or ip address for multi-homed machines. If you want to specify + ***any*** interface, use the example "localhost:port", an empty host + ":port" or the any 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 + complain and fail. If you need the loopback interface, use "127.0.0.1:port". + +- maxClients + + - The maximum number of IP clients that can be simultaneously connected + on this port. Additional connect requests will fail. +- priority + + - Priority at which the listener thread and any asyn I/O ports it creates + will run. If this is zero or missing, then epicsThreadPriorityMedium is used. +- noAutoConnect + + - Zero or missing indicates that the listener port should automatically + connect. Non-zero if explicit connect command must be issued. Note that all asyn + I/O ports that the listener thread creates will be created with noAutoConnect=1, + but this is transparent to socket server applications, because the listener thread + does the explicit connection for them. +- noProcessEos is passed to drvAsynIPPortConfigure when new asyn I/O ports are created. + If 0 then asynInterposeEosConfig is called specifying both processEosIn and processEosOut. + + +This driver implements the asynOctet interface. For TCP connections the only methods +it supports are registerInterruptUser and cancelInterruptUser. Calling the other +asynOctet methods will result in an error. For UDP it implements asynOctet->read(). +The following happens when a new connection is received on the port specified in +drvAsynIPServerPortConfigure: + +- The list of drvAsynIPPort ports that this listener thread has created is searched + to see if there is a drvAsynIPPort that is currently disconnected because there + is no remote IP client connected. +- If there is a disconnected port, then it is connected with the file descriptor + from the new IP connection. +- If there are no disconnected ports then the incoming connection will be immediately closed. +- The asynTraceMask and asynTraceIOMask of the newly connected port are set to the + current values of the listener thread port. This makes it possible to trace the + early stages of execution of the callbacks to the registered clients, before one + could enable tracing at iocsh. +- All registered asyn clients (who have called registerInterruptUser on the asynOctet + interface of the listener port) are called back with the name of the newly connected + port. + +VXI-11 +~~~~~~ +VXI-11 is a TCP/IP protocol for communicating with IEEE 488.2 devices. It is an +RPC based protocol. In addition to the VXI-11 standard, three additional standards +are defined. + +- VXI-11.1 - A standard for communicating with VXIbus devices. These controllers + have a vxiName that starts with "vxi" and can control multiple devices, i.e. the + port driver will be a multiaddress driver. +- VXI-11.2 - A standard for communicating with a IEEE 488.1 device. This means that + the TCP/IP connection is talking to a GPIB controller that is talking to a GPIB + bus. These devices have an vxiName that starts with "gpib". Note that the Agilent + E2050A does not follow the standard. For it the vxiName must be "hpib" +- VXI-11.3 - A standard for communicating with IEEE 488.2 devices. This means that + the TCP/IP connection is talking directly with an device. These devices have an + vxiName that starts with "inst". These controllers can control only a single device, + i.e. the port driver will be a single address driver + +*NOTES* + +- No VXI-11.1 controller has been tested. +- The following VXI-11.2 controllers have been tested: Agilent E2050 and E5810 +- The following VXI-11.3 instruments have been tested: + + - Tektronix TDS3054B scope. + + SRQs do not work. Do not know why + + - Tektronix TDS5054B scope. + + SRQs do work. The asynUser MUST specify addr = 0. Also do NOT set bit 0x40 of Service + Request Enable register, i.e. cause SRQ when device has output available. This did + not work and can cause infinite set of SRQs + +Consult the following documents (available on-line) for details. +:: + + VMEbus Extensions for Instrumentation + VXI-11 TCP/IP Instrument Protocol Specification + VXI-11.1 TCP/IP-VXIbus Interface Specification + VXI-11.2 TCP/IP-IEEE 488.1 Interface Specification + VXI-11.3 TCP/IP-IEEE 488.2 Instrument Interface Specification + +The following commands may be specified in the st.cmd file +:: + + E2050Reboot("inet_addr") + E5810Reboot("inet_addr","password") + vxi11Configure("portName","inet_addr",flags,"timeout","vxiName",priority,noAutoConnect) + +where + +- inet_addr - Internet Address +- password - password. If given as 0 the default E5810 is used. +- portName - The portName that is registered with asynGib. +- flags - Bitmap + + - Bit 0 (0x1) recoverWithIFC - (0,1) => (don't, do) issue IFC when error occurs. + - Bit 1 (0x2) lockDevices - (0,1 ) => (don't, do) lock devices when creating + the link. + - Bit 2 (0x4) noSRQ - (0,1 ) => (do, don't) set up a VXI-11 SRQ channel. + + +- timeout + + - I/O operation timeout in seconds as a string. Prior to release R4-16 + this was a double, but was changed to a string because it is not safe to pass doubles + on the vxWorks shell. If "0.0", then a default is assigned. +- vxiName + + - Must be chosen as specified above. NOTE: For the Agilent E2050 vxiName + must be "hpib". For the Agilent E5810 use the name "gpib0". For an instrument that + supports VXI11 try "inst0". +- priority + + - Priority at which the asyn I/O thread will run. If this is zero or + missing, then epicsThreadPriorityMedium is used. +- noAutoConnect + + - Zero or missing indicates that portThread should automatically + connect. Non-zero if explicit connect command must be issued. + +The vxi11 driver implements two timeouts: ioTimeout and rpcTimeout (Remote Procedure +Call timeout). The ioTimeout is taken from asynUser:timeout. The rpcTimeout is handled +internally for each port. It has a default of 4 seconds but can be changed by calling +setOptions. For example: +:: + + asynSetOption L0 -1 rpctimeout .1 + +Will change the rpcTimeout for port L0 to .1 seconds. + +drvPrologixGPIB +~~~~~~~~~~~~~~~ +The drvPrologixGPIB port driver was written to support +`the Prologix GPIB-Ethernet controller `__. + +Configuration command is: +:: + + prologixGPIBConfigure(portName,host,priority,noAutoConnect) + +where + +- portName + + - An ascii string specifying the port name that will be registered with + asynDriver. +- host + + - The IP address or IP name and port number of the Prologix GPIB-Ethernet + controller. The port number is factory assigned to 1234. +- priority + + - An integer specifying the priority of the port thread. A value of 0 + will result in a default value being assigned. +- noAutoConnect + + - Non-zero indicates that portThread should automatically connect. + - Zero means explicit connect command must be issued. + +An example is: +:: + + prologixGPIBConfigure("L0","gse-prologix:1234",0,0) + +**NOTES** +The Prologix GPIB-Ethernet is a simple device that does not support many GPIB functions. + +- SRQ is not supported. +- SerialPoll is not supported. +- AddressedCMD is not supported. +- UniversalCMD is not supported. +- REN (remote enable) is not supported. + +Linux-Gpib +~~~~~~~~~~ + +The linux-gpib port driver was written to support +`the Linux GPIB Package library `__. + +In order to build this support the Linux GPIB Package must be installed. Also in +configure/RELEASE the statement: +:: + + LINUX_GPIB=NO + +must be changed to +:: + + LINUX_GPIB=YES + +Configuration command is: +:: + + GpibBoardDriverConfig(portName,autoConnect,BoardIndex,timeout,priority) + +where + +- portName + + - An ascii string specifying the port name that will be registered with + asynDriver. +- noAutoConnect + + - Non-zero indicates that portThread should automatically connect. + - Zero means explicit connect command must be issued. +- boardIndex + + - Integer containing index of board (0 means /dev/gpib0). Normally it + is 0. This must be the same as in gpib.conf file (minor number - board index) of + driver configuration. +- timeout + + - Time in seconds in which an i/o operation must complete. Zero means + disabled. This is "general" timeout for every call to low level drivers. For actual + read/write operations timeout must be defined in device support. Both timeouts are + converted into integers 0-17 which represents disabled to 1000 seconds. +- priority + + - An integer specifying the priority of the port thread. A value of 0 + will result in a default value being assigned. + +An example is: +:: + + GpibBoardDriverConfig("L0",1,0,3,0) + +**NOTES:** + +- AsynOption Interface is supported. Key (hexadecimal) and val (integer) arguments + to setPortOptions function must be appropriate values represented as character arrays. + See GPIB library documentation for details. +- pgpibCmd type GPIBREADW and GPIBEFASTIW were not tested. +- The linux-port driver was tested with PC104-GPIB board from Measurement Computing. + +Green Springs IP488 +~~~~~~~~~~~~~~~~~~~ + +This is support for the Green Springs Industry Pack GPIB carrier. The configuration +command is: +:: + + gsIP488Configure(portName,carrier,module,intVec,priority,noAutoConnect) + +where + +- portName + + - An ascii string specifying the port name that will be registered with + asynDriver. +- carrier + + - An integer identifying the Industry Pack Carrier +- module + + - An integer identifying the module on the carrier +- intVec + + - An integer specifying the interrupt vector +- priority + + - An integer specifying the priority of the portThread. A value of 0 + will result in a defalt value being assigned +- noAutoConnect + + - Zero or missing indicates that portThread should automatically connect. + - Non-zero if explicit connect command must be issued. + + +An example is: +:: + + #The following is for the Greensprings IP488 on an MV162 + ipacAddMVME162("A:l=3,3 m=0xe0000000,64") + gsIP488Configure("L0",0,0,0x61,0,0) + +**WARNING:** + +This module includes code that implement a 6 microsecond delay because the gpib +interface chip requires it. The first time gsIP488Configure is executed code is +run to determine a variable used by the delay routine. It assumes that there is +no higher priority thread running that consumes lots of cpu cycles. + + +National Instruments GPIB-1014D +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is support for a National Instruments VME GPIB interface. The configuration +command is: +:: + + ni1014Config(portNameA,portNameB,base,vector,level,priority,noAutoConnect) + +where + +- portNameA + + - An ascii string specifying the port name that will be registered with + asynDriver for portA. +- portNameB + + - An ascii string specifying the port name that will be registered with + asynDriver for portB. If only one port should be registered, then leave this as + a null string. The support should also work for a single port NI1014 but has not + been tested. +- base + + - VME A16 base address. +- vector + + - VME interrupt vector. +- level + + - An integer specifying the interrupt level. +- priority + + - In integer specifying the priority of the portThread. A value of 0 + will result in a defalt value being assigned +- noAutoConnect + + - Zero or missing indicates that portThread should automatically + connect. Non-zero if explicit connect command must be issued. + +An example is: +:: + + ni1014Config("L0","L1",0x5000,0x64,5,0,0) + +**NOTES:** + +- Ports A and B are almost but not quite the same. Thus the code for connecting + to port A is slightly different than the code for portB. +- In order to disconnect and reconnect either port, BOTH ports must be disconnected + and reconnected. +- When the ports are connected, portA MUST be connected before port B. +- Programmed I/O, via interrupts, rather than DMA is implemented. Thus no A24 address + space is required. + +**WARNING:** + +This module includes code that implement a 6 microsecond delay because the gpib +interface chip requires it. The first time ni1014Config is executed code is run +to determine a variable used by the delay routine. It assumes that there is no higher +priority thread running that consumes lots of cpu cycles. + +USB TMC (Test and Measurement Class) driver +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Configure each instance of the driver in the application startup script: +:: + + usbtmcConfigure("asynPort", vendorId, productId, "serialNumber", priority, flags) + +The ``asynPort`` and ``serialNumber`` arguments are strings and the other +arguments are integers. A missing or 0 ``vendorId`` or ``productId`` matches +any value and a missing or empty ``serialNumber`` string matches any value. +Thus the command: +:: + + usbtmcConfigure("usbtmc1") + +will associate ASYN port usbtmc1 with the first USB TMC device discovered. A missing +or 0 priority will set the worker thread priority to its default value of 50 (``epicsThreadPriorityMedium``). + +A missing flags argument is taken to be 0. As of now only one bit is used: Bit 0 +(0x1) Disable/enable (1/0) automatic port connection. + +Non-octet records +................. +In addition to the asynOctet stream this support module provides some values for +records with DTYP=asynInt32. Since the port is a single-address device the subaddress +field of the INP or OUT '@asyn()' descriptor can not be used. Instead the 'drvUser' +string at the end of the INP or OUT field is used to distinguish the parameter to +be read or written. + +Service Request (SRQ) handling +.............................. +The presence of one or more records with INP="@asyn(port, 0, 0) SRQ") will cause +the driver to create an extra thread to read from the device Interrupt-In endpoint. +The SCAN field must be "I/O Intr". Record processing will occur when the device +sends a service request message on the Interrupt-In endpoint and the value will +be the device status byte sent as part of the service request message. Typically +the record type will be longin or mbbiDirect. + +Device Status Byte (STB) +........................ + +The USBTMC/USB488 device status byte is read by a record with +:: + + INP="@asyn(port, 0, 0) STB"). + +Typically the record type will be longin or mbbiDirect. + +Remote Enable (REN) +................... +The device remote enable is written by a record with +:: + + OUT="@asyn(port, 0, 0) REN") + +Typically the record type will be bo but writing any non-zero value enables remote +operation. + +Local Lockout (LLO) +................... +The IEEE-488 local lockout command is sent by processing a record with +:: + + OUT="@asyn(port, 0, 0) LLO") + +Typically the record type will be bo. The value written is ignored. + +Go To Local (GTL) +................. +The IEEE-488 go to local command is sent by processing a record with +:: + + OUT="@asyn(port, 0, 0) GTL") + +Typically the record type will be bo. The value written is ignored. + +Linux udev configuration +........................ +If attempts to communicate with a device result in error messages of the form "Access +denied (insufficient permissions)" you must add udev entries to allow access. In +the /etc/udev/rules.d directory create a file, 55-usbtmc.rules for example, with +a line for each device of interest. + +To allow everyone in the "usbtmc" group access to a device with vendor code 1BFA +(hexadecimal) and product code 0498 (hexadecimal) the line would look like: +:: + + SUBSYSTEM=="usb", ATTRS{idVendor}=="1BFA", ATTRS{idProduct}=="0498", GROUP="usbtmc", MODE="0660" + +To allow everyone access the line would look like: +:: + + SUBSYSTEM=="usb", ATTRS{idVendor}=="1BFA", ATTRS{idProduct}=="0498", MODE="0666" + +The ``{idVendor}`` and ``{idProduct}`` values must match those of the +device with which you wish to communicate. + +StreamDevice Exception Handlers +............................... +The USBTMC driver attempts to take correct action when it detects that the device +has been unplugged or become unresponsive. The effectiveness of this depends somewhat +on the level of support provided by the underlying operating system so it is good +practice to also specify the following StreamDevice global exception handlers: +:: + + @mismatch { disconnect; } + @writetimeout { disconnect; } + @readtimeout { disconnect; } + @replyTimeout { disconnect; } + +FTDI Port +~~~~~~~~~ +The drvAsynFTDIPort driver supports devices connected via FTDI adapters. + +FTDI ports are configured with the ``drvAsynFTDIPortConfigure`` and ``asynSetOption`` +commands: +:: + + drvAsynFTDIPortConfigure("portName",vendor,product,baudrate,latency,priority,noAutoConnect,noProcessEos,mode) + asynSetOption("portName",addr,"key","value") + +where the arguments are: + +- portName + + - The portName that is registered with asyn. +- vendor + + - The USB vendor number associated with the FTDI device. +- product + + - The USB product number associated with the FTDI device. +- baudrate + + - The baudrate to be used with the FTDI device. +- latency + + - The latency timer after which non-full FTDI buffers are sent. +- priority + + - Priority at which the asyn I/O thread will run. If this is zero or + missing,then epicsThreadPriorityMedium is used. +- noAutoConnect + + - Zero or missing indicates that portThread should automatically connect. + - Non-zero if explicit connect command must be issued. +- noProcessEos + + - If 0 then asynInterposeEosConfig is called specifying both processEosIn + and processEosOut. +- mode: + + - 0 = UART; + - 1 = FTDI initialized in binary SPI mode. + +The setEos and getEos methods have no effect and return asynError. The read method +blocks until at least one character has been received or until a timeout occurs. +The read method transfers as many characters as possible, limited by the specified +count. asynInterposeEos can be used to support EOS. + + +The following table summarizes the drvAsynFTDIPort driver asynSetOption keys and +values. Reasonable defaults are used at first. + +.. list-table:: FTDI driver + :widths: 10 10 60 + :header-rows: 1 + + * - Key + - Value + - Note + * - baud + - 50 75 110 134 150 200 300 600 1200 2400 9600 ... + - Any numeric value. Check chip datasheet for actual supported baud rates. + * - bits + - 8 7 + - + * - parity + - none even odd mark space + - + * - stop + - 1 1.5 2 + - + * - break + - off on + - + * - flow + - rts_cts dtr_dsr xon_xoff + - Values can be OR'ed together, e.g., ``rts_cts|dtr_dsr`` + +The FTDI SPI interface was developed for control of evaluation board, EVAL-AD9915, +via Adafruit FT232H. During initial SPI learning it is sufficient to short circuit, +(loop-back), FTDI D1(MOSI) - D2(MISO) pins and read back written values. (Note the +SPI is synchronous interface, not asynchronous.) + +AD9915 provides basic control for RF amplitude and phase. In order to use the Adafruit +as USB - SPI converter for EVAL-AD9915 the following pins need to be connected: + +.. list-table:: Adafruit FT232H EVAL-AD9915 connections + :widths: 20 80 + :header-rows: 1 + + * - Adafruit FT232H + - EVAL-AD9915 + * - D0 (SPI Clock, SK) + - SCLK-BUF + * - D1 (Data Out, MOSI) + - SDIO + * - D2 (Data In, MISO) + - SDO + * - D3 (Chip Select, CS) + - CSB + * - D4 + - IOUPDATE-BUF + * - D5 + - SYNC_IO + * - D6 + - RESET + +On EVAL-AD9915 board: + +1. The on-board USB-SPI converter, (lacking open source driver), + should be disabled by jumpers P203-P205. +2. The following jumpers need to be configured: + EXTPDCTL=GND; PS0-BUF=GND; PS1-BUF=GND; PS2-BUF=GND; IOCFG=+5V; IOCFG1...3=GND. + +The FTDI SPI driver supports raw 32-bit integer reads/writes. MPSSE instruction +codes, pin controls, data lengths are currently hard coded in the stream protocol: +(WRite Digital Output, WRite PIN, ReaD Digital Input): +:: + + WRDO { + # MPSSE_DO_WRITE | MPSSE_WRITE_NEG | MPSSE_DO_READ = 0x31 + # Length = 0x04 bytes after the instruction code and 2 length bytes: + out 0x31 0x04 0x00 $1 "%.4r"; + } + + WRPIN { + # SK = 0x01 + # DO = 0x02 + # DI = 0x04 + # CS = 0x08 + # IO_UPD = 0x10 + # SYNCIO = 0x20 + # RESET = 0x40 + # PINDIR = 0x7B + # SET_BITS_LOW = 0x80 + out 0x80 "%r" 0x7B; + } + + RDDI { + # MPSSE_DO_WRITE | MPSSE_WRITE_NEG | MPSSE_DO_READ = 0x31 + # Length = 0x04 bytes after the instruction code and 2 length bytes: + # Input is clocked in while the 0 bytes are clocked out: + out 0x31 0x04 0x00 $1 0x00 0x00 0x00 0x00; + in "%5r"; + } + +The sequences are controlled by EPICS database. For further details refer to the +respective technical manuals. + +asynPortDriver C++ base class +----------------------------- +A C++ base class called asynPortDriver is available. This is a base class from which +real asyn port drivers can be derived. It greatly simplifies the job of writing +an asyn port driver, because it takes care of all of the tasks like registering +the port, registering the interfaces, and calling interrupt clients. It is documented +separately in `asynPortDriver `__. + + +asynPortClient C++ classes +-------------------------- +asynPortClient is a set of C++ classes that are designed to simplify the task of +writing a client that directly communicates with an asyn port driver, without running +an EPICS IOC. They handle the details of connecting to the driver, finding the required +interfaces, etc. They only uses the synchronous interfaces, so all calls are blocking. +If clients need asynchronous operation then they can use the normal C interface +with pasynManager->queueRequest. It is documented separately in `asynPortClient `__. + +Diagnostic Aids +--------------- +iocsh Commands +~~~~~~~~~~~~~~ +:: + + asynReport(level,portName) + asynInterposeFlushConfig(portName,addr,timeout) + asynInterposeEosConfig(portName,addr,processIn,processOut) + asynSetTraceMask(portName,addr,mask) + asynSetTraceIOMask(portName,addr,mask) + asynSetTraceInfoMask(portName,addr,mask) + asynSetTraceFile(portName,addr,filename) + asynSetTraceIOTruncateSize(portName,addr,size) + asynSetOption(portName,addr,key,val) + asynShowOption(portName,addr,key) + asynAutoConnect(portName,addr,yesNo) + asynSetAutoConnectTimeout(timeout) + asynWaitConnect(portName, timeout) + asynEnable(portName,addr,yesNo) + asynOctetConnect(entry,portName,addr,timeout,buffer_len,drvInfo) + asynOctetRead(entry,nread) + asynOctetWrite(entry,output) + asynOctetWriteRead(entry,output,nread) + asynOctetFlush(entry) + asynOctetSetInputEos(portName,addr,eos,drvInfo) + asynOctetGetInputEos(portName,addr,drvInfo) + asynOctetSetOutputEos(portName,addr,eos,drvInfo) + asynOctetGetOutputEos(portName,addr,drvInfo) + asynRegisterTimeStampSource(portName,functionName); + asynUnregisterTimeStampSource(portName) + +``asynReport`` calls ``asynCommon:report`` for a specific port +if portName is specified, or for all registered drivers and interposeInterface if +portName is not specified. + +``asynInterposeFlushConfig`` is a generic interposeInterface that implements +flush for low level drivers that don't implement flush. It just issues read requests +until no bytes are left to read. The timeout is used for the read requests. + +``asynInterposeEosConfig`` is a generic interposeInterface that implements +End of String processing for low level drivers that don't. + +``asynSetTraceMask`` calls ``asynTrace:setTraceMask`` for the +specified port and address. If portName is zero length then the global trace mask +is set. The mask bit definitions are documented in the +`traceMask definitions <#asyntrace>`__. + +``asynSetTraceIOMask`` calls ``asynTrace:setTraceIOMask`` for +the specified port and address. If portName is zero length then the global traceIO +mask is set. The mask bit definitions are documented in the +`traceIO mask definitions <#asyntrace>`__. + +``asynSetTraceInfoMask`` calls ``asynTrace:setTraceInfoMask`` +for the specified port and address. If portName is zero length then the global traceInfo +mask is set. The mask bit definitions are documented in the +`traceInfo mask definitions <#asyntrace>`__. + +Beginning with asyn R4-35 the mask argument of asynSetTraceMask, asynSetTraceIOMask, +and asynSetTraceInfoMask can be specified either 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 are not case sensitive +and the prefixes ASYN\_, TRACE\_, TRACEIO\_, and TRACEINFO\_ are optional. Examples: +:: + + asynSetTraceMask port,0,ASYN_TRACE_ERROR + asynSetTraceIOMask port,0,ascii+escape + asynSetTraceInfoMask port,0,1+port+TRACEINFO_SOURCE|ASYN_TRACEINFO_THREAD + +``asynSetTraceFile`` calls ``asynTrace:setTraceFile``. The filename +is handled as follows: + +- Not specified - A NULL pointer is passed to setTraceFile. Subsequent messages + are sent to errlog. +- An empty string ("") or "stderr" - stderr is passed to setTraceFile. +- "stdout" - stdout is passed to setTraceFile. +- Any other string - The specified file is opened with an option of "w" and the + file pointer is passed to setTraceFile. + + +``asynSetTraceIOTruncateSize`` calls ``asynTrace:setTraceIOTruncateSize`` + +``asynSetOption`` calls ``asynCommon:setOption``. + +``asynShowOption`` calls ``asynCommon:getOption``. + +The asynOctetXXX commands provide shell access to asynOctetSyncIO methods. The entry +is a character string constant that identifies the port,addr. + +The other arguments are as follows: + +.. list-table:: asynOctetXXX command arguments + :widths: 20 80 + :header-rows: 1 + + * - Argument name + - Value + * - filename + - An ascii string naming a file. If null or a null string, then the output + is sent to ``stdout.`` + * - level + - The report level. + * - portName + - An ascii string specifying the portName of the driver. + * - addr + - An integer specifying the address of the device. For multiDevice ports + a value of -1 means the port itself. For ports that support a single device, addr + is ignored. + * - mask + - The mask value to set. See the mask bit definitions in asynDriver.h + * - key + - The key for the option desired. + * - val + - The value for the option. + * - yesNo + - The value (0,1) means (no,yes). + * - entry + - A character string that identifies the asynOctetConnect request. + * - timeout + - timeout as an integer in milliseconds. The default is 1. + * - buffer_len + - length of buffer for I/O. Default=160. NOTE: output strings passed + to asynOctetWrite can have escape characters. The buffer_len must be large enough + to handle escape characters. For example if \x02 appears in an output string it + counts as four characters. + * - drvInfo + - A string to pass to the driver via interface asynDrvUser. + * - nread + - max number of bytes to read. Default=buffer_len. + * - flush + - (0,1) means (don't, do) flush before reading. Default=0. + * - output + - output string. + +The commands asynOctetConnect, asynOctetDisconnect, asynOctetRead, asynOctetWrite, +asynOctetWriteRead, asynOctetFlush allow I/O to a device from the ioc shell. Examples +are: +:: + + asynOctetConnect("myid","A",0,1,20) + asynOctetWrite("myid","testnew") + asynOctetRead("myid") + testnew\n + asynOctetWriteRead("myid","this is test") + this is test\n + asynOctetDisconnect("myid") + +``asynRegisterTimeStampSource`` calls ``pasynManager->registerTimeStampSource`` +for the specified port. The time stamp source function must be defined as a "function" +in the application dbd file. + +``asynUnregisterTimeStampSource`` calls ``pasynManager->runegisterTimeStampSource`` +for the specified port. This reverts to the default timestamp source function in +asynManager. + +Example Client +-------------- +The following is an example of an asyn client that reads from an asyn driver via +octet messages: +:: + + #include + ... + #define BUFFER_SIZE 80 + typedef struct myData { + epicsEventId done; + asynOctet *pasynOctet; + void *drvPvt; + char buffer[BUFFER_SIZE]; + }myData; + + static void queueCallback(asynUser *pasynUser) { + myData *pmydata = (myData *)pasynUser->userPvt; + asynOctet *pasynOctet = pmydata->pasynOctet; + void *drvPvt = pmydata->drvPvt; + asynStatus status; + int writeBytes,readBytes; + int eomReason; + + asynPrint(pasynUser,ASYN_TRACE_FLOW,"queueCallback entered\n"); + status = pasynOctet->write(drvPvt,pasynUser,pmydata->buffer, + strlen(pmydata->buffer),&writeBytes); + if(status!=asynSuccess) { + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "queueCallback write failed %s\n",pasynUser->errorMessage); + } else { + asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE, + pmydata->buffer,strlen(pmydata->buffer), + "queueCallback write sent %d bytes\n",writeBytes); + } + status = pasynOctet->read(drvPvt,pasynUser,pmydata->buffer, + BUFFER_SIZE,&readBytes,&eomReason); + if(status!=asynSuccess) { + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "queueCallback read failed %s\n",pasynUser->errorMessage); + } else { + asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE, + pmydata->buffer,BUFFER_SIZE, + "queueCallback read returned: retlen %d eomReason 0x%x data %s\n", + readBytes,eomReason,pmydata->buffer); + } + epicsEventSignal(pmydata->done); + } + + static void asynExample(const char *port,int addr,const char *message) + { + myData *pmyData; + asynUser *pasynUser; + asynStatus status; + asynInterface *pasynInterface; + + pmyData = (myData *)pasynManager->memMalloc(sizeof(myData)); + memset(pmyData,0,sizeof(myData)); + strcpy(pmyData->buffer,message); + pasynUser = pasynManager->createAsynUser(queueCallback,0); + pasynUser->userPvt = pmyData; + status = pasynManager->connectDevice(pasynUser,port,addr); + if(status!=asynSuccess) { + printf("can't connect to serialPort1 %s\n",pasynUser->errorMessage); + exit(1); + } + pasynInterface = pasynManager->findInterface( + pasynUser,asynOctetType,1); + if(!pasynInterface) { + printf("%s driver not supported\n",asynOctetType); + exit(-1); + } + pmyData->pasynOctet = (asynOctet *)pasynInterface->pinterface; + pmyData->drvPvt = pasynInterface->drvPvt; + pmyData->done = epicsEventCreate(epicsEventEmpty); + status = pasynManager->queueRequest(pasynUser,asynQueuePriorityLow, 0.0); + if(status) { + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "queueRequest failed %s\n",pasynUser->errorMessage); + } + epicsEventWait(pmyData->done); + status = pasynManager->freeAsynUser(pasynUser); + if(status) { + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "freeAsynUser failed %s\n",pasynUser->errorMessage); + } + epicsEventDestroy(pmyData->done); + pasynManager->memFree(pasynUser->userPvt,sizeof(myData)); + } + +The flow of control is as follows: +#. A port driver calls registerPort. This step is not shown in the above example. +#. asynExample allocates myData and an asynUser. +#. asynExample connects to a device and to the asynOctet interface for the port driver. +#. When it is ready to communicate with the driver it calls queueRequest. +#. queueCallback is called. It calls the port driver's write and read methods. + +Test Applications +----------------- +The asynDriver distribution includes several test applications to test asynDriver +and device support. + +testApp +~~~~~~~ +This is an example of how to interface to asynManager. The example resides in /testApp +and contains the following components: +:: + + Db/ + test.db + testBlock.db + adl/ + test.adl + src/ + devTestBlock.dbd + echoDriver.c + addrChangeDriver.c + devTestBlock.c + interposeInterface.c + +echoDriver is a port driver that echos messages it receives. It implements asynCommon +and asynOctet. When asynOctet:write is called it saves the message. When asynOctet:read +is called, the saved message is returned and the message is flushed. echoDriverInit +has an argument that determines if it acts like a multiDevice or a single device +port driver. + +An instance of echoDriver is started via the iocsh command: +:: + + echoDriverInit(portName,delay,noAutoConnect,multiDevice) + +where the arguments are: + +.. list-table:: echoDriverInit command arguments + :widths: 20 80 + :header-rows: 1 + + * - Argument name + - Value + + * - portName + - the port name for this instance. + * - delay + - The time to delay after a read or write. If delay is 0 then echoDriver + registers as a synchronous port driver, i.e. bit ASYN_CANBLOCK of attributes is + not set. If delay>0 then ASYN_CANBLOCK is set. + * - noAutoConnect + - Determines initial setting for port. + * - multiDevice + - If true then it supports two devices with addresses 0 and 1. If + false it does not set ASYN_MULTIDEVICE, i.e. it only supports a single device. + +addrChangeDriver is a multidevice driver that is an asynUser of another port driver. +In the example application it connects to echoDriver. An example where this technique +might be used is a port driver for mult-drop serial that connects to a standard +serial port. + +An instance of addrChangeDriver is started via the iocsh command: +:: + + addrChangeDriverInit(portName,lowerPort,addr) + +where the arguments are: + +.. list-table:: echoDriverInit command arguments + :widths: 20 80 + :header-rows: 1 + + * - Argument name + - Value + * - portName + - the port name for this instance. + * - lowerPort + - the port to which addrChangeDriver connects + * - addr + - The address to which addrChangeDriver connects + +devTestBlock is device support that tests blockProcessCallback. It has device support +for stringin records. The INP field has the syntax: +:: + + field(INP,"@asyn(port,addr,timeout) pvname) + +where: +- asyn(port,addr,timeout) is same as for devEpics support. +- pvname - The name of a record in the same ioc. + +When the stringin record is processed the following occurs. + +- When process is called and PACT is : + + - TRUE - then it just returns to record support. + - FALSE - It does what follows. + +- When processing starts the state is stateIdle. +- blockProcessCallback is called. +- callbackRequestDelayed is called (.1 second delay). The callback calls queueRequest. +- When processCallback is called it does the following: + + - calls unblockProcessCallback + - If state is stateIdle + + - Calls dbGet to get a string value from pvname + - calls pasynOctet->write to send the string + - sets state to stateWrite + - Calls blockProcessCallback + - callbackRequestDelayed is called The callback calls queueRequest. + - completes. processCallback will be called again + + - If state is stateWrite + + - calls pasynOctet->read and puts the value in VAL. + - Sets state = stateIdle + - requests the the record be processed. This time PACT will be TRUE + +test.db is a template containing three records: a calc record, which forward links +to a stringout record which forward links to a stringin record. The stringOut record +attaches to the device support supplied by asynOctetWriteRead.c. When the calcRecord +is processed the following happens: + +- The calcRecord acts as a counter that overflows when the count reaches 10. After + counting to forward links ti the stringIn record. +- The string in record gets the current value of the counter converted to s character + string and forward links to the stringOut record. +- The stringOut record gets the value from the stringIn record an calls queueRequest. + The record is left with PACT true. +- The processCallback calls pasynOctet->write passing the value obtained from + the stringIn record. The then does does a pasynOctet->read. When this completes + it asks for the record to complete processing. +- The stringOut record completes processing. + +testBlock.db is a template similar to test.db except that it attached to device +support testBlock instead of asynOctetWriteRead. + +Executing "medm -x test.adl" produces the display: + +.. figure:: asynTest.png + :align: center + + **asynTest.png** + +It assumes that an ioc has been started via: +:: + + cd /iocBoot/ioctest + ../../bin/linux-x86_64/test st.cmd + +This starts two versions of echoDriver as port "A" and "B". port A acts as single +device port. port B acts as a multiDevice port that has two devices. For each of +the three possible devices, the st.cmd file starts up two sets of records from test.db +The st.cmd file also loads a set of records from asynTest.db for port A and for +port B and for each of the two devices attached to port B. It also loads a set of +records from asynRecord.db. It starts one version of addrChangeDriver which connects +to port A. + +It loads six versions of test.db and four versions of testBlock.db The test.adl +file attaches to these database records. + +testArrayRingBufferApp +~~~~~~~~~~~~~~~~~~~~~~ +This tests ring buffers for callbacks with arrays. The example resides in /testArrayRingBufferApp. + +Executing "medm -x testArrayRingBufferTop.adl" produces a top-level display from +which this display can be opened: + +.. figure:: asynTestArrayRingBuffer.png + :align: center + + **asynTestArrayRingBuffer.png** + +It assumes that an ioc has been started via: +:: + + cd /iocBoot/ioctestArrayRingBuffer + ../../bin/linux-x86_64/testArrayRingBuffer st.cmd + +testAsynPortClientApp +~~~~~~~~~~~~~~~~~~~~~ +This is a test program that demonstrates how to write C++ program that instantiates +both an asyn port driver and an asynPortClient object. It uses the asynPortClient +object to communicate with the asyn port driver directly over the asyn interfaces +without running an EPICS IOC. It creates an asynIPPort driver and an asynPortClient, +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 provided that +show how to use testAsynIPPortClient to communicate with a Web server, a Newport +XPS motor controller, and a telnet host respectively. + +Usage: testAsynIPPortClient hostInfo outputString [outputEos] [inputEos] + +Example: testAsynIPPortClient cars.uchicago.edu:80 "GET / HTTP/1.0" "\n\n" + +The example resides in /testAsynPortClientApp. + +testAsynPortDriverApp + +This test demonstrates how to write a driver using the asynPortDriver C++ class. +It consists of a simple digital oscilloscope simulator. When the vertical gain changes +the driver does callbacks on the enum choices for the vertical volts/division. This +requires closing and re-opening the display in medm, because Channel Access does +not do monitors on enum value changes. + +The example resides in /testAsynPortDriverApp. + +Executing "medm -x testAsynPortDriverTop.adl" produces a top-level display from +which this display can be opened: + +.. figure:: testAsynPortDriver.png + :align: center + + **testAsynPortDriver.png** + +It assumes that an ioc has been started via: +:: + + cd /iocBoot/ioctestAsynPortDriver + ../../bin/linux-x86_64/testAsynPortDriver st.cmd + +testBroadcastApp +~~~~~~~~~~~~~~~~ +This application contains 3 test programs that use UDP IP broadcast messages. + +testBroadcastAsyn.c +................... + This program uses drvAsynIPPort to send UDP broadcast messages on port 37747. The + message is "i\n". It then listens for any responses. If there are NSLS electrometers + on the network they should respond. + +testBroadcastNoAsyn.c +..................... + This program does the same as testBroadcastAsyn.c but uses native socket calls rather + than drvAsynIPort. + +testBroadcastBurst.c +.................... + This program is used to test the behavior of devices in the presence of large amounts + of broadcast traffic. It should be used with caution, since it can send a large + number of broadcast messages very quickly. It sends numBroadcast messages with no + delay. The messages is "test\r". It does this in a loop of numLoops with a delay + of delayTime seconds at the end of each loop. delayTime is floating point value, + so can be less than 1 second.
+ Usage: testBroadcastBurst broadcastAddress broadcastPort numBroadcast numLoops delayTime + +The code resides in /testBroadcastApp. + +testConnectApp +~~~~~~~~~~~~~~ +This application can be used to test connection management. It connects to a device +with drvAsynIPPort and periodically writes to it in a background thread. Depending +on whether the device is connected error messages will be printed. The device can +be connected and disconnected by power-cycling or removing the network cable to +test the behavior. + +The example resides in /testConnectApp. + +The test ioc can be started via: +:: + + cd /iocBoot/ioctestConnect + ../../bin/linux-x86_64/testConnect st.cmd + +The st.cmd file can be edited to select devices which will or will not ever connect. +There is no medm screen for this test. + +testEpicsApp +~~~~~~~~~~~~ +This test includes example asyn port drivers for the asynInt32 and asynUInt32Digital +interfaces. Both drivers also implement the asynFloat64 interface for controlling +the update rate. The testEpicsApp application also uses the asynOctet echoDriver +from `testApp <#testapp>`__. + +The example resides in /testEpicsApp. + +Executing "medm -x \*.adl" from the /testEpicsApp/adl directory opens +the followings displays. + +.. figure:: testInt32.png + :align: center + + **testInt32** + +.. figure:: testDigital.png + :align: center + + **testDigital** + +.. figure:: testOctet.png + :align: center + + **testOctet** + +From the testInt32.adl screen the following time-series screen can be opened. + +.. figure:: asynTimeSeries.png + :align: center + + **asynTimeSeries** + +It assumes that an ioc has been started via: +:: + + cd /iocBoot/ioctestEpics + ../../bin/linux-x86_64/testEpics st.cmd + +testErrorsApp +~~~~~~~~~~~~~ +This tests error handling in standard asyn device support. The user can control +the status and severity for write operations, read operations, and interrupt callbacks. +It tests all of the interfaces (asynInt32, asynInt64, asynUInt32Digital, asynFloat64, +asynOctet, asynEnum, asynXXXArray (XXX=Int8, Int16, Int32, Int64, Float32, Float64). +It tests output records both with an without the info tag asyn:READBACK. By editing +options in the st.cmd file it also tests: + +- Synchronous and asynchronous driver operation (ASYN_CANBLOCK unset or set) +- String and waveform records with or without ring buffer support(asyn:FIFO=0 or 5) +- Record .TSE field 0 (default timestamp support) or -2 (records get their timestamps + from the driver) +- Periodic or I/O Intr scanning of input records. + +The example resides in /testEpicsApp. + +Executing "medm -x testErrorsTop.adl" from the /testEerrorsApp/adl directory +produces a top-level display from which this display can be opened: + +.. figure:: testErrors.png + :align: center + + **testErrors** + +It assumes that an ioc has been started via: +:: + + cd /iocBoot/ioctestErrors + ../../bin/linux-x86_64/testErrors st.cmd + +Install and Build +----------------- +Install and Build asynDriver +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +After obtaining a copy of the distribution, it must be installed and built for use +at your site. These steps only need to be performed once for the site (unless versions +of the module running under different releases of EPICS and/or the other required +modules are needed). + +#. Create an installation directory for the module, usually this will end with + :: + + .../support/asyn/ + +#. Place the distribution file in this directory. Then issue the commands (Unix style) + :: + + tar xvzf .tar.gz + +#. This creates a support . + :: + + .../support/asyn/X-Y + where X-Y is the release number. For example: + .../support/asyn/3-1 + +#. Edit the ``config/RELEASE`` file and set the paths to your installation of + EPICS_BASE and IPAC. IPAC is only needed if you are building for vxWorks. +#. Run ``make`` in the top level directory and check for any compilation errors. + +Using asynDriver Components with an EPICS iocCore Application +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Since asynDriver does NOT provide support for specific devices an application must +obtain device specific support elsewhere. This section only explains how to include +asynDriver components. + +In the ``configure/RELEASE`` file add definitions for ``IPAC``, +``ASYN``, and ``EPICS_BASE``. + +In the src directory where the application is built: + +- Add the following to ``Makefile`` + :: + + _LIBS += asyn + +The application database definition file must include the database definition +files for the stream package and for any needed ASYN drivers. There are two ways +that this can be done: + +If you are building your application database definition file from the application +Makefile you specify the aditional database definitions there (uncomment the lines +appropriate to your application): +:: + + include "asyn.dbd" + #include "drvAsynSerialPort.dbd" + #include "drvAsynIPPort.dbd" + #include "drvVxi11.dbd" + #include "drvGsIP488.dbd" + #include "drvIpac.dbd" + #include "drvUSBTMC.dbd" + +If you are building your application database definition file from the application +Makefile you specify the aditional database definitions there (again, uncomment +the lines appropriate to your application): +:: + + xxx_DBD += asyn.dbd + #xxx_DBD += drvAsynSerialPort.dbd + #xxx_DBD += drvAsynIPPort.dbd + #xxx_DBD += drvVxi11.dbd + #xxx_DBD += drvGsIP488.dbd + #xxx_DBD += drvIpac.dbd + #xxx_DBD += drvUSBTMC.dbd + +In the ``st.cmd`` file add: +:: + + dbLoadRecords("db/asynRecord.db", "P=, R=, PORT=, ADDR=, OMAX=, IMAX=") + +You must provide values for , , , , , and . + +Once the application is running, medm displays for an ioc can be started by: +:: + + medm -x -macro "P=,R=" /medm/asynRecord.adl & + +You must provide correct values for and . Once asynRecord +is started, it can be connected to different devices. + +License Agreement +----------------- +:: + + Copyright (c) 2002 University of Chicago All rights reserved. + asynDriver is distributed subject to the following license conditions: + + SOFTWARE LICENSE AGREEMENT + Software: asynDriver + + 1. The "Software", below, refers to asynDriver (in either source code, or + binary form and accompanying documentation). Each licensee is + addressed as "you" or "Licensee." + + 2. The copyright holders shown above and their third-party licensors + hereby grant Licensee a royalty-free nonexclusive license, subject to + the limitations stated herein and U.S. Government license rights. + + 3. You may modify and make a copy or copies of the Software for use + within your organization, if you meet the following conditions: + a. Copies in source code must include the copyright notice and this + Software License Agreement. + b. Copies in binary form must include the copyright notice and this + Software License Agreement in the documentation and/or other + materials provided with the copy. + + 4. You may modify a copy or copies of the Software or any portion of it, + thus forming a work based on the Software, and distribute copies of + such work outside your organization, if you meet all of the following + conditions: + a. Copies in source code must include the copyright notice and this + Software License Agreement; + b. Copies in binary form must include the copyright notice and this + Software License Agreement in the documentation and/or other + materials provided with the copy; + c. Modified copies and works based on the Software must carry + prominent notices stating that you changed specified portions of + the Software. + + 5. Portions of the Software resulted from work developed under a U.S. + Government contract and are subject to the following license: the + Government is granted for itself and others acting on its behalf a + paid-up, nonexclusive, irrevocable worldwide license in this computer + software to reproduce, prepare derivative works, and perform publicly + and display publicly. + + 6. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY + OF ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY LICENSORS, THE + UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND THEIR + EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME + ANY LEGAL LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, + OR USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE + SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT + THAT THE SOFTWARE WILL FUNCTION UNINTERRUPTED, THAT IT IS ERROR-FREE + OR THAT ANY ERRORS WILL BE CORRECTED. + + 7. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, THEIR + THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT + OF ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, INCIDENTAL, + CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF ANY KIND OR NATURE, + INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS OR LOSS OF DATA, FOR ANY + REASON WHATSOEVER, WHETHER SUCH LIABILITY IS ASSERTED ON THE BASIS OF + CONTRACT, TORT (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR + OTHERWISE, EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE + POSSIBILITY OF SUCH LOSS OR DAMAGES. diff --git a/documentation/asynGPIBSetup.png b/docs/source/asynGPIBSetup.png similarity index 100% rename from documentation/asynGPIBSetup.png rename to docs/source/asynGPIBSetup.png diff --git a/documentation/asynIPPortSetup.png b/docs/source/asynIPPortSetup.png similarity index 100% rename from documentation/asynIPPortSetup.png rename to docs/source/asynIPPortSetup.png diff --git a/documentation/asynOctet.png b/docs/source/asynOctet.png similarity index 100% rename from documentation/asynOctet.png rename to docs/source/asynOctet.png diff --git a/docs/source/asynPortClient.rst b/docs/source/asynPortClient.rst new file mode 100755 index 0000000..d729de5 --- /dev/null +++ b/docs/source/asynPortClient.rst @@ -0,0 +1,48 @@ +asynPortClient +============== + +:date: January 26, 2019 +:author: Mark Rivers, University of Chicago + +Overview +-------- +asynPortClient is a set of C++ classes that are designed to simplify the task of +writing a client that directly communicates with an asyn port driver, without running +an EPICS IOC. They handle the details of connecting to the driver, finding the required +interfaces, etc. They only use the synchronous interfaces, so all calls are blocking. +If clients need asynchronous operation then they can use the normal C interface +with pasynManager->queueRequest. + +asynPortClient provides a base class, asynParamClient, from which interface-specific +class are derived. It also provides a class for each of the standard asyn interfaces, +(asynInt32Client, asynFloat64Client, asynCommonClient, asynEnumClient, etc.). + +The asynPortClient class connects to a specific asynPortDriver object. It creates +an asynParamClient derived class 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 generic 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. + +Detailed documentation +---------------------- +The detailed documentation for asynPortClient is in these files (generated by doxygen): + +- `asynParamClient class reference `__ +- `asynPortClient class reference `__ +- `asynPortClient.h file reference `__ + +Examples +-------- +One example of the use of asynPortClient can be found in +`areaDetector/ADSimDetector `__ + +Another example client using the asynPortClient class is provided in the testAsynPortClientApp +application in asyn. 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. diff --git a/docs/source/asynPortDriver.rst b/docs/source/asynPortDriver.rst new file mode 100644 index 0000000..15bc084 --- /dev/null +++ b/docs/source/asynPortDriver.rst @@ -0,0 +1,451 @@ +asynPortDriver +============== + +:author: Mark Rivers, University of Chicago + +Overview +-------- +asynPortDriver is a base C++ class that is designed to greatly simplify the task +of writing an asyn port driver. It handles all of the details of registering the +port driver, registering the supported interfaces, and registering the required +interrupt sources. + +Drivers typically need to support a number of parameters that control their operation +and provide status information. Most of these can be treated as 32-bit integers, +64-bit floats, or strings. When the new value of a parameter is sent to a driver, +(e.g. new D/A output value) from an asyn client (e.g. an EPICS record), then the +driver will need to take some action. It may change some other parameters in response +to this new value. The sequence of operations in the driver can be summarized as + +#. New parameter value arrives, or new data arrives from a device. +#. Change values of one or more parameters. +#. For each parameter whose value changes set a flag noting that it changed. +#. When operation is complete, call the registered callbacks for each changed parameter. + +asynPortDriver provides methods to simplify the above sequence, which must be implemented +for each of the often many parameters that the driver supports. Each parameter is +assigned a number, which is the value in the pasynUser->reason field that asyn +clients pass to the driver when reading or writing that parameter. asynPortDriver +maintains a table of parameter values, associating each parameter number with a +data type (integer, UInt32Digital, double, or string), caching the current value, +and maintaining a flag indicating if a value has changed. Drivers use asynPortDriver +methods to read the current value from the table, and to set new values in the table. +There is a method to call all registered callbacks for values that have changed +since callbacks were last done. + +Detailed documentation +---------------------- +The detailed documentation for asynPortDriver is in these files (generated by doxygen): + +- `asynPortDriver class reference `__ +- `asynPortDriver.h `__ + +The example driver in asyn (testAsynPortDriver) is a simple example of how to use +this class + +The `synApps measComp module `__ +contains a detailed example of writing an asynPortDriver driver. The +driver is for the Measurement Computing USB-1608GX-2AO USB device. The example starts +with a very simple driver that only uses a few of the features of the device, and +is fewer than 150 lines of code. There are 5 versions of the driver that each add +additional features. There is a document describing the code for each driver in +detail, which was the basis of a talk at an EPICS short course on asyn. The following +are links to this example: + +- `Introductory talk about the Measurement Computing USB-1608GX-2AO driver `__ +- `Tutorial talk about writing the USB-1608GX-2AO driver step-by step, from a simple driver to a complex one `__ +- `Directory containing the source code for all 5 versions of the the example driver `__ + +More complex examples can be found in the drivers and plugins provided with the +`areaDetector `__ module. + +Example driver +-------------- +An example driver using the asynPortDriver class is provided in the testAsynPortDriverApp +application in asyn. This example is a simple digital oscilloscope emulator. In +this example all of output control and input data is done in a calculated simulation. +But it is easy to see how to use the driver as a basis for real device control. +The code doing the simulation would simply be changed to talk to an actual device. +This could be done using the asyn serial or IP drivers via the asynOctetSyncIO interface +(because at this driver level blocking is permitted), or via VME register access, +or any other I/O mechanism. + +This is the medm screen for controlling this example application. It is started +in the testAsynPortDriverApp/adl directory with the command: +:: + + medm -x -macro "P=testAPD:, R=scope1:" testAsynPortDriver.adl &; + +testAsynPortDriver.adl +~~~~~~~~~~~~~~~~~~~~~~ + +.. figure:: testAsynPortDriver.png + :align: center + + **testAsynPortDriver.png** + +The simulated scope input is a noisy 1kHz sin wave with an amplitude of +-1V. The +amplitude of the noise is an adjustable parameter. The scope parameters that can +be adjusted are the vertical volts/division, vertical volt offset, horizontal time/division, +trigger delay (relative to time=0 for the sin wave). The minimum, maximum and mean +values of the waveform are calculated. The run/stop control turns the simulation +of the waveform on and off. The update time in seconds controls the rate at which +the waveform and statistics are calculated. By default all of the EPICS input records +are I/O Intr scanned. There is a control on the medm screen to change the scan rate +of the waveform record itself. By default it is also I/O Intr scanned, so the plot +updates on every simulation. One can change this to, for example, 1 second, and +then the simulation can be running faster (for example 50 Hz, Update time=.02) so +the statistics will update quickly but the waveform at only 1Hz to save CPU time +and network bandwidth. + +This driver supports about 20 EPICS records, including ao, ai, bo, bi, and waveform. +It does callbacks to device support when any of the input records changes, so the +records can use I/O Intr scanning rather than polling. It uses only the standard +asyn EPICS record device support provided as part of asyn. Yet the driver is only +about 340 lines of well-commented C++ code, because so much of the infrastructure +is handled by the asynPortDriver base class. + +Here are the important lines from the startup script to start this IOC: +:: + + testAsynPortDriverConfigure("testAPD", 1000) + dbLoadRecords("../../db/testAsynPortDriver.db","P=testAPD:,R=scope1:,PORT=testAPD,ADDR=0,TIMEOUT=1,NPOINTS=1000") + +The first line starts the asyn port driver with a 1000 point waveform. The second +line loads the database. The PORT parameter is the name of the asyn port created +in the first line. The ADDR parameter is 0 because this driver is not ASYN_MULTIDEVICE, +it only supports a single address. The TIMEOUT parameter is not really significant +because this is a synchronous asyn port driver, i.e. ASYN_CANBLOCK=0. NPOINTS is +the value for NELM in the waveform record in the database. It would normally match +the value provided in the configure command above. + +This is an example of 2 of the record definitions in the database file, testAsynPortDriver.db. +:: + + ################################################################### + # These records are the time per division # + ################################################################### + record(ao, "$(P)$(R)TimePerDiv") + { + field(PINI, "1") + field(DTYP, "asynFloat64") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))SCOPE_TIME_PER_DIV") + field(PREC, "5") + } + + record(ai, "$(P)$(R)TimePerDiv_RBV") + { + field(PINI, "1") + field(DTYP, "asynFloat64") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))SCOPE_TIME_PER_DIV") + field(PREC, "5") + field(SCAN, "I/O Intr") + } + +Note that there is both an output record and an input record for this parameter, +the time per horizontal division. This is done so that if the driver is forced to +modify a parameter (for example because the device cannot support the output value +it received) there is feedback to the user on the actual value being used. In this +case the ai record will always be the same as the ao record. But in the case of +the update time parameter the driver enforces a minimum time of 0.02 seconds, so +that if a value less than this is requested the ao and ai records will not agree. +In that particular case DRVL could be used to enforce that limit at the ao record +level, but this is not always the case, because device limits can vary with the +value of other parameters. + +The DTYP field of these records is asynFloat64, which uses the standard asyn device +support for ao and ai records, provided in asyn/devEpics/devAsynFloat64.c. + +The OUT and INP fields use the PORT, ADDR and TIMEOUT values described above. The +final parameter, SCOPE_TIME_PER_DIV in these fields is used by the driver to identify +which driver parameter these records are connected to. This is the asyn drvInfo +parameter, and is discussed below. + +Finally, note that the ai record has SCAN=I/O Intr. This means that this record +does not have to be periodically scanned (which is inefficient), but rather it will +be processed whenever its value is changed by the driver. For the ai statistics +records (min, max, mean) in this example,,. record callbacks occur every time the +simulation runs if the noise is non-zero. + +This is the definition of the testAsynPortDriver class: +:: + + class testAsynPortDriver : public asynPortDriver { + public: + testAsynPortDriver(const char *portName, int maxArraySize); + + /* These are the methods that we override from asynPortDriver */ + virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); + virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value); + virtual asynStatus readFloat64Array(asynUser *pasynUser, epicsFloat64 *value, + size_t nElements, size_t *nIn); + virtual asynStatus readEnum(asynUser *pasynUser, char *strings[], int values[], int severities[], + size_t nElements, size_t *nIn); + + /* These are the methods that are new to this class */ + void simTask(void); + + protected: + /** Values used for pasynUser->reason, and indexes into the parameter library. */ + int P_Run; + int P_MaxPoints; + int P_TimePerDiv; + int P_TimePerDivSelect; + int P_VertGain; + int P_VertGainSelect; + int P_VoltsPerDiv; + int P_VoltsPerDivSelect; + int P_VoltOffset; + int P_TriggerDelay; + int P_NoiseAmplitude; + int P_UpdateTime; + int P_Waveform; + int P_TimeBase; + int P_MinValue; + int P_MaxValue; + int P_MeanValue; + + private: + /* Our data */ + epicsEventId eventId_; + epicsFloat64 *pData_; + epicsFloat64 *pTimeBase_; + // Actual volts per division are these values divided by vertical gain + char *voltsPerDivStrings_[NUM_VERT_SELECTIONS]; + int voltsPerDivValues_[NUM_VERT_SELECTIONS]; + int voltsPerDivSeverities_[NUM_VERT_SELECTIONS]; + void setVertGain(); + void setVoltsPerDiv(); + void setTimePerDiv(); + }; + +testAsynPortDriver is derived from asynPortDriver. It overrides the methods writeInt32, +writeFloat64, readFloat64Array, and drvUserCreate. It adds a new method, simTask, +which runs a separate thread to compute the waveform at the specified update time. + +This is the how the parameters are defined in the driver, testAsynPortDriver.cpp +:: + + /* These are the drvInfo strings that are used to identify the parameters. + * They are used by asyn clients, including standard asyn device support */ + #define P_RunString "SCOPE_RUN" /* asynInt32, r/w */ + #define P_MaxPointsString "SCOPE_MAX_POINTS" /* asynInt32, r/o */ + #define P_TimePerDivisionString "SCOPE_TIME_PER_DIV" /* asynFloat64, r/w */ + #define P_VoltsPerDivisionString "SCOPE_VOLTS_PER_DIV" /* asynFloat64, r/w */ + #define P_VoltOffsetString "SCOPE_VOLT_OFFSET" /* asynFloat64, r/w */ + #define P_TriggerDelayString "SCOPE_TRIGGER_DELAY" /* asynFloat64, r/w */ + #define P_NoiseAmplitudeString "SCOPE_NOISE_AMPLITUDE" /* asynFloat64, r/w */ + #define P_UpdateTimeString "SCOPE_UPDATE_TIME" /* asynFloat64, r/w */ + #define P_WaveformString "SCOPE_WAVEFORM" /* asynFloat64Array, r/o */ + #define P_TimeBaseString "SCOPE_TIME_BASE" /* asynFloat64Array, r/o */ + #define P_MinValueString "SCOPE_MIN_VALUE" /* asynFloat64, r/o */ + #define P_MaxValueString "SCOPE_MAX_VALUE" /* asynFloat64, r/o */ + #define P_MeanValueString "SCOPE_MEAN_VALUE" /* asynFloat64, r/o */ + +Note that each parameter has an integer value that identifies it. It is also associated +with a string that is used in the drvInfo field of the record INP or OUT fields +to associate a record with a parameter. + +This is the beginning of the constructor for the testAsynPortDriver C++ class. +:: + + testAsynPortDriver::testAsynPortDriver(const char *portName, int maxPoints) + : asynPortDriver(portName, + 1, /* maxAddr */ + asynInt32Mask | asynFloat64Mask | asynFloat64ArrayMask | asynEnumMask | asynDrvUserMask, /* Interface mask */ + asynInt32Mask | asynFloat64Mask | asynFloat64ArrayMask | asynEnumMask, /* Interrupt mask */ + 0, /* asynFlags. This driver does not block and it is not multi-device, so flag is 0 */ + 1, /* Autoconnect */ + 0, /* Default priority */ + 0) /* Default stack size*/ + ... + +It invokes the constructor for the asynPortDriver base class. It passes: + +- The portName, which is the name of the asyn port to be created. In the st.cmd + file above this is "testAPD". +- The maximum number of asyn addresses that this driver supports, which is 1. +- A mask which defines which asyn interfaces this driver supports, in this case + asynInt32, asynFloat64, asynFloat64Array, and asynDrvUser. All drivers must support + asynCommon, so that bit is added in the base class. +- A mask which defines which asyn interfaces can generate interrupts (callbacks). + In this case that is asynInt32, asynFloat64, and asynFloat64Array. +- A mask which defines the asyn attributes for this driver. asyn currently defines + two attribute bits, ASYN_CANBLOCK and ASYN_MULTIDEVICE. ASYN_CANBLOCK must be set + for drivers that perform "slow" operations on their interfaces, requiring asynManager + to create a separate port thread for them and to use asynchronous device support. + ASYN_MULTIDEVICE must be set for drivers that support more than one asyn address, + for example a driver used to support a 16-channel A/D converter. +- A flag to tell asynManager that it should automatically attempt to connect to + this device when a call is made on its interfaces. This results in a call to asynCommon->connect(). +- A priority flag for the port thread that asynManager will create if ASYN_CANBLOCK + is 1. If this is 0 then asyn will use a default medium thread priority. +- The stack size for the port thread that asynManager will create if ASYN_CANBLOCK + is 1. If this is 0 then asyn will use a default medium thread stack size. + +The constructor also allocates spaces for the waveform arrays (X and Y axes), and +creates the simTask thread. + +This is the implementation of the writeFloat64 function: +:: + + asynStatus testAsynPortDriver::writeFloat64(asynUser *pasynUser, epicsFloat64 value) + { + int function = pasynUser->reason; + asynStatus status = asynSuccess; + epicsInt32 run; + const char *paramName; + const char* functionName = "writeFloat64"; + + /* Set the parameter in the parameter library. */ + status = (asynStatus) setDoubleParam(function, value); + + /* Fetch the parameter string name for possible use in debugging */ + getParamName(function, ¶mName); + + if (function == P_UpdateTime) { + /* Make sure the update time is valid. If not change it and put back in parameter library */ + if (value < MIN_UPDATE_TIME) { + asynPrint(pasynUser, ASYN_TRACE_WARNING, + "%s:%s: warning, update time too small, changed from %f to %f\n", + driverName, functionName, value, MIN_UPDATE_TIME); + value = MIN_UPDATE_TIME; + setDoubleParam(P_UpdateTime, value); + } + /* If the update time has changed and we are running then wake up the simulation task */ + getIntegerParam(P_Run, &run); + if (run) epicsEventSignal(eventId_); + } else { + /* All other parameters just get set in parameter list, no need to + * act on them here */ + } + + /* Do callbacks so higher layers see any changes */ + status = (asynStatus) callParamCallbacks(); + + 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", + driverName, functionName, function, paramName, value); + return status; + } + +This is what is being performed in this function: + +- The pasynUser->reason field is used to get the value of `function`. + This is one of the parameter indices (e.g. P_TimePerDivision). It was placed in + the pasynUser->reason field by this driver's drvUserCreate method that was called + at iocInit, and was passed the drvUser field from the record link, e.g. "SCOPE_TIME_PER_DIV". +- The value passed is set in the parameter list with `setDoubleParam`. +- A series of if statements that processes each of the parameters differently. In + this case only one float64 parameter, P_UpdateTime, needs to actually have any action + taken in this function. All other parameters just have their values set in the parameter + list for later use. +- For P_UpdateTime the value is checked for validity to make sure it is greater + than MIN_UPDATE_TIME. If not then the value is changed, and the new value is written + to the parameter list. This new value will be passed in callbacks to any callback + clients, for example an ai record that is monitoring this parameter. The function + then retrieves the value of the P_Run parameter from the parameter list, and if + it is 1 it sends an EPICS event signal to wake up the simTask. This is done so that + if the update time is changed from a very long value to a shorter one then it does + not wait for the long timer to expire. +- `callParamCallbacks()` is called, which results in callbacks to all + registered clients for any parameters that have changed as a result of this function + call. In this case the only parameter that will have changed is whatever parameter + was passed in pasynUser->reason, but in general other parameters could have changed + as a side-effect of changing this parameter. +- Diagnostic information is optionally printed for both error and success status. + +The `writeInt32` function is very similar. + +Finally here is the `simTask` function, which actually does the simulation. +It runs in a separate thread created in the constructor: +:: + + void testAsynPortDriver::simTask(void) + { + /* This thread computes the waveform and does callbacks with it */ + + double timePerDiv, voltsPerDiv, voltOffset, triggerDelay, noiseAmplitude; + double updateTime, minValue, maxValue, meanValue; + double time, timeStep; + double noise, yScale; + epicsInt32 run, i, maxPoints; + double pi=4.0*atan(1.0); + + lock(); + /* Loop forever */ + while (1) { + getDoubleParam(P_UpdateTime, &updateTime); + getIntegerParam(P_Run, &run); + // Release the lock while we wait for a command to start or wait for updateTime + unlock(); + if (run) epicsEventWaitWithTimeout(eventId_, updateTime); + else (void) epicsEventWait(eventId_); + // Take the lock again + lock(); + /* run could have changed while we were waiting */ + getIntegerParam(P_Run, &run); + if (!run) continue; + getIntegerParam(P_MaxPoints, &maxPoints); + getDoubleParam (P_TimePerDiv, &timePerDiv); + getDoubleParam (P_VoltsPerDiv, &voltsPerDiv); + getDoubleParam (P_VoltOffset, &voltOffset); + getDoubleParam (P_TriggerDelay, &triggerDelay); + getDoubleParam (P_NoiseAmplitude, &noiseAmplitude); + time = triggerDelay; + timeStep = timePerDiv * NUM_DIVISIONS / maxPoints; + minValue = 1e6; + maxValue = -1e6; + meanValue = 0.; + + yScale = 1.0 / voltsPerDiv; + for (i=0; i maxValue) maxValue = pData_[i]; + meanValue += pData_[i]; + pData_[i] = NUM_DIVISIONS/2 + yScale * (voltOffset + pData_[i]); + time += timeStep; + } + updateTimeStamp(); + meanValue = meanValue/maxPoints; + setDoubleParam(P_MinValue, minValue); + setDoubleParam(P_MaxValue, maxValue); + setDoubleParam(P_MeanValue, meanValue); + callParamCallbacks(); + doCallbacksFloat64Array(pData_, maxPoints, P_Waveform, 0); + } + } + +Here are the important aspects of this function: + +- The value of `P_Run` determines whether the simulation is running or + stopped. If stopped it simply waits for a signal (from the `writeInt32()` + function) to start running. If running it waits for the update time, or until it + receives a signal, which will occur if the update time is changed in the `writeFloat64()` + function. +- It reads the values of the simulation parameters (`P_TimePerDivision`, + etc.) from the parameter list. +- It computes each point in the waveform inside the `for` loop, using + the current values of the simulation parameters. It also updates the statistics + parameters (min, max, mean) inside this loop. +- After the loop is done the new values of the statistics parameters are written + to the parameter list with `setDoubleParam()`. +- New values of all scalar parameters (int32, float64, string) in the parameter + list are sent to registered clients (e.g. asyn device support for input records) + with the call to `callParamCallbacks()`. +- The new value of the waveform is sent to registered clients (e.g. device support + for the waveform input record) with the call to `doCallbacksFloat64Array()`. + + +Real drivers may or may not need such a separate thread. Drivers that need to periodically +poll status information will probably use one. Most drivers will probably implement +one or more of the `writeInt32()`, `writeFloat64()`, or ` +writeOctet()` functions, in addition to `drvUserCreate()`. diff --git a/documentation/asynRecord.png b/docs/source/asynRecord.png similarity index 100% rename from documentation/asynRecord.png rename to docs/source/asynRecord.png diff --git a/docs/source/asynRecord.rst b/docs/source/asynRecord.rst new file mode 100644 index 0000000..82b2db9 --- /dev/null +++ b/docs/source/asynRecord.rst @@ -0,0 +1,1205 @@ +asyn Record +=========== + +:author: Mark Rivers and Marty Kraimer + +.. contents:: Contents + +Overview +-------- +The asyn record is designed to provide access to nearly all of the features of the +asyn facility. It includes the ability to: + +- Perform I/O to any asyn device that supports the asynOctet, asynInt32, asynUInt32Digital, + and/or asynFloat64 interfaces. +- Allow EPICS to communicate with a new device without rebooting the IOC, i.e. without + writing any C code or changing the database. This allows Channel Access clients + to communicate with devices for which no EPICS device support exists. +- In combination with the scalcout record to format output strings and to parse + response strings, eliminate the need for C device support code in many applications. +- Dynamically change the asyn device "port" and "address", so a single asyn record + can be switched from talking to one device to another at run time. +- Dynamically change the asyn interface being used for I/O. +- Manage the connection state of a device, i.e. connect/disconnect, enable/disable, + autoConnect/noAutoConnect.. +- Provide access to asynTrace, controlling debugging output for any asyn device. +- Control the the baud rate, parity, etc. for serial ports whose drivers support + the asynOption interface. +- Control the GPIB address and execute global and addressed commands for GPIB devices. + +For the asynOctet interface there are two output fields, AOUT (ASCII Output) and +BOUT (Byte Output). The OFMT (Output Format) field is used to select one of these +fields or the other as the output source to the device. Similarly, there are two +input fields, AINP (ASCII Input) and BINP (Byte Input). The IFMT (Input Format) +field is used to select one or the other as the destination of data sent from the +device. The ASCII fields are type DBF_STRING, and are very convenient for typical +communication with many devices. They permit, for example, ``medm`` screens +where the user can type a string and observe the response from the instrument. The +ASCII fields, however are limited to 40 characters in length, and cannot be used +to read or write binary data. The byte input and output fields are DBF_CHAR arrays, +and can be used to transfer large blocks of arbitrary data, either ASCII or binary. + +In the "Access" columns in the field description tables: + +.. list-table:: Access Codes + :widths: 20 80 + + * - R + - Read only + * - R/W + - Read and write are allowed + * - R/W* + - Read and write are allowed; write triggers record processing if the record's SCAN + field is set to "Passive". + * - N + - No access allowed + +Device Address Control Fields +----------------------------- + +.. list-table:: Device Address Control Fields + :widths: 10 10 10 10 60 + :header-rows: 1 + + * - Name + - Access + - Prompt + - Data type + - Description + * - PORT + - R/W + - "asyn port" + - DBF_STRING + - The asyn "port" name. This field can be changed at any time to connect the record + to another asyn device. + * - ADDR + - R/W + - "asyn address" + - DBF_LONG + - The asyn address. This field can be changed at any time to connect the record to + another asyn device. + * - PCNCT + - R/W + - "Port Connect/Disconnect" + - DBF_MENU + - Disconnects or connects the port. Choices are "Disconnect" and "Connect". The value + read reflects whether there is currently a valid connection to a port. + * - DRVINFO + - R/W + - "Driver information" + - DBF_STRING + - A string that is passed to the driver with asynDrvUser->create(), assuming that + the asynDrvUser interface exists. The driver will update pasynUser->reason and/or + pasynUser->drvUser as a result. If pasynUser->reason is changed then the asynRecord + REASON field will be updated. + * - REASON + - R/W + - "Reason or command" + - DBF_LONG + - A integer "reason" or "command" that is typically used to tell the driver what item + to read or write. This value is updated when connecting to the driver, using the + DRVINFO field. It can be changed later without reconnecting to the driver. If REASON + is changed then the DRVINFO field will be set to an empty string. + +The asyn record does not have traditional INP or OUT fields for input and output +links. Rather it provides the PORT and ADDR fields to allow dynamically changing +what asyn device the record is connected to. + + +Writing to the PORT, ADDR or DRVINFO fields causes the asyn record to disconnect +from the current device and connect to the specified asyn port and address. This +permits a single asyn record to be used to control any asyn device. Writing to these +fields does not cause any I/O to be done. + +Note that since writing to the PORT, ADDR, or DRVINFO fields cause the record to +automatically attempt to connect to the port, it is usually not necessary to write +to the PCNCT field to connect to the port. The PCNCT field is useful for determining +if the port is connected, and for forcing a disconnect if desired. + +Input/Output Control Fields +--------------------------- + +.. list-table:: Input/Output Control Fields + :widths: 10 10 10 10 60 + :header-rows: 1 + + * - Name + - Access + - Prompt + - Data type + - Description + * - VAL + - R/W + - "Value field (unused)" + - DBF_STRING + - This field is unused. The functions normally assigned to the VAL field in many records + are performed by the AOUT, BOUT, AINP, BINP, I32OUT, I32INP, UI32OUT, UI32INP, F64OUT, + and F64INP fields in the asyn record. + * - TMOD + - R/W + - "Transaction mode" + - DBF_MENU + - The type of I/O transaction to perform when the record is processed. The choices are: + + - "Write/Read" (default) + - "Write" + - "Read" + - "Flush" + - "NoI/O" + * - IFACE + - R/W + - "Interface" + - DBF_MENU + - The interface to use for the I/O transfer when the record processes. The choices are: + + - "asynOctet" (default) + - "asynInt32" + - "asynUInt32Digital" + - "asynFloat64" + * - OCTETIV + - R + - "Octet Is Valid" + - DBF_LONG + - This field is (1,0) if the driver (does,does not) support the asynOctet interface. + * - I32IV + - R + - "Int32 Is Valid" + - DBF_LONG + - This field is (1,0) if the driver (does,does not) support the asynInt32 interface. + * - UI32IV + - R + - "UInt32Digital Is Valid" + - DBF_LONG + - This field is (1,0) if the driver (does,does not) support the asynUInt32Digital + interface. + * - F64IV + - R + - "Float64 Is Valid" + - DBF_LONG + - This field is (1,0) if the driver (does,does not) support the asynFloat64 interface. + * - OPTIONIV + - R + - "Option Is Valid" + - DBF_LONG + - This field is (1,0) if the driver (does,does not) support the asynOption interface. + * - GPIBIV + - R + - "GPIB Is Valid" + - DBF_LONG + - This field is (1,0) if the driver (does,does not) support the asynGPIB interface. + * - TMOT + - R/W + - "Timeout (sec)" + - DBF_DOUBLE + - The timeout value for read and write operations in seconds. If a response is not + received from the device within this time then the record sets a major alarm. -1.0 + means wait forever, no timeout. Default=1.0 + +The TMOD field controls what type of I/O is performed when the record processes. + +.. list-table:: Transfer Mode + :widths: 20 80 + + * - "Write/Read" (default) + - The output data is sent from the selected output field to the device. A response + is then read back into the selected input field. The response must be received within + the time specified by TMOT. For asynOctet the input buffer is flushed before the + write operation, so that any characters received prior to the write operation are + discarded. The Write/Read operation is "atomic", meaning that it is guaranteed that + no other asyn I/O to the device will occur between the write and read operations. + * - "Write" + - The output source is sent to the device. No response is read back. + * - "Read" + - Data is read from the device into the input field. The response must be received + within the time specified by TMOT. No output is sent to the device prior to the + read operation. + * - "Flush" + - The input buffer is flushed. Nothing is sent to the device or read from the device. + Applies only to asynOctet. + * - "NoI/O" + - The record processes but no I/O is actually performed. This mode can be used as + a safety feature when using an asyn record to just control the trace fields of asyn + ports. If the record is in this mode and is accidentally processed, then no I/O + will occur. + +Output Control Fields for asynOctet +----------------------------------- +These fields control output I/O when using the asynOctet interface (i.e. when IFACE="asynOctet"). + +.. list-table:: Output Control Fields for asynOctet + :widths: 10 10 10 10 60 + :header-rows: 1 + + * - Name + - Access + - Prompt + - Data type + - Description + * - AOUT + - R/W* + - "Output string" + - DBF_STRING + - The output string which is sent to the device if OFMT="ASCII". The number of bytes + sent to the device will be ``strlen(AOUT)`` plus ``strlen(OEOS)``. + * - BOUT + - R/W* + - "Output byte data" + - DBF_CHAR (array) + - The output data which is sent to the device if OFMT="Binary" or "Hybrid". The maximum + length of this field is controlled by OMAX. The actual number of bytes to be sent + to the device when OFMT="Hybrid" will be ``strlen(BOUT)`` plus ``strlen(OEOS)``. + The actual number of bytes to be sent to the device when OFMP="Binary" will be NOWT. + * - OEOS + - R/W + - "Output terminator" + - DBF_STRING + - A character string that is appended to the output before transmission to the device. + This field is ignored if OFMT="Binary". Set this field to "" to suppress transmission + of a terminator. Commonly used values are "\r" (the default), "\n", and "\r\n". + * - OMAX + - R + - "Max. size of output array" + - DBF_LONG + - The allocated length of the BOUT array. This value cannot be changed after IOC initialization. + Default=80. + * - NOWT + - R/W + - "Number of bytes to write" + - DBF_LONG + - The number of bytes to send from the BOUT array to the device if OFMT="Binary". + This value must be less than or equal to OMAX. Default=80. + * - NAWT + - R/W + - "Number of bytes actually written" + - DBF_LONG + - The actual number of bytes written in the last write operation. This field is valid + for all OFMT modes. This number does not include the output terminator, if any. + * - OFMT + - R/W + - "Output format" + - DBF_MENU + - The output format. The choices are: + + - "ASCII "(default) + - The data sent to the device will be taken from the AOUT field. + - "Hybrid" + - The data sent to the device will be taken from the BOUT field. + - "Binary" + - The data sent to the device will be taken from the BOUT field. + +There are two output fields, AOUT (ASCII Output) and BOUT (Byte Output). The OFMT +(Output Format) field is used to select one of these fields or the other as the +output source to the device. + +If OFMT="ASCII" then the AOUT field is processed with dbTranslateEscape() to convert +control characters (e.g. "\r", "\021") to bytes, the length of the output is determined +with strlen(), and the string is sent to the device using asynOctet->write. This +will append the output EOS if one has been set. + +If OFMT="Hybrid" then the BOUT field is processed with dbTranslateEscape() to convert +control characters (e.g. "\r", "\021") to bytes, the length of the output is determined +with strlen(), and the string is sent to the device using asynOctet->write. This +will append the output EOS if one has been set. + +If OFMT="Binary" then NOWT bytes from the BOUT field are sent to the device using +asynOctet->write. This will not append an output EOS. + +OEOS is set to the current value for the port when the record connects to the port. +If OEOS is modified after the record connects to the port, then the output EOS will +be changed using asynOctet->setOutputEos. IMPORTANT: The value of OEOS in the +database file is never used, because it is modified when the record connects to +the port. + +Input Control Fields for asynOctet +---------------------------------- +These fields control input I/O when using the asynOctet interface (i.e. when IFACE="asynOctet"). + +.. list-table:: Input Control Fields for asynOctet + :widths: 10 10 10 10 60 + :header-rows: 1 + + * - Name + - Access + - Prompt + - Data type + - Description + * - AINP + - R + - "Input string" + - DBF_STRING + - The input string that is read from the device if IFMT="ASCII". The string will be + null terminated. Note that due to the maximum size of a string in EPICS, the input + string must be less than 40 characters. If longer strings are required then set + IFMT="Hybrid" and read into the BINP field. + * - BINP + - R + - "Input byte data" + - DBF_CHAR (array) + - The input data that is read from the device if IFMT="Hybrid" or IFMT="Binary". The + maximum length of this field is controlled by IMAX. The actual number of bytes read + from the device is given by NORD. + * - IEOS + - R/W + - "Input terminator" + - DBF_STRING + - A string that indicates the end of a message on input. Set this field to """ if + no input terminator should be used. This field is ignored if IFMT="Binary". Commonly + used values are "\r" (the default), "\n", and "\r\n". The input terminator is removed + from the input buffer after the read. + * - IMAX + - R + - "Max. size of input array" + - DBF_LONG + - The allocated length of the BINP array. This value cannot be changed after IOC initialization. + Default=80. + * - NRRD + - R/W + - "Number of bytes to read" + - DBF_LONG + - The requested number of bytes to read. This field is valid for all IFMT modes. If + this field is <= 0, then the requested number of bytes to read will be the EPICS + defined MAX_STRING_SIZE=40 (if IFMT="ASCII") or IMAX (if IFMT="Hybrid" or "Binary"). + Default=0. + * - NORD + - R + - "Number of bytes read" + - DBF_LONG + - The actual number of bytes read in the last read operation. This field is valid + for all IFMT modes. This number includes the input terminator, if any. + * - IFMT + - R/W + - "Input format" + - DBF_MENU + - The input format. The choices are: + + - "ASCII" (default) + + - The data read from the device will be placed in the AINP field. + + - "Hybrid" + + - The data read from the device will be placed in the BINP field. + + - "Binary" + + - The data read from the device will be placed in the BINP field. + * - TINP + - R + - "Translated input" + - DBF_CHAR (array) + - This field will contain up to the first 40 characters of the AINP or BINP fields + (depending on IFMT), after translation with epicsStrSnPrintEscaped, to convert non-printable + characters to a printable form (e.g. \r, \n, etc.) + + +There are two input fields, AINP (ASCII Input) and BINP (Byte Input). The IFMT (Input +Format) field is used to select one or the other as the destination of data sent +from the device. + +A read operation terminates when any 1 of the following 4 conditions is met: + +#. The input terminator (IEOS) is found (if IFMT="ASCII" or "Hybrid") +#. EOI asserted (GPIB only) +#. The desired number of input characters (NRRD) are received +#. The timeout (TMOT) expires + + +If IFMT="ASCII" then input is read into the AINP field with asynOctet->read. +This will remove the input EOS string, if any, and AINP will be NULL terminated +if possible. + +If IFMT="Hybrid" then the input is read into the BINP field with asynOctet->read. +This will remove the input EOS string, if any, and BINP will be NULL terminated +if possible. + +If IFMT="Binary" then the input is read into the BINP field using asynOctet->read. +This will ignore the input EOS. BINP will be null terminated. + + +The TINP field is intended for operator display. It will contain up to the first +40 characters of the input read into AINP (if IFMT="ASCII") or BINP (if IFMT="Hybrid" +or "Binary"). Non-printable characters are first converted to a printable form using +epicsStrSnPrintEscaped. This field should not normally be using for parsing the +response from the device. This is the field that is shown as the ASCII input field +in the medm display asynRecord.adl. It is useful for displaying the device response, +even in "Hybrid" and "Binary" input modes. + +The IEOS terminator field is 40 characters long. However, the serial drivers permit +2 character end-of-message strings at most. The GPIB drivers only permit 1 character +end-of-message strings. + +IEOS is set to the current value for the port when the record connects to the port. +If IEOS is modified after the record connects to the port, then the input EOS will +be changed using asynOctet->setInputEos. IMPORTANT: The value of IEOS in the +database file is never used, because it is modified when the record connects to +the port. + +Input/Output Control Fields for Register Interfaces +--------------------------------------------------- +These fields control I/O when using the register interfaces (i.e. when IFACE="asynInt32", +"asynUInt32Digital", or "asynFloat64"). + +.. list-table:: Input/Output Control Fields for Register Interfaces + :widths: 10 10 10 10 60 + :header-rows: 1 + + * - Name + - Access + - Prompt + - Data type + - Description + * - I32INP + - R + - "asynInt32 input" + - DBF_LONG + - The input data that is read from the device if IFACE="asynInt32" and TMOD="Read" + or "Write/Read". + * - I32OUT + - R/W* + - "asynInt32 output" + - DBF_LONG + - The data that is sent to the device if IFACE="asynInt32" and TMOD="Write" or "Write/Read". + * - UI32INP + - R + - "asynUInt32Digital input" + - DBF_ULONG + - The input data that is read from the device if IFACE="asynUInt32Digital" and TMOD="Read" + or "Write/Read". + * - UI32OUT + - R/W* + - "asynUInt32Digital output" + - DBF_ULONG + - The data that is sent to the device if IFACE="asynUInt32Digital" and TMOD="Write" + or "Write/Read". + * - UI32MASK + - R/W + - "asynUInt32Digital mask" + - DBF_ULONG + - The mask that is used if IFACE="asynUInt32Digital". The mask is used for both write + and read operations. Only bits that are set in mask will be modified on writes, + and any bits that are clear in mask will be zero on read. + * - F64INP + - R + - "asynFloat64 input" + - DBF_DOUBLE + - The input data that is read from the device if IFACE="asynFloat64" and TMOD="Read" + or "Write/Read". + * - F64OUT + - R/W* + - "asynFloat64 output" + - DBF_DOUBLE + - The data that is sent to the device if IFACE="asynFloat64" and TMOD="Write" or "Write/Read". + +Serial Control Fields +--------------------- + +.. list-table:: Input/Output Control Fields for Register Interfaces + :widths: 10 10 10 10 60 + :header-rows: 1 + + * - Name + - Access + - Prompt + - Data type + - Description + * - BAUD + - R/W + - "Baud rate" + - DBF_MENU + - The baud rate for the port. Choices are "Unknown", "300", "600", "1200", "2400", + "4800", "9600", "19200", "38400", "57600", "115200", "230400", 460800, 576000, 921600, + and 1152000. Default="Unknown". Note that BAUD field is limited to 16 choices because + it is of type DBF_MENU. The LBAUD field can be used to select baud rates that are + not available in the BAUD menu. + * - LBAUD + - R/W + - "Baud rate (long)" + - DBF_LONG + - The baud rate for the port as an integer. This field allows selecting any baud rate, + including those not available in the BAUD menu field. Changing the BAUD field will + change the LBAUD field accordingly. Changing the LBAUD field will change the BAUD + field to the appropriate menu choice if possible, or to "Unknown" if that baud rate + is not in the menu. + * - PRTY + - R/W + - "Parity" + - DBF_MENU + - The device parity. Choices are "Unknown", "None", "Even", and "Odd". Default="Unknown". + * - DBIT + - R/W + - "Data bits" + - DBF_MENU + - The number of data bits. Choices are "Unknown", "5", "6", "7", and "8". Default="Unknown". + * - SBIT + - R/W + - "Stop bits" + - DBF_MENU + - The number of stop bits. Choices are "Unknown", "1" and "2". Default="Unknown". + * - MCTL + - R/W + - "Modem Control" + - DBF_MENU + - Modem control. Choices are "Unknown", "CLOCAL" and "YES". Default="Unknown". + * - FCTL + - R/W + - "Flow control (cts rts)" + - DBF_MENU + - Flow control. Choices are "Unknown", "None" and "Hardware". Default="Unknown". Hardware + means to use the cts (clear to send) and rts (request to send) signals + * - IXON + - R/W + - "Output XOFF/XON" + - DBF_MENU + - XOFF/XON control on output. Choices are "Unknown", "No" and "Yes". Default="Unknown". + If the IOC receives an XOFF character, it suspends output until an XON character + is received. + * - IXOFF + - R/W + - "Input XOFF/XON" + - DBF_MENU + - XOFF/XON control on input. Choices are "Unknown", "No" and "Yes". Default="Unknown". + The IOC sends XOFF and XON characters as necessary to prevent input from coming + in faster than programs are reading it. The external device sending the input data + must respond to an XOFF character by suspending transmission, and to an XON character + by resuming transmission. + * - IXANY + - R/W + - "XON=any character" + - DBF_MENU + - Choices are "Unknown", "No" and "Yes". Default="Unknown". Allows any input character + to restart output when output has been suspended with the XOFF character. Otherwise, + only the XON character restarts output. This flag is not available on all systems, + including WIN32. + +The above fields are used to set the serial port parameters. A write to any of these +fields causes the port parameters to be changed immediately, but does not cause +any I/O to be performed. The port parameters can currently be set only for local +serial ports, including IP-Octal on vxWorks. They cannot currently be set for Ethernet/serial +adapters like the Moxa units. + +The "Unknown" choice for each option is used on readback if the driver does not +support that option. "Unknown" should not be written into the field. + +The baud rates actually available are device dependent. For the SBS IP-Octal module +the maximum baud rate is 38400. + + +These record fields are set to the values currently in effect for the port when +the connection to the port is made. IMPORTANT: The value of these fields in the +database file is never used, because it is modified when the record connects to +the port. + +vxWorks and MCTL,FCTL. The sioLib serial support for vxWorks uses CLOCAL for what +POSIX calls CTSRTS (Clear to send and request to send). It does not appear that +sioLib has any concept of modem control, which is what POSIX calls CLOCAL. For vxWorks +the standard serial support for asynDriver supplied in drvAsynSerialPort.c, accepts +both MCTL and FCTL. MCTL=(CLOCAL,YES) is the same as FCTL=(None,Hardware). + +IP Control Fields +----------------- + +.. list-table:: IP Control Fields + :widths: 10 10 10 10 60 + :header-rows: 1 + + * - Name + - Access + - Prompt + - Data type + - Description + * - DRTO + - R/W + - "Disconnect on Read Timeout" + - DBF_MENU + - Choices are "Unknown", "No" and "Yes". Default="No". If Yes then the IP port will + be disconnected on a read timeout. + * - HOSTINFO + - R/W + - "IP port hostInfo" + - DBF_STRING + - The IP port hostInfo string with the same syntax as the drvAsynIPPortConfigure command + i.e. host:port[:localport] [protocol]. + +Writing to the HOSTINFO field will cause the drvAsynIPPort driver to disconnect +from the current host (if any) and then attempt to connect to the new host. + +If the drvAsynIPPort was created with the COM (RFC 2217) protocol then the serial +control fields listed above can be used to control those settings on ther Ethernet/serial +adapter. + +GPIB Control Fields +------------------- + +.. list-table:: GPIB Control Fields + :widths: 10 10 10 10 60 + :header-rows: 1 + + * - Name + - Access + - Prompt + - Data type + - Description + * - SPR + - R + - "Serial Poll Response" + - DBF_UCHAR + - The device status byte, which is read during a Serial Poll operation. + * - UCMD + - R/W* + - "Universal command" + - DBF_MENU + - A GPIB Universal Command to be executed. The choices are: + + - "None" + - "Device Clear (DCL)" + - "Local Lockout (LL0)" + - "Serial Poll Disable (SPD)" + - "Serial Poll Enable (SPE)" + - "Unlisten (UNL)" + - "Untalk (UNT)" + * - ACMD + - R/W* + - "Addressed command" + - DBF_MENU + - A GPIB Addressed Command to be executed. The choices are: + + - "None" + - "Group Execute Trig. (GET)" + - "Go To Local (GTL)" + - "Selected Dev. Clear (SDC)" + - "Take Control (TCT)" + - "Serial Poll" + +GPIB Universal Commands are commands which are directed to all devices on the GPIB +bus, not just addressed devices. If the UCMD field is set to any value except "None" +then the appropriate Universal Command is executed, and UCMD is set back to "None". +The record processing only performs the Universal Command, i.e. it does not also +perform the GPIB operation indicated by TMOD. + +GPIB Addressed Commands are commands which are directed to only the addressed devices +on the GPIB bus. If the ACMD field is set to any value except "None" then the appropriate +Addressed Command is executed, and ACMD is set back to "None". The record processing +only performs the Addressed Command, i.e. it does not also perform the GPIB operation +indicated by TMOD. + +Trace Control Fields +-------------------- + +.. list-table:: Trace Control Fields + :widths: 10 10 10 10 60 + :header-rows: 1 + + * - Name + - Access + - Prompt + - Data type + - Description + * - TMSK + - R/W + - "Trace mask" + - DBF_LONG + - The asynTraceMask. + * - TB0 + - R/W + - "Trace error" + - DBF_MENU + - The ASYN_TRACE_ERROR bit. Choices are "Off" and "On". + * - TB1 + - R/W + - "Trace IO device" + - DBF_MENU + - The ASYN_TRACEIO_DEVICE bit. Choices are "Off" and "On". + * - TB2 + - R/W + - "Trace IO filter" + - DBF_MENU + - The ASYN_TRACEIO_FILTER bit. Choices are "Off" and "On". + * - TB3 + - R/W + - "Trace IO driver" + - DBF_MENU + - The ASYN_TRACEIO_DRIVER bit. Choices are "Off" and "On". + * - TB4 + - R/W + - "Trace flow" + - DBF_MENU + - The ASYN_TRACE_FLOW bit. Choices are "Off" and "On". + * - TB5 + - R/W + - "Trace warning" + - DBF_MENU + - The ASYN_TRACE_WARNING bit. Choices are "Off" and "On". + * - TIOM + - R/W + - "Trace I/O mask" + - DBF_LONG + - The asynTraceIOMask. + * - TIB0 + - R/W + - "Trace IO ASCII" + - DBF_MENU + - The ASYN_TRACEIO_ASCII bit. Choices are "Off" and "On". + * - TIB1 + - R/W + - "Trace IO escape" + - DBF_MENU + - The ASYN_TRACEIO_ESCAPE bit. Choices are "Off" and "On". + * - TIB2 + - R/W + - "Trace IO hex" + - DBF_MENU + - The ASYN_TRACEIO_HEX bit. Choices are "Off" and "On". + * - TINM + - R/W + - "Trace Info mask" + - DBF_LONG + - The asynTraceInfoMask. + * - TINB0 + - R/W + - "Trace Info Time" + - DBF_MENU + - The ASYN_TRACEINFO_TIME bit. Choices are "Off" and "On". + * - TINB1 + - R/W + - "Trace Info Port" + - DBF_MENU + - The ASYN_TRACEINFO_PORT bit. Choices are "Off" and "On". + * - TINB2 + - R/W + - "Trace Info Source" + - DBF_MENU + - The ASYN_TRACEINFO_SOURCE bit. Choices are "Off" and "On". + * - TINB3 + - R/W + - "Trace Info Thread" + - DBF_MENU + - The ASYN_TRACEINFO_THREAD bit. Choices are "Off" and "On". + * - TSIZ + - R/W + - "TraceIO truncate size" + - DBF_LONG + - The parameter passed to asynTraceSetTraceIOTruncateSize(). This value is used to + limit the number of I/O bytes printed by traceIO. + * - TFIL + - R/W + - "Trace IO file" + - DBF_STRING + - The name of the file to which trace information is printed. + +The above fields are used to control the asynTrace facility. They allow one to turn +on and off debugging output printed at the shell or written to the trace file. + +The TMSK field allows one to read/write the entire asynTraceMask word. The TB0-TB5 +fields allow one to read/write the individual bits in asynTraceMask. The TIOM field +allows one to read/write the entire asynTraceIOMask word, and the TIB0-TIB2 fields +allow one to read/write the individual bits in asynTraceIOMask. The TINM field allows +one to read/write the entire asynTraceInfoMask word, and the TINB0-TINB3 fields +allow one to read/write the individual bits in asynTraceInfoMask. + +When the asyn record is connected to a new device with the PORT and ADDR fields +the above trace fields are automatically updated to reflect the current asynTrace, +asynTraceIO, and asynTraceInfo masks for that device. + +The TFIL field is used to set the name of the trace file. It is not possible for +the asyn record to determine the current file name if the record did not set it. +In this case the file name is displayed as "Unknown". Set this field to a string +file name (including possibly a valid path from the IOC's current default directory) +to have the output written to that file. The following values are handled as special +cases: + +- - Write to standard out. +- - Write to standard error. +- - Use the errlog facility. + + +Connection Management Fields +---------------------------- + +.. list-table:: Connection Management Fields + :widths: 10 10 10 10 60 + :header-rows: 1 + + * - Name + - Access + - Prompt + - Data type + - Description + * - AUCT + - R/W + - "Autoconnect" + - DBF_MENU + - Sets the autoconnect option. Choices are "noAutoConnect" and "autoConnect". The + value read reflects current state of the autoconnect flag, i.e. the value returned + from isAutoConnect(). + * - ENBL + - R/W + - "Disable/Enable" + - DBF_MENU + - Disables or enables the port. Choices are "Disable" and "Enable". The value read + reflects current state of the enabled flag, i.e. the value returned from isEnabled(). + * - CNCT + - R/W + - "Connect/Disconnect" + - DBF_MENU + - Disconnects or connects the device. Choices are "Disconnect" and "Connect". The + value read reflects current state of the connected flag, i.e. the value returned + from isConnected(). + +Error Status Fields +------------------- + +.. list-table:: Error Status Fields + :widths: 10 10 10 10 60 + :header-rows: 1 + + * - Name + - Access + - Prompt + - Data type + - Description + * - ERRS + - R + - "Error status" + - DBF_STRING + - Error status string for the most recent operation. This string is set to "" (null + string) at the start of each connection and I/O operation. + * - AQR + - W + - "About queueRequest" + - DBF_CHAR + - Abort queueRequest. If a process request has been queued but not delivered it is + canceled, the record is put into alarm and record completion occurs. + +The ERRS field is set to "" (null string) at the start of every operation, including +trace and connection management operations. It contains the first 100 characters +of any error message the record writes with asynPrint(...ASYN_TRACE_ERROR...). + + +The standard EPICS record fields STAT (status) and SEVR (severity) are used to report +the I/O error status. For example status field may be set to NO_ALARM, WRITE, READ, +or COMM, and the SEVR field may be set to NO_ALARM, MINOR, or MAJOR. These alarm +fields are only used to report I/O errors or errors when connecting to a new PORT +or ADDR. They are not affected by trace or connection management operations. + +Private Fields +-------------- + +.. list-table:: Error Status Fields + :widths: 10 10 10 10 60 + :header-rows: 1 + + * - Name + - Access + - Prompt + - Data type + - Description + * - IPTR + - N + - "Input buffer pointer" + - DBF_NOACCESS + - The pointer to the buffer for the BINP field. + * - OPTR + - N + - "Output buffer pointer" + - DBF_NOACCESS + - The pointer to the buffer for the BOUT field. + +Record Processing +----------------- +The asyn record processes, i.e. performs the I/O operation given by TMOD, according +to the normal rules for EPICS records. The AOUT, BOUT, I32OUT, UI32OUT, and F64OUT +fields are Process Passive, so the record will process if these fields are written +to and the SCAN field of the record is Passive. The scan field of the record can +be set to any of the periodic scan rates (e.g. "1 second") for periodic processing, +to "Event" for event processing, or to "I/O Intr" for I/O interrupt processing. + +"I/O Intr" scanning is fully supported for drivers that provide callbacks. + +If the SCAN field is "I/O Intr" it will be changed to "Passive" when any of the +following fields are modified: PORT, ADDR, DRVINFO, REASON, IFACE, or UINT32MASK. +This is necessary because changes to these fields require re-registering with the +interrupt source. + + +Obsolete serial and GPIB records +-------------------------------- +The asyn record is designed to be a complete replacement for the older generic serial +("serial") and generic GPIB ("gpib") records. These records are no longer needed, +and will not be supported in the future. The following is a list of the differences +between the old serial and GPIB records and the new asyn record which may require +changes to databases or applications. + +#. The ODEL field has been replaced by OEOS. It has changed from a DBF_LONG to DBF_STRING + in order to support multi-character terminators. +#. The IDEL (serial) and EOS (gpib) fields have been replaced by IEOS. They have + changed from a DBF_LONG to DBF_STRING in order to support multi-character terminators. +#. The INP field has been replaced by the PORT and ADDR fields in order to support + run-time connection to different devices. +#. The AOUT and OEOS fields are processed by dbTranslateEscape before being sent + to the device. In rare cases this may require changing the output strings if these + contained the "\" character. +#. The asyn record always posts monitors on the input field (AINP or BINP) when the + record processes. The older records did not post monitors on the AINP field if the + value was the same as the previous read. This caused problems for some SNL programs + and data acquisition applications. +#. The ODEL and IDEL fields were used even when OFMT or IFMT were in "Binary" mode. + OEOS and IEOS are now ignored when OFMT or IFMT respectively are in "Binary" mode. +#. The ODEL and IDEL fields were always used to set the input and output end of string. + The IEOS and OEOS fields now are now initialized to the current EOS settings for + the port when the record connects. IEOS and OEOS only change the EOS settings if + these fields are modified after the record connects to the port. Thus, it is now + important to initialize the EOS strings for the port correctly in the startup script. +#. The TMOT field has changed from DBF_LONG to DBF_DOUBLE, and the units have changed + from milliseconds to seconds. TMOT=-1.0 now means wait forever. + +medm screens +------------ + +The following are screen shots of the medm screens provided for the asyn record. + +Main control screen, asynRecord.adl +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. figure:: asynRecord.png + :align: center + + **asynRecord.png** + + +asynOctet I/O screen, asynOctet.adl +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. figure:: asynOctet.png + :align: center + + **asynOctet.png** + +asyn register device I/O screen, asynRegister.adl +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. figure:: asynRegister.png + :align: center + + **asynRegister.png** + +Serial port setup screen, asynSerialPortSetup.adl +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. figure:: asynSerialPortSetup.png + :align: center + + **asynSerialPortSetup.png** + +IP port setup screen, asynIPPortSetup.adl +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. figure:: asynIPPortSetup.png + :align: center + + **asynIPPortSetup.png** + +GPIB setup screen, asynGPIBSetup.adl +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. figure:: asynGPIBSetup.png + :align: center + + **asynGPIBSetup.png** + +Example #1 +---------- + +The following is an IDL program that demonstrates the use of the asyn record. It +transfers data in both ASCII and binary formats. Hopefully the IDL syntax is clear +enough to be understood by non-IDL users, and can be translated into your favorite +scripting language. +:: + + ; This IDL program demonstrates the use of the EPICS asyn record. + ; The program uses 2 asyn records. The ports corresponding to these + ; 2 records are connected with a null-modem cable + ; Record 1 sends a message to record 2 in ASCII. + ; Record 2 sends a message back to record 1 in binary. + + ; Record names + rec1 = '13LAB:serial2' + rec2 = '13LAB:serial3' + recs = [rec1, rec2] ; Array with both record names + ; Set up port parameters for both records: + ; 19,200 baud, 8 data bits, 1 stop bit, no parity, no flow control + ; Timeout=1 second + for i=0, 1 do begin + rec = recs[i] + t = caput(rec+'.BAUD', '19200') + t = caput(rec+'.DBIT', '8') + t = caput(rec+'.SBIT', '1') + t = caput(rec+'.PRTY', 'None') + t = caput(rec+'.FCTL', 'None') + t = caput(rec+'.TMOT', 1.0) + endfor + + ; Put record 1 in ASCII output mode, output delimiter, + ; binary input mode, no input delimiter + t = caput(rec1+'.OFMT', 'ASCII') + t = caput(rec1+'.OEOS', '\r') + t = caput(rec1+'.IFMT', 'Binary') + t = caput(rec1+'.IEOS', '') + ; Put a monitor on record 1 Binary input field + t = casetmonitor(rec1+'.BINP') + ; Clear the monitor by reading the value + t = caget(rec1+'.BINP', junk) + + ; Put record 2 in Binary output mode, no output delimiter + ; ASCII input mode, input delimiter + t = caput(rec2+'.OFMT', 'Binary') + t = caput(rec2+'.OEOS', '') + t = caput(rec2+'.IFMT', 'ASCII') + t = caput(rec2+'.IEOS', '\r') + + ; Put record 2 in read transfer mode + t = caput(rec2+'.TMOD', 'Read') + ; Put a monitor on record2 ASCII input field + t = casetmonitor(rec2+'.AINP') + ; Clear the monitor by reading the value + t = caget(rec2+'.AINP', junk) + + ; Process record 2; this will cause it to wait for data + t = caput(rec2+'.PROC', 1) + ; Put record 1 in Write transfer mode + t = caput(rec1+'.TMOD', 'Write') + ; Send a message to port 2 + message = 'Request data: '+string(systime()) + print, 'Record 1 sent message: ' + message + t = caput(rec1+'.AOUT', message) + + ; Wait for monitor on record2 ASCII input field + while (not cacheckmonitor(rec2+'.AINP')) do wait, .1 + ; Read data from record 2 + t = caget(rec2+'.AINP', input) + print, 'Got a message from record 1: ', input + + size=256 + ; Put record 1 in read mode, expect "size" byte input + t = caput(rec1+'.TMOD', 'Read') + t = caput(rec1+'.NRRD', size) + ; Process record 1; this will cause it to wait for data + t = caput(rec1+'.PROC', '1') + + ; Put record 2 in write mode + t = caput(rec2+'.TMOD', 'Write') + ; Send an 8 bit binary sin wave, "size" points long from + ; port 2 to port 1 + send_data = byte(sin(findgen(size)/5)*126 + 127) + t = caput(rec2+'.NOWT', size) + t = caput(rec2+'.BOUT', send_data) + + ; Wait for monitor on channel 1 binary input + while (not cacheckmonitor(rec1+'.BINP')) do wait, .1 + + ; Record 1 should have received "size" bytes. Make sure NORD=size + t = caget(rec1+'.NORD', nord) + if (nord eq size) then $ + print, 'Read array data OK' $ + else $ + print, 'Error reading array data!' + + ; Read data from record 1 + t = caget(rec1+'.BINP', rec_data, max=nord) + + ; Plot it + plot, rec_data + + end + +Example #2 +----------- +The following is an IDL procedure that demonstrates the use of the asyn record to +communicate with a Tektronix TDS200 Digital Oscilloscope. It transfers data in both +ASCII and binary formats. It will work with either an RS-232 or GPIB connection +to the scope. The record must be loaded with IMAX at least large enough to read +the waveform. The entire waveform readout is 2500 channels on the TDS220. The buffer +size required is 1 byte per channel + 7 bytes header/checksum. The start and stop +parameters to the procedure can be used to read a subset of the waveform. + +Hopefully the IDL syntax is clear enough to be understood by non-IDL users, and +can be translated into your favorite scripting language. +:: + + pro read_tds200, record, data, start=start, stop=stop, chan=chan + + ; This procedure reads waveforms from the Tektronix TDS200 series scopes + ; Mark Rivers + ; Modifications: + ; March 7, 2001 Correctly put record in Write and Write/Read modes. + ; Dec. 7, 2001 Set timeout to 2 seconds before read. + ; March 30, 2004 Change IFMT from Binary to Hybrid, other fixes. + + if (n_elements(start) eq 0) then start=1 + if (n_elements(stop) eq 0) then stop=2500 + if (n_elements(chan) eq 0) then chan=1 + chan = 'CH'+strtrim(chan,2) + + aout = record + '.AOUT' + binp = record + '.BINP' + tmod = record + '.TMOD' + ifmt = record + '.IFMT' + binp = record + '.BINP' + nord = record + '.NORD' + tmot = record + '.TMOT' + oeos = record + '.OEOS' + ieos = record + '.IEOS' + + ; Set the terminators to newline (assumes scope is set up this way) + t = caput(oeos, '\n', /wait) + t = caput(ieos, '\n', /wait) + + ; Set the transfer mode to write + t = caput(tmod, 'Write', /wait) + + ; Set the encoding to positive binary, start and stop readout channels + ; Set the readout range. Can't do as one command, exceed 40 characters + command = 'DATA:ENC RPB; DATA:START ' + strtrim(start,2) + t = caput(aout, command, /wait) + command = 'DATA:STOP ' + strtrim(stop,2) + t = caput(aout, command, /wait) + + ;Set DATa:WIDth to 2 + ;command = 'DATA:WIDTH 2' + ;t = caput(aout, command, /wait) + + ;Set channel number + command = 'DATA:SOURCE '+ strtrim(chan,2) + t = caput(aout, command, /wait) + + ; Set the input mode to hybrid. Large buffer but line-feed terminator + t = caput(ifmt, 'Hybrid', /wait) + + + ; Set the transfer mode to write/read + t = caput(tmod, 'Write/Read', /wait) + + ; Empirically the timeout needs to be about 5 seconds for + ; 1024 channels with RS-232 + t = caput(tmot, 5.0) + + ; Read the scope + t = caput(aout, 'Curve?', /wait) + + ; Get the data + t = caget(binp, data) + + ; Check the number of bytes read. See if it's what's expected + n_data = stop-start+1 + n_header = 2 + strlen(strtrim(n_data, 2)) + n_checksum = 1 + n_expected = n_header + n_data + n_checksum + t = caget(nord, n) + if (n ne n_expected) then $ + print, 'Scope returned:', n, $' bytes, expected: ', n_expected + + ; The first n_header bytes are header, the last byte is checksum. + ; Data are offset by 127, convert to long + data = data[n_header:n-2] - 127L + + return + end diff --git a/docs/source/asynRecordControl.rst b/docs/source/asynRecordControl.rst new file mode 100644 index 0000000..510d078 --- /dev/null +++ b/docs/source/asynRecordControl.rst @@ -0,0 +1,151 @@ +asyn Record I/O Example +======================= + +This document describes how to use an asyn record to communicate with a message-based instrument. + +It is a step-by-step example of how I set up simple instrument control +using only an asyn record. The instrument may be connected to a +local serial port, a USB/Serial adapter, a LAN/Serial adapter, a +network port (raw TCP or VXI-11), a local GPIB interface or a LAN/GPIB adapter. + +- Create a new application + :: + + mkdir serialTest + cd serialTest + /usr/local/epics/R3.14.11/bin/darwin-x86/makeBaseApp.pl -l + /usr/local/epics/R3.14.11/bin/darwin-x86/makeBaseApp.pl -t ioc serialTest< + /usr/local/epics/R3.14.11/bin/darwin-x86/makeBaseApp.pl -i -t ioc serialTest + +- Add ASYN support. + Edit configure/RELEASE and add a line specifying the path to your ASYN installation + :: + + ASYN=/usr/local/epics/R3.14.11`__ +for writing support for your instrument. diff --git a/documentation/asynRegister.png b/docs/source/asynRegister.png similarity index 100% rename from documentation/asynRegister.png rename to docs/source/asynRegister.png diff --git a/documentation/asynSerialPortSetup.png b/docs/source/asynSerialPortSetup.png similarity index 100% rename from documentation/asynSerialPortSetup.png rename to docs/source/asynSerialPortSetup.png diff --git a/documentation/asynTest.png b/docs/source/asynTest.png similarity index 100% rename from documentation/asynTest.png rename to docs/source/asynTest.png diff --git a/documentation/asynTestArrayRingBuffer.png b/docs/source/asynTestArrayRingBuffer.png similarity index 100% rename from documentation/asynTestArrayRingBuffer.png rename to docs/source/asynTestArrayRingBuffer.png diff --git a/documentation/asynTimeSeries.png b/docs/source/asynTimeSeries.png similarity index 100% rename from documentation/asynTimeSeries.png rename to docs/source/asynTimeSeries.png diff --git a/docs/source/asynTimeStampSupport.rst b/docs/source/asynTimeStampSupport.rst new file mode 100755 index 0000000..d3ba81d --- /dev/null +++ b/docs/source/asynTimeStampSupport.rst @@ -0,0 +1,541 @@ +asyn Timestamp Support +====================== + +:author: Mark Rivers + +:date: September 16, 2013 + +Overview +-------- +This document describes the timestamp support that was added to asyn in R4-22 (October 30, 2013). + +There have been several requests to support EPICS time stamps in asyn port drivers and standard asyn device support. +This will be used by setting the TSE field in the EPICS records to -2. +The record support then directly uses the TIME field in the record as the timestamp. +Device support must have properly set the TIME field in the record. + +Setting the timestamp when the driver processes, rather than later on when the record processes can be desirable because +the timestamp then reflects more accurately the actual time that the I/O operation was performed. +It is also desirable to allow for a user-defined function to provide the timestamp, +rather than being restricted to simply calling epicsTimeGetCurrent(). +For example, the driver may be associated with a particular EPICS event, +and the user-defined function would then call epicsTimeGetEvent() with that event ID. +This can return a site-specific time format. +For example at LCLS epicsTimeGetEvent() returns a timestamp where the low-order bits encode the pulse ID. +They want drivers to read that timestamp as soon as possible after the I/O is complete. + +The process of adding support for timestamps in asyn was begun by Eric Norum in asyn R4-20. +This added a new "timestamp" field to the pasynUser structure. +Standard asyn device support was changed to copy the pasynUser->timestamp field to precord->time. +However, this was only supported for callbacks to device support, i.e. records with SCAN=I/O Intr, +and not for records that called the read() function in the driver, i.e. records with SCAN!= I/O Intr. +There was also no code in pasynManager or asynPortDriver to assist drivers in adding timestamps +to the pasynUser structure on read operations or callbacks, +or to support user-defined timestamp sources that could work with any driver. +The changes described in this document address these issues. + + +asynManager changes +------------------- +In order to support these requirements the following functions have been added to asynManager. +:: + + typedef void (*timeStampCallback)(void *userPvt, epicsTimeStamp *pTimeStamp); + 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); + +asynManager now has an epicsTimeStamp value that is stored for each asyn port. +When the port is created there is a default function in asynManager to update this timestamp. +This default function simply calls epicsTimeGetCurrent(). + +pasynManager->registerTimeStampSource() registers a user-defined function that will return an epicsTimeStamp each time +that pasynManager->updateTimeStamp() is called. + +pasynManager->unregisterTimeStampSource() unregisters any user-defined function and reverts to the default timestamp source in asynManager. + +pasynManager->getTimeStamp() returns the internal time stamp returned by the last call to pasynManager->updateTimeStamp(). + +pasynManager->setTimeStamp() sets the internal timestamp to the value passed in this function. + +The functions above provide the required infrastructure for asynManager to support driver timestamps, +including user-defined timestamp sources. +However, asynManager does not provide a means to set the pasynUser->timestamp field in read or callback operations. +This is because asynManager is not involved in these operations; +read calls are done directly from device support to the asyn port driver, +and callback operations are done directly from the asyn port driver to device support. + +asynShellCommands changes to load a user-defined timestamp function +------------------------------------------------------------------- +Two new commands have been added to asyn/miscellaneous/asynShellCommands.c. +These commands can be called from the vxWorks or iocsh shells. +:: + + asynRegisterTimeStampSource(const char *portName, const char *functionName); + asynUnregisterTimeStampSource(const char *portName); + +The "functionName" argument is the name of a user timestamp source function. +It is defined the same way one would define a function for the EPICS sub or asub records. + +This is from asyn/iocBoot/ioctestErrors/st.cmd +:: + + asynRegisterTimeStampSource("PORT1", "myTimeStampSource") + +This is asyn/testErrorsApp/src/myTimeStampSource.cpp +:: + + #include + #include + #include + + // This function demonstrates using a user-define time stamp source + // It simply returns the current time but with the nsec field set to 0, so that record timestamps + // can be checked to see that the user-defined function is indeed being called. + + static void myTimeStampSource(void *userPvt, epicsTimeStamp *pTimeStamp) + { + epicsTimeGetCurrent(pTimeStamp); + pTimeStamp->nsec = 0; + } + + extern "C" { + epicsRegisterFunction(myTimeStampSource); + } + +This is the line from the dbd file: +:: + + function("myTimeStampSource") + + +asynPortDriver changes +---------------------- + +The asynPortDriver C++ classes now provide very thin wrappers around several of the asynManager functions listed above. +The following functions have been added to asynPortDriver: +:: + + virtual asynStatus updateTimeStamp(); + virtual asynStatus updateTimeStamp(epicsTimeStamp *pTimeStamp); + virtual asynStatus getTimeStamp(epicsTimeStamp *pTimeStamp); + virtual asynStatus setTimeStamp(const epicsTimeStamp *pTimeStamp); + +The functions in asynPortDriver that do callbacks to device support (triggered by callParamCallbacks(), doCallbacksXXXArray(), +and doCallbacksGenericPointer()) now get the timestamp using asynPortDriver::getTimeStamp() +and set the pasynUser->timestamp field in the callback. + +In addition, all of the base class read() functions (e.g. readInt32(), readFloat64(), readUnt32Digital, readOctet) +now also get the timestamp using asynPortDriver::getTimeStamp() and set the pasynUser->timestamp field. + +Note that the asynPortDriver does not implement the readXXXArray() or readGenericPointer() functions, +these are only implemented in derived classes. +All derived classes should set pasynUser->timestamp and pasynUser->status in their readXXXArray() and readGenericPointer() methods. + +devEpics changes +---------------- +In asynR4-20 the standard asyn device support was changed to set the record timestamp (precord->time) from pasynUser->timestamp. +However, this was only supported for callbacks to device support, i.e. records with SCAN=I/O Intr, +and not for records that called the read() function in the driver, i.e. records that did not use SCAN= I/O Intr. + +This has now been fixed so that all input records get precord->time set from the pasynUser->timestamp from the driver, +whether the records have SCAN=I/O Intr or not. + +The previous release also had a bug in devAsynFloat64, so that records with DTYP=AsynFloat64 did not get the proper +timestamp even with SCAN=I/O Intr. This has been fixed. + + +Testing +------- +The timestamp support must be implemented separately for each asyn interface (asynInt32, asynFloat64, asynInt8Array, etc.) +in asynPortDriver. It must also be implemented separately for dozens of device support types (asynInt32 for ai, longin, bi, etc, +asynInt32Array for waveform record,etc.). +There are also code differences depending on whether the record is I/O Intr scanned or not. +For these reasons it is important to have a comprehensive test program to verify that the timestamp support in +asynManager, asynPortDriver, and standard asyn device support are all working properly. + +There was already a test program in asyn to verify that the record STAT and SEVR fields were being set properly +for most records types with standard asyn device support, and for most asyn interfaces, +with both periodically scanning and I/O Intr scanning. +This is an asyn driver that derives from asynPortDriver and is located in asyn/testErrorsApp/src/testErrors.cpp. +This driver and its example IOC (asyn/iocBoot/iocTestErrors) have been modified to also test the new timestamp support. +The driver now calls asynPortDriver::updateTimeStamp() each time new values are computed, +and it sets pasynUser->timestamp in the readXXXArray() methods. + +testErrorsApp/src/myTimeStampSource is a new file that contains an example of a user-defined timestamp source. +The timestamp source in that file simply calls epicsTimeGetCurrent(&timeStamp) and then sets timeStamp.nsec=0, +so the time stamp is always an integer number of seconds. + +There are 3 settings in the IOC startup script that can be set for testing. + +1. TSE in every record: + + - 0 (use the normal record timestamp mechanism) + - \-2 (the record timestamp is set by device support) + +2. SCAN in every record + + - "2 second". Periodically scan the record + - "I/O Intr" Use callbacks from driver to trigger record processing + +3. Time stamp source + + - Default timestamp source in asynPortDriver + - User-defined timestamp source (timeStamp.nsec=0) + +There are thus 8 tests that need to be done to verify that all combinations of the above parameters work correctly. + +The record timestamps and record values were monitored with the "camonitor" program from epics base. +asyn/iocBoot/iocTestErrors/timeStampMonitor.sh contains the camonitor commands to monitor all of the PVs in the test database. + + +Result 1. TSE=0, SCAN=2 second, user-defined timestamp source=No. +.................................................................. +:: + + testErrors:AiInt32 2013-09-11 12:44:31.378018 1 12 + testErrors:LonginInt32 2013-09-11 12:44:31.378024 1 12 + testErrors:BiInt32 2013-09-11 12:44:31.378020 1 One + testErrors:MbbiInt32 2013-09-11 12:44:31.378028 1 Twelve STATE MAJOR + testErrors:BiInt32 2013-09-11 12:44:31.378020 1 One + testErrors:LonginUInt32D 2013-09-11 12:44:31.378026 1 0 + testErrors:BiUInt32D 2013-09-11 12:44:31.378022 1 Zero + testErrors:MbbiUInt32D 2013-09-11 12:44:31.378030 1 Zero + testErrors:MbbiDUInt32D 2013-09-11 12:44:31.378032 1 0 + testErrors:AiFloat64 2013-09-11 12:44:31.378013 1 1.2 + testErrors:SiOctet 2013-09-11 12:44:31.378036 1 1.2 + testErrors:WfInOctet 2013-09-11 12:44:31.378044 1 49 + testErrors:WfInt8 2013-09-11 12:44:31.378050 1 12 + testErrors:WfInt16 2013-09-11 12:44:31.378046 1 12 + testErrors:WfInt32 2013-09-11 12:44:31.378048 1 12 + testErrors:WfFloat32 2013-09-11 12:44:31.378041 1 1.2 + testErrors:WfFloat64 2013-09-11 12:44:31.378043 1 1.2 + testErrors:AiFloat64 2013-09-11 12:44:33.378144 1 1.6 + testErrors:AiInt32 2013-09-11 12:44:33.378155 1 0 + testErrors:BiInt32 2013-09-11 12:44:33.378158 1 Zero + testErrors:BiInt32 2013-09-11 12:44:33.378158 1 Zero + testErrors:LonginInt32 2013-09-11 12:44:33.378164 1 0 + testErrors:MbbiInt32 2013-09-11 12:44:33.378169 1 Zero + testErrors:SiOctet 2013-09-11 12:44:33.378178 1 1.6 + testErrors:WfFloat32 2013-09-11 12:44:33.378183 1 1.6 + testErrors:WfFloat64 2013-09-11 12:44:33.378186 1 1.6 + testErrors:WfInOctet 2013-09-11 12:44:33.378188 1 49 + testErrors:WfInt16 2013-09-11 12:44:33.378191 1 0 + testErrors:WfInt32 2013-09-11 12:44:33.378193 1 0 + testErrors:WfInt8 2013-09-11 12:44:33.378195 1 0 + testErrors:AiFloat64 2013-09-11 12:44:35.378241 1 2 + +This test shows the expected normal behavior. Each record is processing every 2 seconds. +The timestamps for each record in the group are slightly different because the records are processing sequentially +in the 2 second scan task, and the timestamp is generated when the record processes. + +Result 2. TSE=0, SCAN=2 second, user-defined timestamp source=Yes. +................................................................... +:: + + testErrors:AiInt32 2013-09-11 12:52:02.623938 1 8 + testErrors:LonginInt32 2013-09-11 12:52:02.623944 1 8 + testErrors:BiInt32 2013-09-11 12:52:02.623940 1 One + testErrors:MbbiInt32 2013-09-11 12:52:02.623948 1 Eight STATE MINOR + testErrors:BiInt32 2013-09-11 12:52:02.623940 1 One + testErrors:LonginUInt32D 2013-09-11 12:52:02.623946 1 0 + testErrors:BiUInt32D 2013-09-11 12:52:02.623942 1 Zero + testErrors:MbbiUInt32D 2013-09-11 12:52:02.623950 1 Zero + testErrors:MbbiDUInt32D 2013-09-11 12:52:02.623952 1 0 + testErrors:AiFloat64 2013-09-11 12:52:02.623934 1 0.8 + testErrors:SiOctet 2013-09-11 12:52:02.623956 1 0.8 + testErrors:WfInOctet 2013-09-11 12:52:02.623964 1 48 + testErrors:WfInt8 2013-09-11 12:52:02.623970 1 8 + testErrors:WfInt16 2013-09-11 12:52:02.623966 1 8 + testErrors:WfInt32 2013-09-11 12:52:02.623968 1 8 + testErrors:WfFloat32 2013-09-11 12:52:02.623960 1 0.8 + testErrors:WfFloat64 2013-09-11 12:52:02.623962 1 0.8 + testErrors:AiFloat64 2013-09-11 12:52:04.624023 1 1.2 + testErrors:AiInt32 2013-09-11 12:52:04.624035 1 12 + testErrors:LonginInt32 2013-09-11 12:52:04.624044 1 12 + testErrors:MbbiInt32 2013-09-11 12:52:04.624048 1 Twelve STATE MAJOR + testErrors:SiOctet 2013-09-11 12:52:04.624058 1 1.2 + testErrors:WfFloat32 2013-09-11 12:52:04.624066 1 1.2 + testErrors:WfFloat64 2013-09-11 12:52:04.624071 1 1.2 + testErrors:WfInOctet 2013-09-11 12:52:04.624073 1 49 + testErrors:WfInt16 2013-09-11 12:52:04.624075 1 12 + testErrors:WfInt32 2013-09-11 12:52:04.624079 1 12 + testErrors:WfInt8 2013-09-11 12:52:04.624083 1 12 + testErrors:AiFloat64 2013-09-11 12:52:06.624110 1 1.6 + testErrors:AiInt32 2013-09-11 12:52:06.624122 1 0 + +As expected this test shows the same results as test 1, +because setting a user-defined timestamp source should have no effect when TSE=0. + +Result 3. TSE=0, SCAN=I/O Intr, user-defined timestamp source=No. +.................................................................. +:: + + testErrors:AiInt32 2013-09-11 12:57:55.453886 1 6 + testErrors:LonginInt32 2013-09-11 12:57:55.453891 1 6 + testErrors:BiInt32 2013-09-11 12:57:55.453890 1 One + testErrors:MbbiInt32 2013-09-11 12:57:55.453892 1 Six STATE MINOR + testErrors:BiInt32 2013-09-11 12:57:55.453890 1 One + testErrors:LonginUInt32D 2013-09-11 12:57:53.053579 1 0 + testErrors:BiUInt32D 2013-09-11 12:57:53.053578 1 Zero + testErrors:MbbiUInt32D 2013-09-11 12:57:53.053581 1 Zero + testErrors:MbbiDUInt32D 2013-09-11 12:57:53.053584 1 0 + testErrors:AiFloat64 2013-09-11 12:57:55.453894 1 0.6 + testErrors:SiOctet 2013-09-11 12:57:55.453895 1 0.6 + testErrors:WfInOctet 2013-09-11 12:57:55.453897 1 48 + testErrors:WfInt8 2013-09-11 12:57:55.453899 1 6 + testErrors:WfInt16 2013-09-11 12:57:55.453900 1 6 + testErrors:WfInt32 2013-09-11 12:57:55.453901 1 6 + testErrors:WfFloat32 2013-09-11 12:57:55.453902 1 0.6 + testErrors:WfFloat64 2013-09-11 12:57:55.453903 1 0.6 + testErrors:AiInt32 2013-09-11 12:57:55.954073 1 7 + testErrors:LonginInt32 2013-09-11 12:57:55.954086 1 7 + testErrors:MbbiInt32 2013-09-11 12:57:55.954088 1 Seven STATE MINOR + testErrors:AiFloat64 2013-09-11 12:57:55.954090 1 0.7 + testErrors:SiOctet 2013-09-11 12:57:55.954092 1 0.7 + testErrors:WfInOctet 2013-09-11 12:57:55.954095 1 48 + testErrors:WfInt8 2013-09-11 12:57:55.954098 1 7 + testErrors:WfInt16 2013-09-11 12:57:55.954099 1 7 + testErrors:WfInt32 2013-09-11 12:57:55.954101 1 7 + testErrors:WfFloat32 2013-09-11 12:57:55.954102 1 0.7 + testErrors:WfFloat64 2013-09-11 12:57:55.954103 1 0.7 + testErrors:AiInt32 2013-09-11 12:57:56.454213 1 8 + +This test shows the expected normal behavior. +Each record is processing every 0.5 seconds because that is the delay in the driver thread doing the callbacks. +The timestamps for each record in the group are slightly different because the records are processing sequentially +and the timestamp is generated when the record processes. + +Result 4. TSE=0, SCAN=I/O Intr, user-defined timestamp source=Yes +.................................................................. +:: + + testErrors:AiInt32 2013-09-11 13:03:15.191708 1 0 + testErrors:BiInt32 2013-09-11 13:03:15.191718 1 Zero + testErrors:BiInt32 2013-09-11 13:03:15.191718 1 Zero + testErrors:LonginInt32 2013-09-11 13:03:15.191721 1 0 + testErrors:MbbiInt32 2013-09-11 13:03:15.191723 1 Zero + testErrors:AiFloat64 2013-09-11 13:03:15.191725 1 1.6 + testErrors:SiOctet 2013-09-11 13:03:15.191727 1 1.6 + testErrors:WfInOctet 2013-09-11 13:03:15.191729 1 49 + testErrors:WfInt8 2013-09-11 13:03:15.191732 1 0 + testErrors:WfInt16 2013-09-11 13:03:15.191733 1 0 + testErrors:WfInt32 2013-09-11 13:03:15.191734 1 0 + testErrors:WfFloat32 2013-09-11 13:03:15.191736 1 1.6 + testErrors:WfFloat64 2013-09-11 13:03:15.191737 1 1.6 + testErrors:AiInt32 2013-09-11 13:03:15.691816 1 1 + testErrors:BiInt32 2013-09-11 13:03:15.691825 1 One + testErrors:BiInt32 2013-09-11 13:03:15.691825 1 One + testErrors:LonginInt32 2013-09-11 13:03:15.691828 1 1 + testErrors:MbbiInt32 2013-09-11 13:03:15.691830 1 One + testErrors:AiFloat64 2013-09-11 13:03:15.691832 1 1.7 + testErrors:SiOctet 2013-09-11 13:03:15.691833 1 1.7 + testErrors:WfInOctet 2013-09-11 13:03:15.691836 1 49 + testErrors:WfInt8 2013-09-11 13:03:15.691839 1 1 + testErrors:WfInt16 2013-09-11 13:03:15.691840 1 1 + testErrors:WfInt32 2013-09-11 13:03:15.691841 1 1 + testErrors:WfFloat32 2013-09-11 13:03:15.691842 1 1.7 + testErrors:WfFloat64 2013-09-11 13:03:15.691843 1 1.7 + testErrors:AiInt32 2013-09-11 13:03:16.192034 1 2 + +As expected this test shows the same results as test 3, +because setting a user-defined timestamp source should have no effect when TSE=0. + +Result 5. TSE=-2, SCAN=2 second, user-defined timestamp source=No. +................................................................... +:: + + testErrors:AiInt32 2013-09-11 13:10:02.410217 1 12 + testErrors:LonginInt32 2013-09-11 13:10:02.410217 1 12 + testErrors:BiInt32 2013-09-11 13:10:02.410217 1 One + testErrors:MbbiInt32 2013-09-11 13:10:02.410217 1 Twelve STATE MAJOR + testErrors:BiInt32 2013-09-11 13:10:02.410217 1 One + testErrors:LonginUInt32D 2013-09-11 13:10:02.410217 1 0 + testErrors:BiUInt32D 2013-09-11 13:10:02.410217 1 Zero + testErrors:MbbiUInt32D 2013-09-11 13:10:02.410217 1 Zero + testErrors:MbbiDUInt32D 2013-09-11 13:10:02.410217 1 0 + testErrors:AiFloat64 2013-09-11 13:10:02.410217 1 1.2 + testErrors:SiOctet 2013-09-11 13:10:02.410217 1 1.2 + testErrors:WfInOctet 2013-09-11 13:10:02.410217 1 49 + testErrors:WfInt8 2013-09-11 13:10:02.410217 1 12 + testErrors:WfInt16 2013-09-11 13:10:02.410217 1 12 + testErrors:WfInt32 2013-09-11 13:10:02.410217 1 12 + testErrors:WfFloat32 2013-09-11 13:10:02.410217 1 1.2 + testErrors:WfFloat64 2013-09-11 13:10:02.410217 1 1.2 + testErrors:AiFloat64 2013-09-11 13:10:04.410734 1 1.6 + testErrors:AiInt32 2013-09-11 13:10:04.410734 1 0 + testErrors:BiInt32 2013-09-11 13:10:04.410734 1 Zero + testErrors:BiInt32 2013-09-11 13:10:04.410734 1 Zero + testErrors:LonginInt32 2013-09-11 13:10:04.410734 1 0 + testErrors:MbbiInt32 2013-09-11 13:10:04.410734 1 Zero + testErrors:SiOctet 2013-09-11 13:10:04.410734 1 1.6 + testErrors:WfFloat32 2013-09-11 13:10:04.410734 1 1.6 + testErrors:WfFloat64 2013-09-11 13:10:04.410734 1 1.6 + testErrors:WfInOctet 2013-09-11 13:10:04.410734 1 49 + testErrors:WfInt16 2013-09-11 13:10:04.410734 1 0 + testErrors:WfInt32 2013-09-11 13:10:04.410734 1 0 + testErrors:WfInt8 2013-09-11 13:10:04.410734 1 0 + testErrors:AiFloat64 2013-09-11 13:10:06.411245 1 2 + testErrors:AiInt32 2013-09-11 13:10:06.411245 1 4 + +This test shows the expected result. +The timestamps within a single 2-second group are identical, which is different from test 1. +This is because the timestamps are coming from the driver, reflecting the most recent call by the driver to updateTimeStamp(). +The timestamps have non-zero nsec field because the default timestamp source in pasynManager is being used. + +Result 6. TSE=-2, SCAN=2 second, user-defined timestamp source=Yes. +..................................................................... +:: + + testErrors:AiInt32 2013-09-11 13:15:31.000000 1 8 + testErrors:LonginInt32 2013-09-11 13:15:31.000000 1 8 + testErrors:BiInt32 2013-09-11 13:15:31.000000 1 One + testErrors:MbbiInt32 2013-09-11 13:15:31.000000 1 Eight STATE MINOR + testErrors:BiInt32 2013-09-11 13:15:31.000000 1 One + testErrors:LonginUInt32D 2013-09-11 13:15:31.000000 1 0 + testErrors:BiUInt32D 2013-09-11 13:15:31.000000 1 Zero + testErrors:MbbiUInt32D 2013-09-11 13:15:31.000000 1 Zero + testErrors:MbbiDUInt32D 2013-09-11 13:15:31.000000 1 0 + testErrors:AiFloat64 2013-09-11 13:15:31.000000 1 0.8 + testErrors:SiOctet 2013-09-11 13:15:31.000000 1 0.8 + testErrors:WfInOctet 2013-09-11 13:15:31.000000 1 48 + testErrors:WfInt8 2013-09-11 13:15:31.000000 1 8 + testErrors:WfInt16 2013-09-11 13:15:31.000000 1 8 + testErrors:WfInt32 2013-09-11 13:15:31.000000 1 8 + testErrors:WfFloat32 2013-09-11 13:15:31.000000 1 0.8 + testErrors:WfFloat64 2013-09-11 13:15:31.000000 1 0.8 + testErrors:AiFloat64 2013-09-11 13:15:33.000000 1 1.2 + testErrors:AiInt32 2013-09-11 13:15:33.000000 1 12 + testErrors:LonginInt32 2013-09-11 13:15:33.000000 1 12 + testErrors:MbbiInt32 2013-09-11 13:15:33.000000 1 Twelve STATE MAJOR + testErrors:SiOctet 2013-09-11 13:15:33.000000 1 1.2 + testErrors:WfFloat32 2013-09-11 13:15:33.000000 1 1.2 + testErrors:WfFloat64 2013-09-11 13:15:33.000000 1 1.2 + testErrors:WfInOctet 2013-09-11 13:15:33.000000 1 49 + testErrors:WfInt16 2013-09-11 13:15:33.000000 1 12 + testErrors:WfInt32 2013-09-11 13:15:33.000000 1 12 + testErrors:WfInt8 2013-09-11 13:15:33.000000 1 12 + testErrors:AiFloat64 2013-09-11 13:15:35.000000 1 1.6 + testErrors:AiInt32 2013-09-11 13:15:35.000000 1 0 + +This test shows the expected result. +The timestamps within a single 2-second group are identical, which is different from test 2. +This is because the timestamps are coming from the driver, reflecting the most recent call by the driver to updateTimeStamp(). +The timestamps have no fractional seconds because the user-defined timestamp source is being used, which sets timeStamp.nsec=0. + +Result 7. TSE=-2, SCAN=I/O Intr, user-defined timestamp source=No. +................................................................... +:: + + testErrors:AiInt32 2013-09-11 13:18:40.790244 1 6 + testErrors:LonginInt32 2013-09-11 13:18:40.790244 1 6 + testErrors:MbbiInt32 2013-09-11 13:18:40.790244 1 Six STATE MINOR + testErrors:AiFloat64 2013-09-11 13:18:40.790244 1 0.6 + testErrors:SiOctet 2013-09-11 13:18:40.790244 1 0.6 + testErrors:WfInOctet 2013-09-11 13:18:40.790244 1 48 + testErrors:WfInt8 2013-09-11 13:18:40.790244 1 6 + testErrors:WfInt16 2013-09-11 13:18:40.790244 1 6 + testErrors:WfInt32 2013-09-11 13:18:40.790244 1 6 + testErrors:WfFloat32 2013-09-11 13:18:40.790244 1 0.6 + testErrors:WfFloat64 2013-09-11 13:18:40.790244 1 0.6 + testErrors:AiInt32 2013-09-11 13:18:41.290368 1 7 + testErrors:LonginInt32 2013-09-11 13:18:41.290368 1 7 + testErrors:MbbiInt32 2013-09-11 13:18:41.290368 1 Seven STATE MINOR + testErrors:AiFloat64 2013-09-11 13:18:41.290368 1 0.7 + testErrors:SiOctet 2013-09-11 13:18:41.290368 1 0.7 + testErrors:WfInOctet 2013-09-11 13:18:41.290368 1 48 + testErrors:WfInt8 2013-09-11 13:18:41.290368 1 7 + testErrors:WfInt16 2013-09-11 13:18:41.290368 1 7 + testErrors:WfInt32 2013-09-11 13:18:41.290368 1 7 + testErrors:WfFloat32 2013-09-11 13:18:41.290368 1 0.7 + testErrors:WfFloat64 2013-09-11 13:18:41.290368 1 0.7 + testErrors:AiInt32 2013-09-11 13:18:41.790539 1 8 + +This test shows the expected result. +The timestamps within a single 0.5 second group are identical, which is different from test 3. +This is because the timestamps are coming from the driver, reflecting the most recent call by the driver to updateTimeStamp(). +The timestamps have non-zero nsec field because the default timestamp source in pasynManager is being used. + +Result 8. TSE=-2, SCAN=I/O Intr, user-defined timestamp source=Yes. +.................................................................... +:: + + testErrors:AiInt32 2013-09-11 13:22:55.000000 1 0 + testErrors:BiInt32 2013-09-11 13:22:55.000000 1 Zero + testErrors:BiInt32 2013-09-11 13:22:55.000000 1 Zero + testErrors:LonginInt32 2013-09-11 13:22:55.000000 1 0 + testErrors:MbbiInt32 2013-09-11 13:22:55.000000 1 Zero + testErrors:AiFloat64 2013-09-11 13:22:55.000000 1 1.6 + testErrors:SiOctet 2013-09-11 13:22:55.000000 1 1.6 + testErrors:WfInOctet 2013-09-11 13:22:55.000000 1 49 + testErrors:WfInt8 2013-09-11 13:22:55.000000 1 0 + testErrors:WfInt16 2013-09-11 13:22:55.000000 1 0 + testErrors:WfInt32 2013-09-11 13:22:55.000000 1 0 + testErrors:WfFloat32 2013-09-11 13:22:55.000000 1 1.6 + testErrors:WfFloat64 2013-09-11 13:22:55.000000 1 1.6 + testErrors:AiInt32 2013-09-11 13:22:55.000000 1 1 + testErrors:BiInt32 2013-09-11 13:22:55.000000 1 One + testErrors:BiInt32 2013-09-11 13:22:55.000000 1 One + testErrors:LonginInt32 2013-09-11 13:22:55.000000 1 1 + testErrors:MbbiInt32 2013-09-11 13:22:55.000000 1 One + testErrors:AiFloat64 2013-09-11 13:22:55.000000 1 1.7 + testErrors:SiOctet 2013-09-11 13:22:55.000000 1 1.7 + testErrors:WfInOctet 2013-09-11 13:22:55.000000 1 49 + testErrors:WfInt8 2013-09-11 13:22:55.000000 1 1 + testErrors:WfInt16 2013-09-11 13:22:55.000000 1 1 + testErrors:WfInt32 2013-09-11 13:22:55.000000 1 1 + testErrors:WfFloat32 2013-09-11 13:22:55.000000 1 1.7 + testErrors:WfFloat64 2013-09-11 13:22:55.000000 1 1.7 + testErrors:AiInt32 2013-09-11 13:22:56.000000 1 2 + +This test shows the expected result. +The timestamps within a single 0.5 second group are identical, which is different from test 4. +This is because the timestamps are coming from the driver, reflecting the most recent call by the driver to updateTimeStamp(). +The timestamps have no fractional seconds because the user-defined timestamp source is being used, which sets timeStamp.nsec=0. +Because the records are processing at 0.5 seconds two sets of record processing have the same timestamp, since it has 1 second resolution. + +Result 9. TSE=-2, SCAN=I/O Intr, user-defined timestamp source=Yes. +.................................................................... +:: + + testErrors:WfInt32 2013-09-11 13:33:31.000000 1 13 + testErrors:WfFloat32 2013-09-11 13:33:31.000000 1 4.5 + testErrors:WfFloat64 2013-09-11 13:33:31.000000 1 4.5 + testErrors:AiInt32 2013-09-11 13:33:31.796358 1 14 + testErrors:LonginInt32 2013-09-11 13:33:31.796358 1 14 + testErrors:MbbiInt32 2013-09-11 13:33:31.796358 1 Fourteen STATE INVALID + testErrors:AiFloat64 2013-09-11 13:33:31.796358 1 4.6 + testErrors:SiOctet 2013-09-11 13:33:31.796358 1 4.6 + testErrors:WfInOctet 2013-09-11 13:33:31.796358 1 52 + testErrors:WfInt8 2013-09-11 13:33:31.796358 1 14 + testErrors:WfInt16 2013-09-11 13:33:31.796358 1 14 + testErrors:WfInt32 2013-09-11 13:33:31.796358 1 14 + testErrors:WfFloat32 2013-09-11 13:33:31.796358 1 4.6 + testErrors:WfFloat64 2013-09-11 13:33:31.796358 1 4.6 + testErrors:AiInt32 2013-09-11 13:33:32.296489 1 15 + testErrors:LonginInt32 2013-09-11 13:33:32.296489 1 15 + testErrors:MbbiInt32 2013-09-11 13:33:32.296489 1 Fifteen STATE INVALID + testErrors:AiFloat64 2013-09-11 13:33:32.296489 1 4.7 + testErrors:SiOctet 2013-09-11 13:33:32.296489 1 4.7 + testErrors:WfInOctet 2013-09-11 13:33:32.296489 1 52 + testErrors:WfInt8 2013-09-11 13:33:32.296489 1 15 + testErrors:WfInt16 2013-09-11 13:33:32.296489 1 15 + testErrors:WfInt32 2013-09-11 13:33:32.296489 1 15 + testErrors:WfFloat32 2013-09-11 13:33:32.296489 1 4.7 + testErrors:WfFloat64 2013-09-11 13:33:32.296489 1 4.7 + testErrors:AiInt32 2013-09-11 13:33:32.000000 1 0 + testErrors:BiInt32 2013-09-11 13:33:32.000000 1 Zero + testErrors:BiInt32 2013-09-11 13:33:32.000000 1 Zero + +The above output shows the result when the following commands are typed at the IOC shell. +:: + + unregisterMyTimeStampSource(PORT1) + registerMyTimeStampSource(PORT1) + unregisterMyTimeStampSource(PORT1) + +The timestamps switch between being the user-defined timestamp (no fractional seconds) +and the default timestamp source (with fractional seconds). +This shows that timestamp source can be changed dynamically at run-time. diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..14fae0f --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,39 @@ +# +# asyn documentation + +import sys, os + +project = 'asyn' +html_title = html_short_title = 'asyn support' + +authors = 'Mark Rivers' +copyright = '2023, Mark Rivers' + +extensions = ['sphinx.ext.autodoc', + 'sphinx.ext.mathjax', + 'sphinx.ext.extlinks', + 'sphinx.ext.napoleon'] + +todo_include_todos = True + +templates_path = ['_templates'] +source_suffix = '.rst' +source_encoding = 'utf-8' +master_doc = 'index' +today_fmt = '%Y-%B-%d' + +exclude_trees = ['_build'] + +add_function_parentheses = True +add_module_names = False +pygments_style = 'sphinx' + +# html themes: 'default', 'sphinxdoc', 'alabaster', 'agogo', 'nature', 'pyramid' +#html_theme = 'pyramid' +html_theme = 'sphinx_rtd_theme' + +html_static_path = ['_static'] +html_style = 'css/my_theme.css' +html_last_updated_fmt = '%Y-%B-%d' +html_show_sourcelink = True +htmlhelp_basename = 'asyn_doc' diff --git a/docs/source/devGpib.rst b/docs/source/devGpib.rst new file mode 100644 index 0000000..1bbc8a5 --- /dev/null +++ b/docs/source/devGpib.rst @@ -0,0 +1,1425 @@ +devGpib (obsolete) +================== + +**NOTE: devGpib is obsolete and should not be used for new applications.** + +`StreamDevice `__ +should be used instead. + +License Agreement +----------------- +This product is available via the open source license described at the end of this +document. + +Introduction +------------ +devGpib is the successor to the GPIB support that came with EPICS base 3.13. The +3.13 code was unbundled by Benjamin Franksen, and ultimately became gpibCore which +is the 3.14 version of Benjamin's support. devGpib is the successor to the device +support portion of gpibCore. The driver part of gpibCore is replaced by asynDriver +and asynGpib. + +This manual assumes that the reader is familiar with EPICS IOC record and device +support and also with asynDriver. + +devGpib is one method for implementing EPICS IOC device support for instruments. +Other methods are available. If support for an instrument does not exist, consider +using STREAMS instead of devGpib. + +The 3.13 GPIB support only worked with real GPIB instruments. Since devGpib uses +low level asyn drivers, it can also work with other instruments, e.g. serial devices. +Thus, this manual uses the terminology instrument rather than GPIB device. + +devGpib requires that a device support module be created for each supported instrument. +Facilities are provided to make it relatively easy to write new support. + +The following features are provided: + +- I/O is performed via database records. +- Instrument device support is written by calling devCommonGpib/devSupportGpib routines. +- devCommonGpib provides support for individual record types. +- devSupportGpib provides record independent support. +- devCommonGpib/devSupportGpib use asynCommon, asynOctet, and asynGpib. Thus, the + support will work with any driver that implements these interfaces. If instrument + support does not use GPIB specific features, then the support will work with any + driver that implements asynCommon and asynOctet. In particular, communication via + serial ports is possible. +- devCommonGpib should satisfy most requirements but it is also possible to provide + custom support that uses devSupportGpib. + +Acknowledgments +--------------- + +.. list-table:: + :widths: 20 80 + + * - John Winans + - John provided the original EPICS GPIB support. Most databases using John's support + can be used without modification. With some modification, device support modules + written for John's support can be used. + * - Benjamin Franksen + - John's support only worked on vxWorks. In addition, the driver support was implemented + as a single source file. Benjamin defined an interface between drvCommon and low + level controllers. The low level drivers became separate source modules that implemented + the interface. He also created the original support for VXI-11. + * - Eric Norum + - Eric started with Benjamin's code and converted it to use the Operating System Independent + features of EPICS 3.14. + * - Marty Kraimer + - Marty started with Eric's version and made changes to support secondary addressing + and to replace ioctl with code to support general bus management, universal commands, + and addressed commands. He also made the conversion to using asyn drivers. + +Install and Build +----------------- +devGpib is bundled with the asynDriver. The code is in library asyn. Thus, once +asyn is included as part of an application, devGpib will also be available. It is +only necessary to include `devGpib.dbd` in your `Include.dbd` +file. In addition, device support for your specific instruments must be installed. + +Using Instrument Support +------------------------ +devGpib does not provide support for specific GPIB devices but for implementing +such support. Within the EPICS community, support exists for many GPIB devices. +The EPICS supported hardware list shows some of the support. If your device is not +listed and a message to tech-talk does not provide any help, then you will have +to write your own device support. This section assumes that an instrument support +is available. + +An EPICS record is connected to GPIB by the fields DTYP and INP or OUT. + +The DTYP field has the format: +:: + + field(DTYP,"") + +where `` is the name from a device database definition, +i.e. a definition of the form: +:: + + device(,GPIB_IO,,"") + +The INP or OUT field has the format: +:: + + field(INP,"#L A @") + +or + +:: + + field(OUT,"#L A @") + +where + +.. list-table:: + :widths: 10 90 + + * - `` + - Link number. Low level drivers use portName to provide access to a specific communication + interface. In order to keep compatibility with link numbers, the portName MUST be + Lxxx where xxx is the value that appears in the #Lxxx portion of the INP or OUT + fields of record instances. + * - `` + - GPIB address of your device, which can be a primary address or an extended address. + A primary address has a value <=30. An extended address is of the form PSS, where + P represents the primary address and SS is the secondary address. It is not possible + to express an extended address if the primary address is 0. Some examples are: + :: + + A9 primary address 9 + A900 extended address: primary address is 9, secondary address is 0 + A906 extended address: primary address is 9, secondary address is 6. + + * - `` + - An integer that identifies a gpibCmd definition in a GPIB device support module. + If the implementer is nice, documentation like the following is provided: + :: + + recordType @ Description + + If such documentation is not available, look at the device support itself for statements like: + :: + + /* Param 12 */ + {&DSET_LI, GPIBREAD, IB_Q_LOW, "*ESR?", "%ld", 0, 20, 0, 0, 0, 0, 0, 0}, + The above states that @12 is a GPIB read command via a longin record. Thus the record + definition would be: + :: + record(longin,"") { + field(DTYP,"") + ... + field(OUT,"#L A @12") + ... + } + +Reports and Timeouts +~~~~~~~~~~~~~~~~~~~~ +In order to have these commands available, `devGpib.dbd` must be included +as part of the applications` xxxInclude.dbd` file. + +A report of all devGpib devices can be generated via the command: +:: + + dbior("devGpib",level) + +Three timeouts are defined: + +- `timeout` - This is the timeout for individual I/O operations. It is + determined by the instrument support. +- `queueTimeout` - Maximum time to wait in a the queue for access to + a device instance. The default is 60 seconds and can be changed with the `iocsh` + command: + :: + + devGpibQueueTimeout(interfaceName,gpibAddr,timeout) + +- `srqWaitTimeout` - Maximum time to wait for an SRQ after a GPIBREADW + or GPIBEFASTIW has sent a command to the device. The default is 5 seconds and can + be changed with the `iocsh` command: + :: + + devGpibSrqWaitTimeout(interfaceName,gpibAddr,timeout) + +Creating Instrument Device Support +---------------------------------- +This section describes how to write device support for an instrument. It is assumed +that the reader is already familiar with the dialogue required to operate the instrument +and EPICS record and device support. + +Purpose +~~~~~~~ +An instrument support module provides access to the operating parameters of the +instrument. + +Overview +~~~~~~~~ +Instruments typically have many operating parameters, each of which may be thought +of in terms of an EPICS database record type. It is the job of the instrument support +designer to map operating parameters to record types. Once this mapping is complete, +an instrument support module can be written. For each operating parameter, a gpibCmd +must be created. + +Device DBD Definition +~~~~~~~~~~~~~~~~~~~~~ +For each instrument support module, device definitions must be defined: + +:: + + device(,,,"") + +where + +.. list-table:: + :widths: 20 80 + + * - `` + - The record type, e.g. ai, ao, ... + * - `` + - Link type. Must be GPIB_IO. + * - `` + - Device Support Entry Table name. This is the external name defined in the device + support code. + * - `` + - Device Type name. This is what appears in the DTYP field of record instances. + +For example, the definitions for the test supplied with devGpib are: +:: + + device(ai,GPIB_IO,devAiTestGpib,"GPIB Test") + device(ao,GPIB_IO,devAoTestGpib,"GPIB Test") + device(bi,GPIB_IO,devBiTestGpib,"GPIB Test") + device(bo,GPIB_IO,devBoTestGpib,"GPIB Test") + device(longin,GPIB_IO,devLiTestGpib,"GPIB Test") + device(longout,GPIB_IO,devLoTestGpib,"GPIB Test") + device(mbbi,GPIB_IO,devMbbiTestGpib,"GPIB Test") + device(mbbo,GPIB_IO,devMbboTestGpib,"GPIB Test") + device(stringin,GPIB_IO,devSiTestGpib,"GPIB Test") + device(stringout,GPIB_IO,devSoTestGpib,"GPIB Test") + +For more information about device support, and also how to define INP or OUT links +of records, see the EPICS Application Developers Guide. + +Instrument Device Support Module +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If you are writing a new instrument support module just: + +- Create a source directory and 'cd' to it. +- Create a set of instrument support files by running the makeSupport.pl script: + :: + + /bin//makeSupport.pl -t devGpib +- Modify the src/**.c, src/**.dbd + and src/**.db files to provide the functionality needed by + your device. + +An instrument device support module consists of DSET entries, an array of gpibCmds, +efast tables (optional), name tables (optional), a devGpibParmBlock, a debugging +flag, an init_ai routine, and custom conversion functions (optional.). + +A simplified version of the skeleton file is: +:: + + /* devSkeletonGpib.c */ + ... + #include + ... + /* define all desired DSETs */ + ... + #define DSET_BO devBiSkeletonGpib + ... + #include /* must be included after DSET defines */ + #define TIMEOUT 1.0 + #define TIMEWINDOW 2.0 + ... + /* Strings used by the init routines to fill in the znam,onam,... in BI and BO*/ + static char *offOnList[] = { "Off", "On" }; + static struct devGpibNames offOn = { 2, offOnList, 0, 1 }; + + static char *initNamesList[] = { "Init","Init" }; + static struct devGpibNames initNames = { 2,initNamesList,0,1 }; + /* example EFAST table */ + static char *userOffOn[] = {"USER OFF;", "USER ON;", 0}; + + /* Array of structures that define all GPIB messages */ + static struct gpibCmd gpibCmds[] = + { + /* Param 0 */ + {&DSET_BO,GPIBCMD,IB_Q_HIGH,"init",0,0,32,NULL,0,0,NULL,&initNames,0}, + /* Param 1 */ + {&DSET_BO, GPIBEFASTO, IB_Q_HIGH,0,0, 0, 32,0, 0, 0, userOffOn, &offOn, 0}, + /* definitions for other parameters follow*/ + }; + /* The following is the number of elements in the command array above. */ + #define NUMPARAMS sizeof(gpibCmds)/sizeof(struct gpibCmd) + /* User MUST define init_ai */ + static long init_ai(int parm) + { + if(parm==0) { + devSupParms.name = "devSkeletonGpib"; + devSupParms.gpibCmds = gpibCmds; + devSupParms.numparams = NUMPARAMS; + devSupParms.timeout = TIMEOUT; + devSupParms.timeWindow = TIMEWINDOW; + devSupParms.respond2Writes = -1; + } + } + +The meaning of each portion of the code should become clear as you read the following +sections: + +DSET - Device Support Entry Tables +---------------------------------- + +The following statements create the Device Support Entry Tables +:: + + #define DSET_AI devAiSkeletonGpib + #define DSET_BI devBiSkeletonGpib + #define DSET_MBBI devMbbiSkeletonGpib + ... + #include /* must be included after DSET defines */ + +The actual DSETs are created by devGpib.h based on which DSET_xx definitions are +defined. A #define must appear for each record type required. DSET_AI must be defined +because an init_ai routine must be implemented as described below. If you also define +DSET_AIRAW the associated .dbd file must specify different DTYP strings for the +DSET_AI and DSET_AIRAW device declarations. + +Likewise, if you define both DSET_AO and DSET_AORAW the associated .dbd file must +specify different DTYP strings for the DSET_AO and DSET_AORAW device declarations. + +devCommonGpib provides device support for many standard record types. It is also +possible to create custom support, but this is more difficult. + +gpibCmd Definitions +------------------- +This is where the translation to and from the language of the instrument is defined. +The actual table contains one element for each parameter that is made available +to the user via the @ portion of an INP or OUT field. + +In the example above the definitions for the gpibCmds are: +:: + + static struct gpibCmd gpibCmds[] = + { + /* Param 0 */ + {&DSET_BO, GPIBEFASTO, IB_Q_HIGH, 0, 0, 0, 32,0, 0, 0, userOffOn, &offOn, 0}, + /* definitions for other parameters follow*/ + }; + +This example defines a single command. A database record using this definition must +define field OUT as +:: + + field(OUT,,"#L A @0") + +gpibCmd is +:: + + typedef struct gpibCmd { + gDset *dset; /* used to indicate record type supported */ + int type; /* enum - GPIBREAD...GPIBSRQHANDLER */ + short pri; /* request priority IB_Q_LOW, IB_G_MEDIUM, or IB_Q_HIGH */ + char *cmd; /* CONSTANT STRING to send to instrument */ + char *format;/* string used to generate or interpret msg */ + int rspLen; /* room for response error message */ + int msgLen; /* room for return data message length */ + /*convert is optional custom routine for conversions */ + int (*convert) (gpibDpvt *pgpibDpvt,int P1, int P2, char **P3); + int P1; /* P1 plays a dual role: */ + /* For EFAST it is set internally to the + /* number of entries in the EFAST table */ + /* For convert it is passed to convert() */ + int P2; /* user defined parameter passed to convert() */ + char **P3; /* P3 plays a dual role: */ + /* For EFAST it holds the address of the EFAST table */ + /* For convert it is passed to convert() */ + devGpibNames *pdevGpibNames; /* pointer to name strings */ + char * eos; /* input end-of-string */ + } gpibCmd; + +where + +.. list-table:: + :widths: 10 90 + + * - `dset` + - Address of the Device Support Entry Table (DSET) that describes the record type + supported by the table entry. + * - `type` + - Type of GPIB I/O operation that is to be performed. The `type` field + must be set to one of the enumerated values declared in devSupportGpib.h, i.e. GPIBREAD,...,GPIBSRQHANDLER. + See next section for the definitions. + * - `pri` + - Processing priority of the I/O operation. Must be `IB_Q_HIGH`, `IB_Q_MEDIUM`, + or `IB_Q_LOW`. + * - `cmd` + - Constant string that is used differently depending on the value of `type`. + See the discussion of `type` below. Set this field to 0 if not used. + * - `format` + - Printf/scanf format string that is used differently depending on the value of ` + type`. See the discussion of `type`. Set this field to 0 if not + used. + * - `rspLen` + - Size needed to read back from a device when performing a respond2Writes read operation. + If a gpibCmd is a read operation or a write operation that does not respond, then + set this field to zero. When devGpib initializes, it finds the maximum rspLen of + all commands associated with a port instance and allocates storage of that size. + * - `msgLen` + - Size needed to read or write from a device. If not needed, set it to zero. When + devGpib initializes it finds the maximum msgLen of all commands associated with + a port instance and allocates storage of that size. + * - `convert` + - A conversion function that has the prototype: + :: + + int (*convert) (gpibDpvt *pgpibDpvt,int P1, int P2, char **P3); + + The use depends on the pgpibCmd->type. See below for details. Set to 0 when no + conversion function is present. + + Conversion routines should return 0 to signify a successful conversion. If a convert + routine finds an error, it should do the following: + + - Generate an error message as follows: + :: + + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "",...); + - return -1 to signify failure + * - `P1` + - This plays a dual role. + + For EFAST operations it is set equal to the number of entries in the efast table + by `devSupportGpib:init_record`. + + For other operations, it is an integer passed to the conversion function specified + in `convert.` + + * - `P2` + - Integer passed to the conversion function specified in `convert`. + * - `P3` + - This field plays a dual role. + + When `type` is one of the EFAST operations, this field points to the + EFAST table. See the EFAST operation descriptions under the `type` field + definitions and the section "Efast Tables" for more on the use of this field. Set + this field to 0 when it is not used. + + For other operations, it is passed to the conversion function specified in `convert`. + It has a `char**` value. + + * - `pdevGpibNames` + - Pointer to a Name Table. Name tables are described in the section "Name Tables". + Set this to 0 when no Name Table is used. + * - `eos` + - Input message termination string. It can be: + + - 0 + + A NULL pointer means that this read operation will be terminated by the current + asynOctetSetInputEos value, if any. + - "" + + An empty string signifies that a single null character ('\\0') is the terminator + for this operation. + - non-empty string (e.g. "\\n") + + The termination characters (not including the null character terminating the string) + for this operation. For example, `"\n"` sets the message terminator to + a single ASCII newline (`'\n'`) character. Some drivers, e.g. the VXI-11, + allow only a single termination character. + +Definitions for pgpibCmd->type +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The following describes the semantics for the device support provided by the devGpib +support provided with asynDriver. If an application extends this support, it must +document its changes. + +.. list-table:: Contributions + :widths: 20 80 + + * - GPIBREAD + - Supports record types: ai, bi, event, longin, mbbi, mbbiDirect, stringin, and waveform. + For all of these types the following is done. + + - Send `pgpibCmd->cmd` to the instrument. + - Read from the instrument into `pgpibDpvt->msg`. + `pgpibCmd->msgLen` must specify a size large enough for the message. + + If `convert` is defined then: + + - `convert` is called. It is expected to give a value to the appropriate + field (RVAL for bi, mbbi, mbbiDirect and VAL for all others) of the record or return + -1. Note that it is the responsiblity of the custom conversion routine to set or + clear the record .UDF field. + - The field `pgpibDpvt->msgInputLen` contains the number of bytes + in the last read msg. This allows messages with null characters to be processed. + - Record completion occurs. + + If `convert` is not defined then what is done depends on the record type. + + - bi, event, longin, mbbi, and mbbiDirect. + + `pgpibDpvt->msg` is converted and the result put into field RVAL (bi, + mbbi, mbbiDirect) or VAL (event, longin). If pgpibCmd->format is defined it is + used for the conversion, otherwise a format appropriate to the data type of RVAL/VAL + is used. + + - ai + + `pgpibDpvt->msg` is converted and the result put into field VAL or + RVAL. VAL is used if the DSET does NOT define special_linconv and RVAL is used if + special_linconv is defined. If pgpibCmd->format is defined, it is used for the + conversion. Otherwise, a format appropriate to the field is used. The DSET generated + by devGpib.h does not define special_linconv. + + - stringin + + `pgpibDpvt->msg` is converted and the result put into field VAL. If + pgpibCmd->format is defined it is used for the conversion, otherwise "%39c" is + used. + + - waveform + + Unless FTVL is menuFtypeCHAR, an error is generated and the record is put into alarm. + If FTVL is menuFtypeCHAR,then epicsSnprintf is used to convert `pgpibDpvt->msg` + into BPTR. If format is defined it is used, otherwise "%s" is used. + * - GPIBWRITE + - Supports record types: ao, bo, longout, mbbo, mbboDirect, stringout, and waveform. + + - If `convert` is defined, it is called. It must put a command string + into pgpibDpvt->msg. It can return: + + - \-1 + + Signifies error. The operation is aborted and the record put into alarm. + + - 0 + + Success and call strlen to determine the length of msg. + + - >0 + + Success and the return value is the number of bytes in msg. + + - If `convert` is not defined, then what happens is determined by the + record type. + + - ao + + If special_linconv is NOT defined in DSET, the RVAL field is converted as a long + into msg. If special_linconv is defined, OVAL is converted as a double into msg. + + - bo, mbbo, and mbboDirect + + VAL is converted as an unsigned long into msg. + + - longout + + VAL is converted as a long into msg. + + - stringout + + VAL is converted into msg via epicsSnprintf. If pgpibCmd->format is defined it + is used, otherwise "%s" is used. + + - waveform + + BPTR is converted into msg via epicsSnprintf. If pgpibCmd->format is defined + it is used, otherwise "%s" is used. + + - `pgpibDpvt->msg` is sent to the instrument. + + * - GPIBCVTIO + - Supports record types: ai, ao, bi, bo, event, longin.longout, mbbi, mbbo, mbbiDirect, mmboDirect, stringin, + stringout, waveform. + + All I/O is done by the `convert` routine, which must be defined. ` + convert` is called by a callback routine and thus can make an arbitrary + number of calls to low level drivers. It is passed the address of `gpibDpvt` + which contains the information needed to call the low level drivers: `asynCommon, + asynOctet, and asynGpib.` Note that `asynGpib` may not be present, + i.e. `pasynGpib` is null. `gpibDpvt` also contains a field + `pupvt` which can be used by the convert routine. Is is initialized to + null. The macro `gpibCmdGet` can be used to get the address of `gpibCmd` + which contains other usefull information. + + If the End of String terminator needs to be changed, it must be changed by calling + `pdevSupportGpib->setEos` rather than calling `pgpibDpvt->pasynOctet->setEos` + Also when the `convert` routine has finished with read operations it + must call `pdevSupportGpib->restoreEos` + + Subsection "gpibCmd convert example" below provides an example. + * - GPIBCMD + - Supports record types: ao, bo, longout, mbbo, mbboDirect, stringout, and waveform. + + Send the command string specified in `pgpibCmd->cmd` to the instrument + exactly as specified. + * - GPIBACMD + - This is like GPIBCMD except that ATN is held active. This should rarely be necessary. + * - GPIBSOFT + - No I/O is done. It calls `pgpibCmd->convert`. `pgpibCmd->convert` + must be defined If GPIBSOFT fails, it calls `asynPrint` with mask ` + ASYN_TRACE_ERROR` and also puts the record into alarm. + * - GPIBREADW + - Like GPIBREAD except for that it waits for the device to issue an SRQ before it + issues the read request. + * - GPIBRAWREAD + - Like GPIBREAD except that no command is sent to the instrument. + * - GPIBEFASTO + - This operation type is only valid on BO and MBBO record types. `pgpibCmd->P3` + must contain the address of an efast table. At init time some checks are made to + see that an efast table is defined, but if it is defined incorrectly problems may + arise. + + The following is done: + + - Device support sets `pibDpvt.efastVal` equal to the VAL field. + - If `pgpibCmd->cmd `is not null, then` msgLen` must also + be specified. `msg` is set equal to the concatenation of` cmd` + and the efast value specified by `pgpibCmd->P3`. The resulting ` + msg` is sent. + - If `pgpibCmd->cmd `is null, then the string pointed to by ` + pgpibCmd->P3[efastVal]` is sent. + * - GPIBEFASTI + - This operation type is only valid on BI and MBBI record types. + + The following is done: + + - Send the command string specified in `cmd` to the instrument exactly + as specified. + - Read the data from the instrument and place it into `pgpibDpvt->msg`. + - Compare `msg` with each element of the EFAST table referenced by ` + pgpibCmd->P3.` + - devSupportGpib sets `pgpibDpvt->efastVal` to the index of the EFAST + table that matched. + - Device support sets RVAL equal to `pgpibDpvt->efastVal`. + * - GPIBEFASTIW + - This operation type is like GPIBEFASTI except that it waits for the device to raise + SRQ before the data is read. + * - GPIBIFC + - Valid only for BO records. If rval = (0,1) then (do nothing, pulse IFC). IFC is + one of the GPIB Bus Management Lines. + + Only define `dset`, `type`, and `pri`. A default + pdevGpibNames is provided. For example + :: + + {&DSET_BO, GPIBIFC, IB_Q_LOW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + + * - GPIBREN + - Valid only for BO records. If rval = (0,1) then (drop,assert) REN. REN is one of + the GPIB Bus Management Lines. + + If devices are in the LLO state they can be removed from this state by toggling + the REN line, i.e. turn it off and then turn it back on. + + Only define `dset`, `type`, and `pri`. A default + pdevGpibNames is provided. + * - GPIBDCL + - Valid only for BO records. If rval = (0,1) then (do nothing, send DCL). DCL is a + Universal GPIB command, i.e. it applys to all devices on the link + + Only define `dset`, `type`, and `pri`. A default + pdevGpibNames is provided. + * - GPIBLLO + - If rval = (0,1) then (do nothing, send LLO). LLO is a Universal GPIB command, i.e. + it applys to all devices on the link + + After a LLO, the first time a device is addressed it will disable local control, + i.e. the front pannel controls will not respond. To remove devices from this state + toggle the REN line. A single device can temporarily be removed from LLO by sending + the GPIBCTL command but it will go back to LLO state as soon as it is again addressed. + + Only define `dset`, `type`, and `pri`. A default + pdevGpibNames is provided. + * - GPIBSDC + - If rval = (0,1) then (do nothing, send SDC). SDC is an addressed GPIB command, i.e. + it applies only to the addressed device. + + Only define `dset`, `type`, and `pri`. A default + pdevGpibNames is provided. + * - GPIBGTL + - If rval = (0,1) then (do nothing, send GTL). GTL is an addressed GPIB command, i.e. + it applies only to the addressed device. + + If a device has local control locked out, local control can be temporarily granted + by issuing this command. However the next time the device is addressed it will again + disable local control. + + Only define `dset`, `type`, and `pri`. A default + pdevGpibNames is provided. + * - GPIBSRQHANDLER + - This is used to handle an unsolicited SRQ from gpibAddr, i.e. a device raises SRQ + when a read wait, e.g. GPIBREADW or GPIBEFASTIW, is not active. This request is + implemented only for longin records. When the device issues an SRQ, the status byte + is put into the val field and the record is processed. It is expected that the record + will forward link to records that issue GPIB commands to read the information that + caused the SRQ. + +Efast (Enumerated Fast I/O) Tables +---------------------------------- +A device's command set often has things like "OFF" or "ON" in the command string. +It is convenient to issue such commands via binary and multibit binary records. +Efast tables specify such strings. Simply specify the string value for each of the +possible states of the VAL field of the record. + +The format of an efast table is: +:: + + static char *tableName[] = { + "OFF", /* when VAL = 0 */ + "ON", /* when VAL = 1 */ + 0 /* list terminator */ + }; + +And is referenced in an output parameter table entry like this: +:: + + {&DSET_BO, GPIBEFASTO, IB_Q_HIGH, 0, 0, 0, 0,0, 0, 0, tableName, 0, 0}, + +For an input entry, it would look like this: +:: + + {&DSET_BI, GPIBEFASTI, IB_Q_HIGH, "", 0, 0, 50, 0, 0, 0, tableName, 0, 0}, + +The efast table MUST be 0 terminated. + +For outputs the VAL field is used to index into the efast table and select a string +to send to the instrument. If `cmd` is 0, the string is sent to the instrument +exactly as as it appears in the efast table. If `cmd` is defined, then +that string is prepended to the string obtained from the efast table. + +For input operations, the `cmd` string is sent to the instrument, and +`msg` is read from the instrument. `msg` is compared against +each of the entries in the efast table starting at the zeroth entry. The slot number +of the first table entry that matches the response string is used as the setting +for the RVAL field of the record. When strings are compared, they are compared from +left to right until the number of characters in the efast table are checked. When +ALL of the characters up to but **NOT** including the 0 of the string in the +efast table match the corresponding characters of the response string, it is considered +a valid match. This allows the user to check response strings fairly fast. For example, +if a device returns something like "ON;XOFF;9600" or "OFF;XOFF;9600" in response +to a status check, and you wish to know if the first field is either "OFF" or "ON", +your efast table could look like this: +:: + + static char *statCheck[] = { + "OFF", /* set RVAL to 0 */ + "ON", /* set RVAL to 1 */ + 0}; /* list terminator */ + +The 0 field is *extremely* important. If it is omitted and the instrument +gets confused and responds with something that does not start with an "OFF" or "ON", +the GPIB support library code will end up running off the end of the table. + +In the case when none of the choices in an efast table match for an input operation, +the record is placed into a INVALID alarm state. + +devGpibNames - Name Table +------------------------- + +For binary and multibit binary records, the choice fields of a record can be assigned +values at record initialization. If pdevGpibNames has a value, then when a record +is initialized, the instrument support uses the associated name table to assign +values to choice fields that have not been assigned values. These name tables have +**nothing** to do with I/O operations. + +`devGpibNames` is: +:: + + struct devGpibNames { + int count; /* CURRENTLY only used for MBBI and MBBO */ + char **item; + unsigned long *value; /* CURRENTLY only used for MBBI and MBBO */ + short nobt; /* CURRENTLY only used for MBBI and MBBO */ + }; + +To use a name table, the address of the table must be put into `pdevGpibNames` +of the parameter table. The table format for a multibit record type looks like this: +:: + + static char *tABCDList[] = { + "T", /* zrst*/ + "A", /* onst */ + "B", /* twst */ + "C", /* thst */ + "D"}; /* frst */ + + static unsigned long tABCDVal[] = { + 1, /* zrvl */ + 2, /* onvl */ + 3, /* twvl */ + 5, /* thvl */ + 6 }; /* frvl */ + + static devGpibNames tABCD = { + 5, /* number of elements in string table */ + tABCDList, /* pointer to string table */ + tABCDVal, /* pointer to value table */ + 3 }; /* value for the nobt field */ + +The table format for a binary record type looks like this: +:: + + static char *disableEnableList[] = { + "Disable", /* znam */ + "Enable" }; /* onam */ + + static devGpibNames disableEnable = { + 2, /* number of elements */ + disableEnableList, /* pointer to strings */ + 0, /* pointer to value list */ + 1}; /* number of valid bits */ + +`devGpibNames` is defined in `devSupportGpib.h`. For binary +records, the strings are placed into the name fields in order from lowest to highest +as shown above. For multibit binary records, up to sixteen strings can be defined. +A `devGpibNames` structure referencing these strings is then defined. + +`value` and `nobt` are not used for binary record types, but +should be specified anyway as if the binary record was a multibit binary record +with only 2 values. + +For multibit record types, the name strings, values, and NOBT fields are filled +in from the `devGpibNames` information. For binary record types, only +the znam and onam fields are filled in. + +Name strings (and their associated values in the multibit cases) are not filled +in if the database designer has assigned them values. + +Defining the devGpibParmBlock +----------------------------- +Each DSET of the instrument support contains the address of a `devGpibParmBlock`. +`init_ai` MUST initialize this structure. For example: +:: + + static long init_ai(int parm) + { + if(parm==0) { + devSupParms.name = "devSkeletonGpib"; + devSupParms.gpibCmds = gpibCmds; + devSupParms.numparams = NUMPARAMS; + devSupParms.timeout = TIMEOUT; + devSupParms.timeWindow = TIMEWINDOW; + devSupParms.respond2Writes = -1; + } + return(0); + } + +`devGpibParmBlock` is: +:: + + struct devGpibParmBlock { + char *name; /* Name of this device support*/ + gpibCmd *gpibCmds; /* pointer to gpib command list */ + int numparams; /* number of elements in the command list */ + double timeout; /* seconds to wait for I/O */ + double timeWindow; /* seconds to stop I/O after a timeout*/ + double respond2Writes; /* set >= 0 if device responds to writes */ + /*The following are set by devSupportGpib*/ + int msgLenMax; /*max msgLen all commands*/ + int rspLenMax; /*max rspLen all commands*/ + }; + +.. list-table:: gpibCmds + :widths: 20 80 + + * - `name` + - The device support module type name. Used only to generate diagnostic messages. + - Address of an array of gpibCmd definitions. + * - `numparams` + - The number of gpibCmds defined. A macro should be used to set its value. + * - `timeout` + - timeout in seconds for an individual I/O operation. + * - `timeWindow` + - The number of seconds after a timeout before a new I/O operation will be issued + to the device. During this time window, any I/O operations directed to the timed + out device will result in an error, and the appropriate alarm status will be raised + for the record (either READ_ALARM or WRITE_ALARM depending on the record type and + VALID_ALARM in all cases.) + * - `respond2Writes` + - This field is for devices that echo writes. If respond2Writes >=0 then after + an output command the following is done: + + - If pgpibCmd->rspLen is <=0 no action is taken. This is a way to override + respond2Writes for specific commands. + - If respond2Writes is >0 then a wait of respond2Writes milliseconds occurs. + - A read of up to pgpibCmd->rspLen bytes (terminated earlier by GPIB EOI or by + the terminator string, if any) is read into pgpibDpvt->rsp. + + * - `msgLenMax` + - This is set by devGpibSupport. The value is that of the maximum size input message, + i.e. the largest msgLen defined in gpibCmds. + * - `rspLenMax` + - This is set by devGpibSupport. The value is that of the maximum size response message, + i.e. the largest rspLen defined in gpibCmds. + +SRQ Processing +-------------- + +If the low level device driver implements interface `asynGpib`, then +devSupportGpib registers itself to handle SRQs. It defines two types of SRQs: solicited +and unsollicited. Solicited SRQs are for GPIBREADW and GPIBEFASTIW commands. If +an SRQ is raised for a gpibAddr that does not have an outstanding GPIBREADW or GPIBEFASTIW +command, the SRQ is considered unsolicited. + +When the devSupportGpib receives an unsolicited SRQ and it has a registered handler +for the gpibAddr, it calls the handler. Otherwise it issues a message that it received +an unsolicited SRQ. + +The device support for the longinRecord supports gpibCmd type GPIBSRQHANDLER. It +calls the devSupportGpib registerSrqHandler method. When its interruptCallbackInt32 +gets called, it puts the SRQ status byte into the VAL field and then makes a request +to process the record. By forward linking this record to other records, the user +can handle SRQs from specific devices. Note that the callback is an interruptCallbackInt32 +since asynGpib handles SRQ callbacks via the asynInt32 interface and using asynUser.reason += ASYN_REASON_SIGNAL. + +To save time during SRQ polling operations it is possible to exclude a device which +has become disconnected from the bus for some reason and then to restore the device +to the polling list when the device is reattached. A binary output record with the +following command table entry is used for this purpose: +:: + + /* Add/remove address from SRQ polling list */ + { &DSET_BO,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,0,boSRQonOff,0,0,NULL,NULL,NULL} + +If the binary-output record rval is (0, 1) then (remove, add) device (from, to) +the SRQ polling liist. No commands are sent to the bus. Before exluding a device +from being polled stop any communications to it, i.e. set SCAN-field(s) to PASSIVE +and turn off the device. + +gpibCmd convert example +----------------------- +The asyn distribution includes an example of how to implement the convert parameter +for a gpibCmd. The example is in asyn/devGpib/devGpibConvertExample.c. It defines +three gpibCmds for stringin and three for stringout records. All three input commands +have the same result and all three output commands have the same result. The difference +is how much is done by devGpib support and how much is done by the instrument support. + +The example show how a convert routine can access fields from the devGpibsupport. + +The command tables are: +:: + + static struct gpibCmd gpibCmds[] = + { + /* Param 0 */ + {&DSET_SI,GPIBREAD,IB_Q_LOW,"*IDN?", 0,0,200,0,0,0,0,0,0}, + /* Param 1 simple convert */ + {&DSET_SI,GPIBREAD,IB_Q_LOW,"*IDN?",0,0,200,readString,0,0,0,0,0}, + /* Param 2,example of GPIBCVTIO */ + {&DSET_SI,GPIBCVTIO,IB_Q_LOW,"*IDN?",0,0,200,readCvtio,0,0,0,0,0}, + /* Param 3 */ + {&DSET_SO,GPIBWRITE,IB_Q_LOW,0,0,0,200,0,0,0,0,0,0}, + /* Param 4 simple convert */ + {&DSET_SO,GPIBWRITE,IB_Q_LOW,0,0,0,200,writeString,0,0,0,0,0}, + /* Param 5,example of GPIBCVTIO */ + {&DSET_SO,GPIBCVTIO,IB_Q_LOW,0,0,0,200,writeCvtio,0,0,0,0,0} + }; + +The command for Param 0 lets the devGpib support do everything as follows: + +- The command "\*IDN?" is sent to the instrument. +- A responds is read back from the instrument. +- device suipport for the stringin record copies the response to the VAL field of + the record. + +The command for Param 1 is similar except that, after the response is read from +the instrument, readString is called. It copies the response to VAL. + +The command for Param 2 causes the devGpib support to call readCvtio without doing +any I/O. The convert routine is responsible for all I/O. + +The command for Param 3 lets the devGpib support do everything as follows: + +- Device support for the stringout record copies the current value of the VAL field + to a message buffer. +- The message buffer is sent to the instrument. + +The command for Param 4 is similar except that writeString is called to move the +value of the VAL field to the message buffer. + +The command for Param 5 causes the devGpib support to call writeCvtio without doing +any I/O. The convert routine is responsible for all I/O. + +The actual code for the convert routines is: +:: + + static int readString(gpibDpvt *pgpibDpvt,int P1, int P2, char **P3) + { + stringinRecord *precord = (stringinRecord*)pgpibDpvt->precord; + strncpy(precord->val,pgpibDpvt->msg,sizeof(precord->val)); + precord->val[sizeof(precord->val) - 1] = 0; + return(0); + } + static int readCvtio(gpibDpvt *pgpibDpvt,int P1, int P2, char **P3) + { + stringinRecord *precord = (stringinRecord*)pgpibDpvt->precord; + asynUser *pasynUser = pgpibDpvt->pasynUser; + gpibCmd *pgpibCmd = gpibCmdGet(pgpibDpvt); + asynOctet *pasynOctet = pgpibDpvt->pasynOctet; + void *asynOctetPvt = pgpibDpvt->asynOctetPvt; + asynStatus status; + size_t nchars = 0, lenmsg = 0; + pgpibDpvt->msgInputLen = 0; + + assert(pgpibCmd->cmd); + lenmsg = strlen(pgpibCmd->cmd); + status = pasynOctet->write(asynOctetPvt,pasynUser, + pgpibCmd->cmd,lenmsg,&nchars); + if(nchars==lenmsg) { + asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE,pgpibCmd->cmd,nchars, + "%s readCvtio\n",precord->name); + } else { + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s write status \"%s\" requested %d but sent %d bytes\n", + precord->name,pasynUser->errorMessage,lenmsg,nchars); + return -1; + } + if(!pgpibDpvt->msg) { + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s pgpibDpvt->msg is null\n",precord->name); + nchars = 0; return -1; + } else { + status = pasynOctet->read(asynOctetPvt,pasynUser, + pgpibDpvt->msg,pgpibCmd->msgLen,&nchars,0); + } + asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s readCvtio nchars %d\n", + precord->name,nchars); + if(nchars > 0) { + asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE,pgpibDpvt->msg,nchars, + "%s readCvtio\n",precord->name); + } else { + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s read status \"%s\" nin %d\n", + precord->name, pasynUser->errorMessage,nchars); + pgpibDpvt->msgInputLen = 0; + return -1; + } + pgpibDpvt->msgInputLen = nchars; + if(ncharspgpibcmd->msgLen) pgpibDpvt->msg[nchars] = 0; + readString(pgpibDpvt,P1,P2,P3); + return 0; + } + + static int writeString(gpibDpvt *pgpibDpvt,int P1, int P2, char **P3) + { + asynUser *pasynUser = pgpibDpvt->pasynUser; + stringoutRecord *precord = (stringoutRecord*)pgpibDpvt->precord; + int nchars; + gpibCmd *pgpibCmd = gpibCmdGet(pgpibDpvt); + char *format = (pgpibCmd->format) ? pgpibCmd->format : "%s"; + + if(!pgpibDpvt->msg) { + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s no msg buffer. Must define gpibCmd.msgLen > 0.\n", + precord->name); + recGblSetSevr(precord,WRITE_ALARM, INVALID_ALARM); + return -1; + } + nchars = epicsSnprintf(pgpibDpvt->msg,pgpibCmd->msgLen,format,precord->val); + if(nchars>pgpibCmd->msgLen) { + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s msg buffer too small. msgLen %d message length %d\n", + precord->name,pgpibCmd->msgLen,nchars); + recGblSetSevr(precord,WRITE_ALARM, INVALID_ALARM); + return -1; + } + asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s writeMsgString\n",precord->name); + return nchars; + } + + static int writeCvtio(gpibDpvt *pgpibDpvt,int P1, int P2, char **P3) + { + stringoutRecord *precord = (stringoutRecord*)pgpibDpvt->precord; + asynUser *pasynUser = pgpibDpvt->pasynUser; + asynOctet *pasynOctet = pgpibDpvt->pasynOctet; + void *asynOctetPvt = pgpibDpvt->asynOctetPvt; + asynStatus status; + size_t nsent = 0, lenmsg = 0; + pgpibDpvt->msgInputLen = 0; + + lenmsg = writeString(pgpibDpvt,P1,P2,P3); + if(lenmsg <= 0) return -1; status=pasynOctet->write(asynOctetPvt,pasynUser, + pgpibDpvt->msg,lenmsg,&nsent); + if(nsent==lenmsg) { + asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE,pgpibDpvt->msg,lenmsg, + "%s writeCvtio\n",precord->name); + } else { + asynPrint(pasynUser,ASYN_TRACE_ERROR, + "%s write status \"%s\" requested %d but sent %d bytes\n", + precord->name,pasynUser->errorMessage,lenmsg,nsent); + return -1; + } + return 0; + } + +devCommonGpib +------------- + +The facilities described above should satisfy most gpib requirements. This section +and the next explain how to provide additional support. For example, support could +be written for additional record types. This section explains devCommonGpib, and +the next section explains devSupportGpib. + +devCommonGpib provides support for specific record types by making calls to devSupportGpib. +As explained above, an instrument support module must define some combination of +DSET_AI,...,DSET_WF and then include devGpib.h. devGpib.h defines DSETs (Device +Support Entry Tables) that refer to methods implemented in devCommonGpib.c + +If you want to write additional support code that can be used for writing instrument +specific device support, the easiest way is to start with code in devCommonGpib +and modify it. + +devGpib provides three header files: + +- devCommonGpib.h - This defines the function prototypes for the methods implemented + in devCommonGpib.c +- devGpib.h - Included in instrument specific device support. It generates DSETs + referring to the functions implemented in devCommonGpib. +- devSupportGpib.h - Describes the structures gpibCmd, devGpibNames, and devGpibParmBlock + described above. It also describes additional structures described in the next section. + +devSupportGpib +-------------- +devSupportGpib.h describes all the public structures used by devGpib. The structures +gpibCmd, devGpibNames, and devGpibParmBlock were described above. They are needed +to create an instrument device support module. The remaining structures are used +by devCommonGpib, devSupportGpib, or other support. These structures are: gDset, +gpibDpvt, devGpibPvt, and devSupportGpib. + +gDset +~~~~~ +A gDset is an "overloaded" definition of a DSET. A gDset looks to iocCore like a +regular DSET, but it has an additional field that is the address of a devGpibParmBlock. +:: + + struct gDset + { + long number; + DEVSUPFUN funPtr[6]; + devGpibParmBlock *pdevGpibParmBlock; + }; + +where + +.. list-table:: gpibCmds + :widths: 20 80 + + * - `number` + - This is required for a DSET. It should always be initialized to 6. + * - `funPtr` + - Pointers to device support functions. Allowing for 6 is sufficient for all the standard + types in EPICS base. + * - `pdevGpibParmBlock` + - The address of the devGpibParmBlock for this instrument. + +gpibDpvt +~~~~~~~~ +The dpvt field of a record with devGpib device support contains the address of a gpibDpvt +:: + + struct gpibDpvt + { + devGpibParmBlock *pdevGpibParmBlock; + CALLBACK callback; + dbCommon *precord; + asynUser *pasynUser; + asynCommon *pasynCommon; + void *pasynCommonPvt; + asynOctet *pasynOctet; + void *pasynOctetPvt; + asynGpib *pasynGpib; + void *pasynGpibPvt; + int parm; /* parameter index into gpib commands */ + char *rsp; /* for read/write message error responses */ + char *msg; /* for read/write messages */ + int msgInputLen; /* number of characters in last READ*/ + int efastVal; /* For GPIBEFASTxxx */ + void *pupvt; /*private pointer for custom code*/ + devGpibPvt *pdevGpibPvt; /*private for devGpibCommon*/ + }; + +where + +.. list-table:: gpibCmds + :widths: 20 80 + + * - `pdevGpibParmBlock` + - Address of the devGpibParmBlock. It is the same value as `pgDset->pdevGpibParmBlock` + * - `callback` + - For use by completeProcess. + * - `precord` + - Address of the record. + * - `pasynUser` + - Address of an asynUser which is needed to call asynDriver support. + * - `pasynCommon,pasynCommonPvt` + - Used to call asynCommon methods. If initialization is successful these will have + a value. + * - `pasynOctet,pasynOctetPvt` + - Used to call asynOctet methods. If initialization is successful these will have + a value. + * - `pasynGpib,pasynGpibPvt` + - Used to call asynGpib methods. These may be 0 even if initialization is successful. + If a record that requires asynGpib is processed and pasynGpib is 0, then an error + message is generated and the record is put into alarm. + * - `parm` + - The value of the parm field of INP or OUT. It locates the gpibCmd for its record. + * - `rsp` + - If respond2Writes is >=0 and rspLen is >0, this is the buffer that holds the + read after each write. + * - `msg` + - A buffer of length msgLen. It is used by several GPIBXXX request types. + * - `msgInputLen` + - The length of the last input message. + * - `efastVal` + - Used for GPIBEFASTO, GPIBEFASTI, GPIBEFASTIW. For GPIBEFASTO the device support + sets efastVal from RVAL or VAL before queuing an I/O request. For GPIBEFASTI and + GPIBEFASTIW, the device support sets RVAL or VAL from efastVal after an I/O request + completes. + * - `pupvt` + - This is a private pointer for use by specialized instrument support. + * - `pdevGpibPvt` + - This is used by devSupportGpib. Note that the structure is described in devSupportGpib.c, + i.e. it is private. + +devSupportGpib +~~~~~~~~~~~~~~ +Describes methods implemented by devSupportGpib.c. +:: + + /* If a method returns int then (0,-1) => (OK, failure) */ + typedef void (*gpibWork)(gpibDpvt *pgpibDpvt,int failure); + typedef int (*gpibStart)(gpibDpvt *pgpibDpvt,int failure); + typedef void (*gpibFinish)(gpibDpvt *pgpibDpvt,int failure); + + typedef int (*gpibWork)(gpibDpvt *pgpibDpvt,int failure); + struct devSupportGpib { + long (*initRecord)(dbCommon *precord, struct link * plink); + void (*processGPIBSOFT)(gpibDpvt *pgpibDpvt); + void (*queueReadRequest)(gpibDpvt *pgpibDpvt,gpibStart start,gpibFinish finish); + void (*queueWriteRequest)(gpibDpvt *pgpibDpvt,gpibStart start, gpibFinish finish); + /* queueRequest returns (0,1) for (failure,success) */ + int (*queueRequest)(gpibDpvt *pgpibDpvt, gpibWork work); + void (*registerSrqHandler)( + gpibDpvt *pgpibDpvt,interruptCallbackInt32 handler,void *userPrivate); + int (*writeMsgLong)(gpibDpvt *pgpibDpvt,long val); + int (*writeMsgULong)(gpibDpvt *pgpibDpvt,unsigned long val); + int (*writeMsgDouble)(gpibDpvt *pgpibDpvt,double val); + int (*writeMsgString)(gpibDpvt *pgpibDpvt,const char *str); + int (*readArbitraryBlockProgramData)(gpibDpvt *pgpibDpvt); + int (*setEos)(gpibDpvt *pgpibDpvt,gpibCmd *pgpibCmd); + int (*restoreEos)(gpibDpvt *pgpibDpvt,gpibCmd *pgpibCmd); + void (*completeProcess)(gpibDpvt *pgpibDpvt); + }; + epicsShareExtern devSupportGpib *pdevSupportGpib; + +.. list-table:: gpibCmds + :widths: 10 90 + + * - `gpibWork` + - Prototype of a function that is called when a request is dequeued by asynManager. + This can be either a function passed to queueRequest or an internal function that + devGpibSupport uses to implement queueReadRequest and queueWriteRequest. + * - `gpibStart` + - If queueReadRequest or queueWriteRequest is called, the internal gpibWork function + calls the start routine before it processes the request. + * - `gpibFinish` + - If queueReadRequest or queueWriteRequest is called, the internal gpibWork function + calls the finish routine when it is done processing. + * - `initRecord` + - This initializes all the devGpib structures attached to the record starting with + dbCommon.dpvt. + * - `processGPIBSOFT` + - If pgpibCmd->type is GPIBSOFT, just call this method. + * - `queueReadRequest` + - This handles GPIBREADW, GPIBEFASTIW, GPIBREAD, GPIBEFASTI, and GPIBRAWREAD. The + only thing device support needs to provide is work functions to do record specific + processing of the received message. The `start` function is called before + devGpibSupport issues write/reads and `finish` is called after the read. + `start` is optional and not usually required for read operations. The + `msg` buffer MUST not be accessed except via the start or finish work + functions. + * - `queueWriteRequest` + - This handles GPIBWRITE, GPIBCMD, GPIBACMD, and GPIBEFASTO. Device support provides + a `start` and `finish` work function. The `start` + function is called before devGpibSupport issues a write and `finish` + is called after the write. The msg buffer MUST not be accessed except via the ` + start` or `finish` work functions. `start` must set + `msg` or `efastVal` depending on the `pgpibCmd->type`. + * - `queueRequest` + - The device support provides a work function that is called when the request is dequeued. + queueRequest returns (0,1) if the request (was not, was) queued. + * - `report` + - This generates a report or all devGpib devices. + * - `registerSrqHandler` + - Registers an SRQ handler for gpibAddr. + * - `writeMsgLong, writeMsgULong, writeMsgDouble, writeMsgString` + - pgpibDpvt->msg is written from pgpibCmd->format and the value passed by the + caller. + * - `readArbitraryBlockProgramData` + - Reads zero or more preamble (non-`#`) characters followed by IEEE-488.2 + definite-length arbitrary block program data followed by the end-of-string specified + by the active gpibCmd entry, and stores the entire response in pgpibDpvt->msg. + This routine is intended for use by custom input functions to read a block of arbitrary + data from a serial-line device. + * - `setEos` + - If the End of String terminator needs to be changed, it must be changed by calling + this rather than calling the low level driver. + * - `restoreEos` + - If code calls setEos it must call restoreEos after all reads are done. + * - `completeProcess` + - If the port can block, callbackRequestProcessCallback is called. If the port can + not block then PACT is set false. Thus before calling queueRequest, the caller should + set PACT true. + * - `pdevSupportGpib` + - An external variable which points to devSupportGpib. + +General GPIB Problems +--------------------- + +NOTE: The following comments are from John Winan's original GPIB documentation. + +Every type of communication system has its problems. Some instrument vendors don't +properly test the GPIB interfaces on their products. Some devices miss messages +or commands that are too close together in time. There are handshaking lines that +are supposed to throttle the speed, but are apparently improperly implemented by +device vendors, or make the (wrong) assumption that the controller in charge is +slow in its ability to burst bytes down the bus. The only way that this problem +can be worked around is to add delays in the GPIB device device support modules. +The current device support library does not provide any means to do this. + +Very often, a device will slow down over 800% when a user presses a button on the +front panel of the device. This can cause the GPIB message transfer to time out, +alarms to be set, and so on. When devices of this type have to be used, operators +will have to be instructed to "look, but don't touch." + +Some devices like to go out to lunch once every hour, or day or so, and not respond +to a command for up to about 5 seconds (the DG 535 has done this on more than one +occasion.) This can be more frustrating that anything else. All that can be said +about these types of things is BEWARE of machines that don't work as advertised. +There is probably something wrong with it that won't surface until it is in use +and controlling something very important. + +Test, test, and test your devices after writing a new device support module. Many +devices can run fine if doing only three or five transactions per second, but crank +it up to 50 or more, and watch it go up in flames. Even if all the records in an +EPICS database are scanned slowly, they can still get processed in bursts. EPICS +can actually process over 20,000 records in one second if they are all ready to +go at the same time. And if there are enough records tied to the same device, there +is no telling how fast the device will be pushed. + +License Agreement +----------------- +:: + + Copyright (c) 2002 University of Chicago, The Regents of the + University of California, and Berliner Elektronenspeicherring + Gesellschaft fuer Synchrotronstrahlung m.b.H. (BESSY) All rights + reserved. + + asynDriver is distributed subject to the following license conditions: + + SOFTWARE LICENSE AGREEMENT + Software: asynDriver + + 1. The "Software", below, refers to asynDriver (in either source code, or + binary form and accompanying documentation). Each licensee is + addressed as "you" or "Licensee." + + 2. The copyright holders shown above and their third-party licensors + hereby grant Licensee a royalty-free nonexclusive license, subject to + the limitations stated herein and U.S. Government license rights. + + 3. You may modify and make a copy or copies of the Software for use + within your organization, if you meet the following conditions: + a. Copies in source code must include the copyright notice and this + Software License Agreement. + b. Copies in binary form must include the copyright notice and this + Software License Agreement in the documentation and/or other + materials provided with the copy. + + 4. You may modify a copy or copies of the Software or any portion of it, + thus forming a work based on the Software, and distribute copies of + such work outside your organization, if you meet all of the following + conditions: + a. Copies in source code must include the copyright notice and this + Software License Agreement; + b. Copies in binary form must include the copyright notice and this + Software License Agreement in the documentation and/or other + materials provided with the copy; + c. Modified copies and works based on the Software must carry + prominent notices stating that you changed specified portions of + the Software. + + 5. Portions of the Software resulted from work developed under a U.S. + Government contract and are subject to the following license: the + Government is granted for itself and others acting on its behalf a + paid-up, nonexclusive, irrevocable worldwide license in this computer + software to reproduce, prepare derivative works, and perform publicly + and display publicly. + + 6. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY + OF ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY LICENSORS, THE + UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND THEIR + EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME + ANY LEGAL LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, + OR USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE + SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT + THAT THE SOFTWARE WILL FUNCTION UNINTERRUPTED, THAT IT IS ERROR-FREE + OR THAT ANY ERRORS WILL BE CORRECTED. + + 7. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, THEIR + THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT + OF ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, INCIDENTAL, + CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF ANY KIND OR NATURE, + INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS OR LOSS OF DATA, FOR ANY + REASON WHATSOEVER, WHETHER SUCH LIABILITY IS ASSERTED ON THE BASIS OF + CONTRACT, TORT (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR + OTHERWISE, EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE + POSSIBILITY OF SUCH LOSS OR DAMAGES. diff --git a/docs/source/doxygen.rst b/docs/source/doxygen.rst new file mode 100644 index 0000000..a0bd3b5 --- /dev/null +++ b/docs/source/doxygen.rst @@ -0,0 +1,2 @@ +`Doxygen documentation `__ +================================================================ diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..445ff4a --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,21 @@ +asyn +==== + +:author: Mark Rivers, University of Chicago + + +Table of Contents +----------------- + +.. toctree:: + :maxdepth: 3 + + asynDriver + asynPortDriver + asynPortClient + asynRecord + asynTimeStampSupport + asynRecordControl + HowToDoSerial + devGpib + doxygen diff --git a/documentation/testAsynPortDriver.png b/docs/source/testAsynPortDriver.png similarity index 100% rename from documentation/testAsynPortDriver.png rename to docs/source/testAsynPortDriver.png diff --git a/documentation/testDigital.png b/docs/source/testDigital.png similarity index 100% rename from documentation/testDigital.png rename to docs/source/testDigital.png diff --git a/docs/source/testErrors.png b/docs/source/testErrors.png new file mode 100755 index 0000000..183d715 Binary files /dev/null and b/docs/source/testErrors.png differ diff --git a/documentation/testInt32.png b/docs/source/testInt32.png similarity index 100% rename from documentation/testInt32.png rename to docs/source/testInt32.png diff --git a/documentation/testOctet.png b/docs/source/testOctet.png similarity index 100% rename from documentation/testOctet.png rename to docs/source/testOctet.png diff --git a/documentation/todo.txt b/docs/todo.txt similarity index 100% rename from documentation/todo.txt rename to docs/todo.txt diff --git a/documentation/.gitignore b/documentation/.gitignore deleted file mode 100644 index 0c4bf69..0000000 --- a/documentation/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -asynDoxygenHTML/ -asynDriver.pdf -asynRecord.pdf -devGpib.pdf - diff --git a/documentation/AsynTimeStampSupport.pdf b/documentation/AsynTimeStampSupport.pdf deleted file mode 100755 index 7d21143..0000000 Binary files a/documentation/AsynTimeStampSupport.pdf and /dev/null differ diff --git a/documentation/HowToDoSerial/AB300/AB300App/Db/Makefile b/documentation/HowToDoSerial/AB300/AB300App/Db/Makefile deleted file mode 100644 index 76decd6..0000000 --- a/documentation/HowToDoSerial/AB300/AB300App/Db/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -TOP=../.. -include $(TOP)/configure/CONFIG - -#---------------------------------------- -# ADD MACRO DEFINITIONS AFTER THIS LINE - -#---------------------------------------------------- -# Optimization of DB files using dbst (DEFAULT: NO) -#DB_OPT = YES - -#---------------------------------------------------- -# Create and install (or just install) -# databases, templates, substitutions like this -#DB_INSTALLS += $(AB300)/db/devAB300.db - -# asynRecord support -DB_INSTALLS += $(ASYN)/db/asynRecord.db - -#---------------------------------------------------- -# If .db template is not named *.template add -# _template = - -include $(TOP)/configure/RULES -#---------------------------------------- -# ADD RULES AFTER THIS LINE - diff --git a/documentation/HowToDoSerial/AB300/AB300App/src/AB300Include.dbd b/documentation/HowToDoSerial/AB300/AB300App/src/AB300Include.dbd deleted file mode 100644 index 28d8ea7..0000000 --- a/documentation/HowToDoSerial/AB300/AB300App/src/AB300Include.dbd +++ /dev/null @@ -1,5 +0,0 @@ -include "base.dbd" - -include "devAB300.dbd" -include "drvAsynIPPort.dbd" -include "drvAsynSerialPort.dbd" diff --git a/documentation/HowToDoSerial/AB300/AB300App/src/AB300Main.cpp b/documentation/HowToDoSerial/AB300/AB300App/src/AB300Main.cpp deleted file mode 100644 index ae0ecb6..0000000 --- a/documentation/HowToDoSerial/AB300/AB300App/src/AB300Main.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* _APPNAME_Main.cpp */ -/* Author: Marty Kraimer Date: 17MAR2000 */ - -#include -#include -#include -#include -#include - -#include "epicsExit.h" -#include "epicsThread.h" -#include "iocsh.h" - -int main(int argc,char *argv[]) -{ - if(argc>=2) { - iocsh(argv[1]); - epicsThreadSleep(.2); - } - iocsh(NULL); - epicsExit(0); - return(0); -} diff --git a/documentation/HowToDoSerial/AB300/AB300App/src/AB300VxInclude.dbd b/documentation/HowToDoSerial/AB300/AB300App/src/AB300VxInclude.dbd deleted file mode 100644 index 984c9c4..0000000 --- a/documentation/HowToDoSerial/AB300/AB300App/src/AB300VxInclude.dbd +++ /dev/null @@ -1,3 +0,0 @@ -registrar(vipc616Registrar) -include "tyGSOctal.dbd" -include "AB300Include.dbd" diff --git a/documentation/HowToDoSerial/AB300/AB300App/src/Makefile b/documentation/HowToDoSerial/AB300/AB300App/src/Makefile deleted file mode 100644 index 865abdd..0000000 --- a/documentation/HowToDoSerial/AB300/AB300App/src/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -TOP=../.. - -include $(TOP)/configure/CONFIG -#---------------------------------------- -# ADD MACRO DEFINITIONS AFTER THIS LINE -#============================= - - -#AB300.dbd will be created from AB300Include.dbd -DBD += AB300.dbd -DBD += AB300Vx.dbd - -## Build and add other local sources like this: - -#The following creates an application -PROD_IOC = AB300 -PROD_vxWorks = AB300Vx - -#============================= - -#AB300_registerRecordDeviceDriver.cpp will be created from AB300.dbd -AB300_SRCS += AB300_registerRecordDeviceDriver.cpp -AB300_SRCS += AB300Main.cpp -AB300_LIBS += devAB300 -AB300_LIBS += asyn -AB300_LIBS += $(EPICS_BASE_IOC_LIBS) - -AB300Vx_SRCS += AB300Vx_registerRecordDeviceDriver.cpp -AB300Vx_LIBS += Ipac TyGSOctal -AB300Vx_LIBS += devAB300 -AB300Vx_LIBS += asyn -AB300Vx_LIBS += $(EPICS_BASE_IOC_LIBS) - - -include $(TOP)/configure/RULES -#---------------------------------------- -# ADD RULES AFTER THIS LINE diff --git a/documentation/HowToDoSerial/AB300/AB300Sup/Makefile b/documentation/HowToDoSerial/AB300/AB300Sup/Makefile deleted file mode 100644 index 696519b..0000000 --- a/documentation/HowToDoSerial/AB300/AB300Sup/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -TOP=.. - -include $(TOP)/configure/CONFIG - -#================================================== -# build a support library - -LIBRARY_IOC += devAB300 -devAB300_SRCS += devAB300 - -devAB300_LIBS += asyn -devAB300_LIBS += $(EPICS_BASE_IOC_LIBS) - -DBD += devAB300.dbd -DB_INSTALLS += devAB300.db - -include $(TOP)/configure/RULES -#---------------------------------------- diff --git a/documentation/HowToDoSerial/AB300/AB300Sup/devAB300.c b/documentation/HowToDoSerial/AB300/AB300Sup/devAB300.c deleted file mode 100644 index 74a5b3e..0000000 --- a/documentation/HowToDoSerial/AB300/AB300Sup/devAB300.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * AB300 device support - */ - -#include -#include - -/****************************************************************************** - * - * The following define statements are used to declare the names to be used - * for the dset tables. - * - * A DSET_AI entry must be declared here and referenced in an application - * database description file even if the device provides no AI records. - * - ******************************************************************************/ -#define DSET_AI devAiAB300 -#define DSET_LI devLiAB300 -#define DSET_LO devLoAB300 - -#include /* must be included after DSET defines */ - -#define TIMEOUT 5.0 /* I/O must complete within this time */ -#define TIMEWINDOW 2.0 /* Wait this long after device timeout */ - -/* - * Custom conversion routines - */ -static int -convertPositionReply(struct gpibDpvt *pdpvt, int P1, int P2, char **P3) -{ - struct longinRecord *pli = ((struct longinRecord *)(pdpvt->precord)); - - if (pdpvt->msgInputLen != 3) { - epicsSnprintf(pdpvt->pasynUser->errorMessage, - pdpvt->pasynUser->errorMessageSize, - "Invalid reply"); - return -1; - } - pli->val = pdpvt->msg[0]; - return 0; -} -static int -convertStatusReply(struct gpibDpvt *pdpvt, int P1, int P2, char **P3) -{ - struct longinRecord *pli = ((struct longinRecord *)(pdpvt->precord)); - - if (pdpvt->msgInputLen != 3) { - epicsSnprintf(pdpvt->pasynUser->errorMessage, - pdpvt->pasynUser->errorMessageSize, - "Invalid reply"); - return -1; - } - pli->val = pdpvt->msg[1]; - return 0; -} - -/****************************************************************************** - * - * Array of structures that define all GPIB messages - * supported for this type of instrument. - * - ******************************************************************************/ - -static struct gpibCmd gpibCmds[] = { - /* Param 0 -- Device Reset */ - {&DSET_LO, GPIBWRITE, IB_Q_LOW, NULL, "\377\377\033", 10, 10, - NULL, 0, 0, NULL, NULL, "\033"}, - - /* Param 1 -- Go to new filter position */ - {&DSET_LO, GPIBWRITE, IB_Q_LOW, NULL, "\017%c", 10, 10, - NULL, 0, 0, NULL, NULL, "\030"}, - - /* Param 2 -- Query filter position */ - {&DSET_LI, GPIBREAD, IB_Q_LOW, "\035", NULL, 0, 10, - convertPositionReply, 0, 0, NULL, NULL, "\030"}, - - /* Param 3 -- Query controller status */ - {&DSET_LI, GPIBREAD, IB_Q_LOW, "\035", NULL, 0, 10, - convertStatusReply, 0, 0, NULL, NULL, "\030"} -}; - -/* The following is the number of elements in the command array above. */ -#define NUMPARAMS sizeof(gpibCmds)/sizeof(struct gpibCmd) - -/****************************************************************************** - * - * Initialize device support parameters - * - *****************************************************************************/ -static long init_ai(int pass) -{ - if(pass==0) { - devSupParms.name = "devAB300"; - devSupParms.gpibCmds = gpibCmds; - devSupParms.numparams = NUMPARAMS; - devSupParms.timeout = TIMEOUT; - devSupParms.timeWindow = TIMEWINDOW; - devSupParms.respond2Writes = 0; - } - return(0); -} diff --git a/documentation/HowToDoSerial/AB300/AB300Sup/devAB300.db b/documentation/HowToDoSerial/AB300/AB300Sup/devAB300.db deleted file mode 100644 index 719f759..0000000 --- a/documentation/HowToDoSerial/AB300/AB300Sup/devAB300.db +++ /dev/null @@ -1,32 +0,0 @@ -record(longout, "$(P)$(R)FilterWheel:reset") -{ - field(DESC, "Reset AB300 Controller") - field(SCAN, "Passive") - field(DTYP, "AB300") - field(OUT, "#L$(L) A$(A) @0") -} -record(longout, "$(P)$(R)FilterWheel") -{ - field(DESC, "Set Filter Wheel Position") - field(SCAN, "Passive") - field(DTYP, "AB300") - field(OUT, "#L$(L) A$(A) @1") - field(LOPR, 1) - field(HOPR, 6) -} -record(longin, "$(P)$(R)FilterWheel:fbk") -{ - field(DESC, "Filter Wheel Position") - field(SCAN, "Passive") - field(DTYP, "AB300") - field(INP, "#L$(L) A$(A) @2") - field(LOPR, 1) - field(HOPR, 6) -} -record(longin, "$(P)$(R)FilterWheel:status") -{ - field(DESC, "Filter Wheel Status") - field(SCAN, "Passive") - field(DTYP, "AB300") - field(INP, "#L$(L) A$(A) @3") -} diff --git a/documentation/HowToDoSerial/AB300/AB300Sup/devAB300.dbd b/documentation/HowToDoSerial/AB300/AB300Sup/devAB300.dbd deleted file mode 100644 index b36e949..0000000 --- a/documentation/HowToDoSerial/AB300/AB300Sup/devAB300.dbd +++ /dev/null @@ -1,3 +0,0 @@ -device(ai, GPIB_IO, devAiAB300, "AB300") -device(longin, GPIB_IO, devLiAB300, "AB300") -device(longout, GPIB_IO, devLoAB300, "AB300") diff --git a/documentation/HowToDoSerial/AB300/Makefile b/documentation/HowToDoSerial/AB300/Makefile deleted file mode 100644 index 8c3eeab..0000000 --- a/documentation/HowToDoSerial/AB300/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# Makefile for Asyn _NAME_ support -# -# Created by _USER_ on _DATE_ -# Based on the Asyn _TYPE_ template - -TOP = . -include $(TOP)/configure/CONFIG - -DIRS += configure -DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Sup)) -DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *sup)) -DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *App)) -DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *app)) -DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard iocBoot)) -DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard iocboot)) - -include $(TOP)/configure/RULES_TOP diff --git a/documentation/HowToDoSerial/AB300/configure/CONFIG b/documentation/HowToDoSerial/AB300/configure/CONFIG deleted file mode 100644 index c1a4703..0000000 --- a/documentation/HowToDoSerial/AB300/configure/CONFIG +++ /dev/null @@ -1,29 +0,0 @@ -# CONFIG - Load build configuration data -# -# Do not make changes to this file! - -# Allow user to override where the build rules come from -RULES = $(EPICS_BASE) - -# RELEASE files point to other application tops -include $(TOP)/configure/RELEASE --include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common -ifdef T_A --include $(TOP)/configure/RELEASE.Common.$(T_A) --include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) -endif - -CONFIG = $(RULES)/configure -include $(CONFIG)/CONFIG - -# Override the Base definition: -INSTALL_LOCATION = $(TOP) - -# CONFIG_SITE files contain other build configuration settings -include $(TOP)/configure/CONFIG_SITE --include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common -ifdef T_A - -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) - -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) -endif - diff --git a/documentation/HowToDoSerial/AB300/configure/CONFIG_SITE b/documentation/HowToDoSerial/AB300/configure/CONFIG_SITE deleted file mode 100644 index 212485e..0000000 --- a/documentation/HowToDoSerial/AB300/configure/CONFIG_SITE +++ /dev/null @@ -1,43 +0,0 @@ -# CONFIG_SITE - -# Make any application-specific changes to the EPICS build -# configuration variables in this file. -# -# Host/target specific settings can be specified in files named -# CONFIG_SITE.$(EPICS_HOST_ARCH).Common -# CONFIG_SITE.Common.$(T_A) -# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) - -# CHECK_RELEASE controls the consistency checking of the support -# applications pointed to by the RELEASE* files. -# Normally CHECK_RELEASE should be set to YES. -# Set CHECK_RELEASE to NO to disable checking completely. -# Set CHECK_RELEASE to WARN to perform consistency checking but -# continue building even if conflicts are found. -CHECK_RELEASE = YES - -# Set this when you only want to compile this application -# for a subset of the cross-compiled target architectures -# that Base is built for. -#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32 - -# To install files into a location other than $(TOP) define -# INSTALL_LOCATION here. -#INSTALL_LOCATION= - -# Set this when the IOC and build host use different paths -# to the install location. This may be needed to boot from -# a Microsoft FTP server say, or on some NFS configurations. -#IOCS_APPL_TOP = - -# For application debugging purposes, override the HOST_OPT and/ -# or CROSS_OPT settings from base/configure/CONFIG_SITE -#HOST_OPT = NO -#CROSS_OPT = NO - -# These allow developers to override the CONFIG_SITE variable -# settings without having to modify the configure/CONFIG_SITE -# file itself. --include $(TOP)/../CONFIG_SITE.local --include $(TOP)/configure/CONFIG_SITE.local - diff --git a/documentation/HowToDoSerial/AB300/configure/Makefile b/documentation/HowToDoSerial/AB300/configure/Makefile deleted file mode 100644 index 9254309..0000000 --- a/documentation/HowToDoSerial/AB300/configure/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -TOP=.. - -include $(TOP)/configure/CONFIG - -TARGETS = $(CONFIG_TARGETS) -CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) - -include $(TOP)/configure/RULES diff --git a/documentation/HowToDoSerial/AB300/configure/RELEASE b/documentation/HowToDoSerial/AB300/configure/RELEASE deleted file mode 100644 index 016656d..0000000 --- a/documentation/HowToDoSerial/AB300/configure/RELEASE +++ /dev/null @@ -1,10 +0,0 @@ -#RELEASE Location of external products -# Run "gnumake clean uninstall install" in the application -# top directory each time this file is changed. - -TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top - -# EPICS_BASE usually appears last so other apps can override stuff: -EPICS_BASE=/home/phoebus/NORUME/src/EPICS/base_R3_14_2_branch -IPAC=/home/phoebus/NORUME/src/EPICS/modules/bus/ipac -ASYN=/home/phoebus/NORUME/src/EPICS/modules/soft/asyn diff --git a/documentation/HowToDoSerial/AB300/configure/RULES b/documentation/HowToDoSerial/AB300/configure/RULES deleted file mode 100644 index 6d56e14..0000000 --- a/documentation/HowToDoSerial/AB300/configure/RULES +++ /dev/null @@ -1,6 +0,0 @@ -# RULES - -include $(CONFIG)/RULES - -# Library should be rebuilt because LIBOBJS may have changed. -$(LIBNAME): ../Makefile diff --git a/documentation/HowToDoSerial/AB300/configure/RULES.ioc b/documentation/HowToDoSerial/AB300/configure/RULES.ioc deleted file mode 100644 index 901987c..0000000 --- a/documentation/HowToDoSerial/AB300/configure/RULES.ioc +++ /dev/null @@ -1,2 +0,0 @@ -#RULES.ioc -include $(CONFIG)/RULES.ioc diff --git a/documentation/HowToDoSerial/AB300/configure/RULES_DIRS b/documentation/HowToDoSerial/AB300/configure/RULES_DIRS deleted file mode 100644 index 3ba269d..0000000 --- a/documentation/HowToDoSerial/AB300/configure/RULES_DIRS +++ /dev/null @@ -1,2 +0,0 @@ -#RULES_DIRS -include $(CONFIG)/RULES_DIRS diff --git a/documentation/HowToDoSerial/AB300/configure/RULES_TOP b/documentation/HowToDoSerial/AB300/configure/RULES_TOP deleted file mode 100644 index d09d668..0000000 --- a/documentation/HowToDoSerial/AB300/configure/RULES_TOP +++ /dev/null @@ -1,3 +0,0 @@ -#RULES_TOP -include $(CONFIG)/RULES_TOP - diff --git a/documentation/HowToDoSerial/AB300/iocBoot/Makefile b/documentation/HowToDoSerial/AB300/iocBoot/Makefile deleted file mode 100644 index 252a137..0000000 --- a/documentation/HowToDoSerial/AB300/iocBoot/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -TOP = .. -include $(TOP)/configure/CONFIG -include $(TOP)/configure/RULES.iocBoot diff --git a/documentation/HowToDoSerial/AB300/iocBoot/iocAB300/Makefile b/documentation/HowToDoSerial/AB300/iocBoot/iocAB300/Makefile deleted file mode 100644 index 62fdf57..0000000 --- a/documentation/HowToDoSerial/AB300/iocBoot/iocAB300/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -TOP = ../.. -include $(TOP)/configure/CONFIG -ARCH = vxWorks-68040 -TARGETS += cdCommands -TARGETS += envPaths -#nothing to do -include $(TOP)/configure/RULES.ioc - diff --git a/documentation/HowToDoSerial/AB300/iocBoot/iocAB300/st.cmd b/documentation/HowToDoSerial/AB300/iocBoot/iocAB300/st.cmd deleted file mode 100644 index 927fa5e..0000000 --- a/documentation/HowToDoSerial/AB300/iocBoot/iocAB300/st.cmd +++ /dev/null @@ -1,24 +0,0 @@ -dbLoadDatabase("../../dbd/AB300.dbd",0,0) -AB300_registerRecordDeviceDriver(pdbbase) -dbLoadRecords("../../db/devAB300.db","P=AB300:,R=,L=0,A=0") - -# Create a diagnostic asynRecord -cd ${AB300} -dbLoadRecords("db/asynRecord.db","P=AB300,R=Test,PORT=L0,ADDR=0,IMAX=0,OMAX=0") - -#The following command is for a serial line terminal concentrator -drvAsynIPPortConfigure("L0","164.54.3.137:4001",0,0,0) - -#The following commands are for a local serial line -#drvAsynSerialPortConfigure("L0","/dev/ttyS0",0,0,0) -#asynSetOption("L0", -1, "baud", "9600") -#asynSetOption("L0", -1, "bits", "8") -#asynSetOption("L0", -1, "parity", "none") -#asynSetOption("L0", -1, "stop", "1") -#asynSetOption("L0", -1, "clocal", "Y") -#asynSetOption("L0", -1, "crtscts", "N") - -asynSetTraceMask("L0",-1,0x9) -asynSetTraceIOMask("L0",-1,0x2) - -iocInit() diff --git a/documentation/HowToDoSerial/AB300/iocBoot/iocAB300/vx b/documentation/HowToDoSerial/AB300/iocBoot/iocAB300/vx deleted file mode 100644 index 37a828f..0000000 --- a/documentation/HowToDoSerial/AB300/iocBoot/iocAB300/vx +++ /dev/null @@ -1,37 +0,0 @@ -# Example vxWorks startup file - -# Following must be added for many board support packages -#cd -cd "src/EPICS/modules/soft/asyn/documentation/HowToDoSerial/AB300/iocBoot/iocAB300" - -< cdCommands - -cd topbin -ld < AB300Vx.munch -cd startup - -dbLoadDatabase("../../dbd/AB300.dbd",0,0) -AB300Vx_registerRecordDeviceDriver(pdbbase) - -dbLoadRecords("../../db/AB300.db","user=AB300") - -#The following command is for a serial line terminal concentrator -#drvGenericSerialConfigure("L0","164.54.9.91:4002",0,0) - -#The following commands are for a Greenspring octal UART and VIP616-01 carrier -ipacAddVIPC616_01("0x6000,B0000000") -tyGSOctalDrv(1) -tyGSOctalModuleInit("RS232", 0x80, 0, 0) -tyGSOctalDevCreate("/tyGS/0/0",0,0,1000,1000) -drvGenericSerialConfigure("L0","/tyGS/0/0",0,0) -asynSetPortOption("L0", "baud", "9600") -asynSetPortOption("L0", "bits", "8") -asynSetPortOption("L0", "parity", "none") -asynSetPortOption("L0", "stop", "1") -asynSetPortOption("L0", "clocal", "Y") -asynSetPortOption("L0", "crtscts", "N") - -asynSetTraceMask("L0",0,0xff) -asynSetTraceIOMask("L0",0,0x2) - -iocInit() diff --git a/documentation/HowToDoSerial/HowToDoSerial_StreamDevice.html b/documentation/HowToDoSerial/HowToDoSerial_StreamDevice.html deleted file mode 100755 index 9616382..0000000 --- a/documentation/HowToDoSerial/HowToDoSerial_StreamDevice.html +++ /dev/null @@ -1,692 +0,0 @@ - - - - HowToDoSerial(StreamDevice) - - - -

- How to use StreamDevice and ASYN to create EPICS device support for a simple serial, - GPIB, or network attached device

-
- W. Eric Norum wenorum@lbl.gov -
-

- 1 Introduction

-

- This tutorial provides step-by-step instructions on how to create EPICS support - for a simple serial, GPIB (IEEE-488) or network attached device. The steps are presented - in a way that should make it possible to apply them in cookbook fashion to create - support for other devices. For comprehensive description of all the details of the - I/O system used here, refer to the - asynDriver and StreamDevice - documentation. -

-

- This document isn't for the absolute newcomer though. You must have EPICS installed - on a system somewhere and know how to build and run the example application. In - particular you must have the following installed: -

-
    -
  • EPICS R3.14.11 or higher.
  • -
  • EPICS ASYN support module version 4.14 or higher.
  • -
  • EPICS StreamDevice support module version 2.4.1 or higher.
  • -
-

- Serial, GPIB and network attached devices can now be treated in much the same way. - The EPICS StreamDevice and ASYN support modules can use drivers which communicate - with serial devices connected to ports on the IOC or to Ethernet/Serial converters - or with GPIB devices connected to local I/O cards or to Ethernet/GPIB converters - or to network attached devices using VXI-11 or plain TCP ('telnet') communication - protocols. -

-

- I based this tutorial on the device support I wrote for a Hewlett Packard E3631A - power supply. I chose the E3610A as the basis for this tutorial partly because it - was what I found lying around but mostly because it uses SCPI-compliant commands - which are common to a wide range of devices. Sections 1 through 4 of this tutorial - apply to all SCPI (IEEE-488.2) devices. -

-

- 2 Create a new device support module

-

- The easiest way to do this is with the makeSupport.pl script supplied with the EPICS - ASYN package. -

-

- Here are the commands I ran. To make the command examples a little shorter I used - shell variables to hold the paths to my installation of EPICS base and the ASYN - support module. You can do this with values appropriate for your site or just type - the full path names to the commands. -

-
-EPICS_BASE=/usr/local/epics/R3.14.11/base 
-ASYN=/usr/local/epics/R3.14.11/modules/soft/synApps_5_5/support/asyn-4-14 
-  
-

- You will have to change these to the values appropriate for your EPICS installation - or simply type the appropriate full paths to invoke the scripts. You must also have - the EPICS_HOST_ARCH environment variable set to match the machine on which you are - building. -

-

- To create a new StreamDevice support module: -

-
-norume> mkdir HPE3631A
-norume> cd HPE3631A
-norume> $ASYN/bin/$EPICS_HOST_ARCH/makeSupport.pl -t streamSCPI HPE3631A 
-   
-

- 2.1 Make changes to some files in configure/

-

- Edit the configure/RELEASE file which makeSupport.pl created and confirm that the - entries describing the paths to your EPICS base and ASYN support are correct. For - example these might be: -

-
-ASYN = /usr/local/epics/R3.14.11/modules/soft/synApps_5_5/support/asyn-4-14 
-EPICS_BASE = /usr/local/epics/R3.14.11/base 
-
-

- You'll also have to add a line describing the path to your StreamDevice support. - For example: -

-
-STREAM = /usr/local/epics/R3.14.11/modules/soft/synApps_5_5/support/stream-2-4-1 
-   
-

- Edit the configure/CONFIG_SITE file which makeSupport.pl created and specify the - IOC architectures on which the application is to run. I wanted the application to - run as a soft IOC, so I uncommented the CROSS_COMPILER_TARGET_ARCHS definition and - set the definition to be empty: -

-
-   CROSS_COMPILER_TARGET_ARCHS = 
-   
-

- You may have to fix an error in the HPE3631ASup/devHPE3631A.db file produced by - the makeSupport.pl command. Verify that the IDNwf record description looks like:

-
 
-record(waveform, "$(P)$(R)IDNwf") 
-{
-    field(DESC, "SCPI identification string")
-    field(DTYP, "stream") 
-    field(INP,  "@devHPE3631A.proto getIDN(199) $(PORT) $(A)")
-    field(PINI, "YES") 
-    field(FTVL, "CHAR") 
-    field(NELM, "200") 
-} 
-  
-

- Some versions of the template have FTYP rather than FTVL for the waveform data type - field. -

-

- I install the StreamDevice protocol file into the support module db/ directory. - This seems like a reasonable place to put this file since it's tied closely to its - associated database file. To have the protocol file installed into the db/ directory - edit HPE3631ASup/Makefile and add the line -

-
-DB_INSTALLS += $(TOP)/HPE3631ASup/devHPE3631A.proto 
-  
-

- to the list of DB_INSTALLS. -

-

- 3 Create a test application (optional)

-

- Now that a device support module has been produced it is a good idea to create a - new EPICS application to confirm that the device support is operating correctly. - The easiest way to do this is with the makeBaseApp.pl script supplied with EPICS. - The files in the configure/ directory produced in the previous step do not provide - all the information needed to build an application but will not be overwritten by - the makeBaseApp.pl script. The easiest solution to this problem is to simply remove - the configure/ directory and all its contents and then to make the changes to configure/RELEASE - and configure/CONFIG_SITE at mentioned above.

-

- Here are the commands I ran. -

-
-norume> rm -rf configure
-norume> $EPICS_BASE/bin/$EPICS_HOST_ARCH/makeBaseApp.pl -t ioc HPE3631Atest
-norume> $EPICS_BASE/bin/$EPICS_HOST_ARCH/makeBaseApp.pl -t ioc -i HPE3631Atest
-The following target architectures are available in base:
-    darwin-x86
-    RTEMS-mvme2100 
-    RTEMS-mvme3100 
-    RTEMS-uC5282
-What architecture do you want to use? darwin-x86
-The following applications are available: 
-    HPE3631Atest
-What application should the IOC(s) boot? 
-The default uses the IOC's name, even if not listed above.
-Application name? 
-norume> 
-  
-

- I then added the ASYN and STREAM values to configure/RELEASE and made the change - to the CROSS_COMPILER_TARGET_ARCHS line in configure/CONFIG_SITE.

-

- You must add the StreamDevice and ASYN support modules to the test application. - Edit HPE3631AtestApp/src/Makefile and add the lines:

-
-HPE3631Atest_DBD += stream.dbd
-HPE3631Atest_DBD += asyn.dbd
-HPE3631Atest_DBD += drvAsynSerialPort.dbd 
-and
-HPE3631Atest_LIBS += stream asyn 
-  
-

- To install the support module files and build the test application simply run make:

-
-norume> make
-    .
-    .
-    .
-norume>
-  
-

- The IOC startup script produced by the makeBaseApp.pl script must be modified before - the test application can be run. Change directories to iocBoot/iocHPE3631Atest and - edit the st.cmd file. Here's the file that I use:

-
-  1 #!../../bin/darwin-x86/HPE3631Atest 
-  2
-  3 ############################################################################### 
-  4 # Set up environment 
-  5 < envPaths 
-  6 epicsEnvSet "STREAM_PROTOCOL_PATH" "$(TOP)/db" 
-  7
- 
-  8 ############################################################################### 
-  9 # Allow PV name prefixes and serial port name to be set from the environment 
- 10 epicsEnvSet "P" "$(P=hpE3631A)" 
- 11 epicsEnvSet "R" "$(R=Test)" 
- 12 epicsEnvSet "TTY" "$(TTY=/dev/tty.PL2303-000013FA)" 
- 13
- 
- 14 ############################################################################### 
- 15 ## Register all support components 
- 16 cd "${TOP}" 
- 17 dbLoadDatabase "dbd/HPE3631Atest.dbd" 
- 18 HPE3631Atest_registerRecordDeviceDriver pdbbase 
- 19
- 
- 20 ############################################################################### 
- 21 # Set up ASYN ports 
- 22 # drvAsynSerialPortConfigure port ipInfo priority noAutoconnect noProcessEos 
- 23 drvAsynSerialPortConfigure("L0","$(TTY)",0,0,0) 
- 24 asynSetOption("L0", -1, "baud", "9600") 
- 25 asynSetOption("L0", -1, "bits", "8") 
- 26 asynSetOption("L0", -1, "parity", "none") 
- 27 asynSetOption("L0", -1, "stop", "2") 
- 28 asynSetOption("L0", -1, "clocal", "Y") 
- 29 asynSetOption("L0", -1, "crtscts", "Y") 
- 30 asynOctetSetInputEos("L0", -1, "\n") 
- 31 asynOctetSetOutputEos("L0", -1, "\n") 
- 32 asynSetTraceIOMask("L0",-1,0x2) 
- 33 asynSetTraceMask("L0",-1,0x9) 
- 34
- 
- 35 ############################################################################### 
- 36 ## Load record instances 
- 37 dbLoadRecords("db/devHPE3631A.db","P=$(P),R=$(R),PORT=L0,A=0") 
- 38
- 
- 39 ############################################################################### 
- 40 ## Start EPICS 
- 41 cd "${TOP}/iocBoot/${IOC}" 
- 42 iocInit 
-  
-

- Lines that you'll likely have to modify are: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 10,11 - The prefix applied to all PV names.
- 12 - The name of your serial line (for network attached devices or LAN/Serial adapters - this will be something like 192.168.0.23:4001).
- 23 - The command would be drvAsynIPPortConfigure for LAN/Serial adapters or network attached - devices. See the asynDriver documentation for information on connecting to GPIB - devices.
- 24-29 - The serial line settings for your device (for network attached devices or LAN/Serial - adapters or GPIB devices these lines can be removed or commented out).
- 30,31 - GPIB devices may not need line terminators since they can use the EOI line to mark - the end of messages.
- 33 - This trace mask value prints a message showing the characters sent to and received - from the device. This can produce a lot of messages on the IOC console. To display - error messages only set the trace mask to 1 rather than 9.
-

- So, if you have a LAN/Serial adapter or network attached device which uses a raw - TCP ('telnet' style) connection you would replace lines 23 through 29 with a single - line like: -

-
-drvAsynIPPortConfigure("L0","192.168.0.23:4001",0,0,0) 
-  
-

- You would also change the application Makefile to specify drvAsynIPPort.dbd rather - than drvAsynSerialPort.dbd. -

-

- I you have a VXI-11 LAN/GPIB adapter or network attached device you would replace - lines 23 through 31 with a single line like: -

-
-vxi11Configure("L0","192.168.0.24",0,0.0,"gpib0",0,0) 
-  
-

- You would also change the application Makefile to specify drfvVxi11.dbd rather than - drvAsynSerialPort.dbd. -

-

- 3.1 Run the test application

-

- The application can be started by running the startup script if you make the script - executable:

-
-norume> cd iocBoot/iocHPE3631Atest
-norume> chmod +x st.cmd
-
-

- Then the application can be run by:

-
-norume> ./st.cmd
-#!../../bin/darwin-x86/HPE3631Atest 
-###############################################################################
-# Set up environment
-< envPaths
-epicsEnvSet("ARCH","darwin-x86") 
-epicsEnvSet("IOC","iocHPE3631Atest") 
-epicsEnvSet("TOP","/Users/wenorum/tmp/t/HPE3631A") 
-epicsEnvSet("ASYN","/usr/local/epics/R3.14.11/modules/soft/synApps_5_5/support/asyn-4-14") 
-epicsEnvSet("STREAM","/usr/local/epics/R3.14.11/modules/soft/synApps_5_5/support/stream-2-4-1") 
-epicsEnvSet("EPICS_BASE","/usr/local/epics/R3.14.11/base") 
-epicsEnvSet "STREAM_PROTOCOL_PATH" "/Users/wenorum/tmp/t/HPE3631A/db" 
-############################################################################### 
-# Allow PV name prefixes and serial port name to be set from the environment
-epicsEnvSet "P" "hpE3631A"
-epicsEnvSet "R" "Test"
-epicsEnvSet "TTY" "/dev/tty.PL2303-000013FA"
-###############################################################################
-## Register all support components 
-cd "/Users/wenorum/tmp/t/HPE3631A" 
-dbLoadDatabase "dbd/HPE3631Atest.dbd" 
-HPE3631Atest_registerRecordDeviceDriver pdbbase 
-############################################################################### 
-# Set up ASYN ports
-# drvAsynSerialPortConfigure port ipInfo priority noAutoconnect noProcessEos
-drvAsynSerialPortConfigure("L0","/dev/tty.PL2303-000013FA",0,0,0)
-asynSetOption("L0", -1, "baud", "9600") 
-asynSetOption("L0", -1, "bits", "8") 
-asynSetOption("L0", -1, "parity", "none") 
-asynSetOption("L0", -1, "stop", "2") 
-asynSetOption("L0", -1, "clocal", "Y") 
-asynSetOption("L0", -1, "crtscts", "Y") 
-asynOctetSetInputEos("L0", -1, "\n") 
-asynOctetSetOutputEos("L0", -1, "\n") 
-asynSetTraceIOMask("L0",-1,0x2)
-asynSetTraceMask("L0",-1,0x9)
-############################################################################### 
-## Load record instances
-dbLoadRecords("db/devHPE3631A.db","P=hpE3631A,R=Test,PORT=L0,A=0")
-###############################################################################
-## Start EPICS
-cd "/Users/wenorum/tmp/t/HPE3631A/iocBoot/iocHPE3631Atest"
-iocInit
-Starting iocInit
-############################################################################
-## EPICS R3.14.11 $R3-14-11$ $2009/08/28 18:47:36$
-## EPICS Base built Aug 24 2010
-############################################################################
-2010/08/31 13:10:32.986 /dev/tty.PL2303-000013FA write 6
-*IDN?\n
-iocRun: All initialization complete
-2010/08/31 13:10:33.116 /dev/tty.PL2303-000013FA read 1
-H
-2010/08/31 13:10:33.135 /dev/tty.PL2303-000013FA read 1
-E
-2010/08/31 13:10:33.153 /dev/tty.PL2303-000013FA read 1
-W
-2010/08/31 13:10:33.171 /dev/tty.PL2303-000013FA read 1
-L
-2010/08/31 13:10:33.189 /dev/tty.PL2303-000013FA read 1
-E
-2010/08/31 13:10:33.208 /dev/tty.PL2303-000013FA read 1
-T
-2010/08/31 13:10:33.226 /dev/tty.PL2303-000013FA read 1
-T 
-.
-.
-.
-epics>dbpr hpE3631ATestIDN
-ASG:               
-DESC: SCPI identification string        
-DISA: 0  
-DISP: 0            
-DISV: 1            
-NAME: hpE3631ATestIDN                  
-SEVR: NO_ALARM      STAT: NO_ALARM     
-SVAL:              
-TPRO: 0            
-VAL: HEWLETT-PACKARD,E3631A,0,2.1-5.0-1.0                  
-
-epics>
-
-

- The SCPI IDN*? commands are run as part of iocInit since their records have PINI=YES. - If the stringin record has truncated the identification string you should be able - to see the full string as a waveform record. In another window run:

-
-norume> caget -S hpE3631ATestIDNwf
-hpE3631ATestIDNwf HEWLETT-PACKARD,E3631A,0,2.1-5.0-1.0
-norume>
-  
-

- 4 asynRecord support

-

- The asynRecord provides a convenient mechanism for controlling the diagnostic messages - produced by asyn drivers. You can also use the MEDM asynOctet screen to manually - send commands to and view responses from a device. This can be very handy when trying - to figure out just how a new device actually works.

-

- To use an asynRecord in your application: -

-

- Add the line:

-
-DB_INSTALLS += $(ASYN)/db/asynRecord.db 
-  
-

- to the application Makefile.

-

- Create the diagnostic record in the IOC by adding a line like:

-
-dbLoadRecords("db/asynRecord.db","P=$(P)$(R),R=asyn,PORT=L0,ADDR=-1,OMAX=0,IMAX=0") 
-  
-

- to the application startup script. The PORT value must match the the value in the - corresponding drvAsynIPPortConfigure or drvAsynSerialPortConfigure command. The - ADDR value should be that of the instrument whose I/O you wish to monitor. -

-

- To run the asynRecord screen, add<asynTop>/opi/medm to your EPICS_DISPLAY_PATH - environment variable and start medm with P, R, PORT and ADDR values matching those - given in the dbLoadRecords command:

-
-medm -x -macro "P=hpE3631ATest,R=asyn,PORT=L0,ADDR=-1" asynRecord.adl 
-  
-

- If you have edm installed then you need to use the asynRecord.edl file instead. - Ensure that<asynTop>/opi/medm is in the EDMDATAFILES environment variable. - Start edm with the arguments appropriate for your IOC:

-
-edm -x -m "P=hpE3631ATest, R=asyn,PORT=L1_TCP,ADDR=-1" asynRecord.edl 
-  
-

- 5 Add records and protocol file entries

-

- The descriptions in this section apply directly to the HP E3631A only but may provide - useful hints for adding commands for your particular device.

-

- 5.1 Add a record to set the device to local or remote control

-

- First add an entry to HPE3631ASup/devHPE3631A.proto:

-
-setLocRem {
-    out "SYST:%{LOC|REM}";
-}
-  
-

- This uses the StreamDevice ENUM converter to send one of two strings to the device - based on the PV value. The corresponding addition to HPE3631ASup/devHPE3631A.db - is:

-
-record(bo, "$(P)$(R)SetRemote")
-{
-    field(DESC, "Set into local/remote mode")
-    field(DTYP, "stream")
-    field(OUT,  "@devHPE3631A.proto setLocRem $(PORT) $(A)")
-    field(ZNAM, "Local")
-    field(ONAM, "Remote")
-    field(PINI, "YES")
-    field(VAL,  "1")
-}
-  
-

- The PINI and VAL fields ensure that the device is set into remote control mode during - IOC startup.

-

- Once you've made the above changes run make to install the modified files. - If you've created the test application you can try out the new command and see if - it works.

-

- 5.2 Add records to set and check the output on/off status

-

- These are simple since they use StreamDevice protocol entries that already exist. - The setD and getD entries set and get the value of a single integer parameter whose - command is passed as the argument to the protocol entry:

-
-record(bo, "$(P)$(R)SetOnOff")
-{
-    field(DESC, "Turn output off/on")
-    field(DTYP, "stream")
-    field(OUT,  "@devHPE3631A.proto setD(OUTP) $(PORT) $(A)")
-    field(ZNAM, "Off")
-    field(ONAM, "On")
-}
-record(bi, "$(P)$(R)GetOnOff")
-{
-    field(DESC, "Is output on?")
-    field(DTYP, "stream")
-    field(INP,  "@devHPE3631A.proto getD(OUTP) $(PORT) $(A)")
-    field(ZNAM, "Off")
-    field(ONAM, "On")
-}
-
-

- 5.3 Add records to set and check the output voltage and current setpoints

-

- Add two entries to HPE3631ASup/devHPE3631A.proto:

-
-setVI {
-    out "INST \$1;\$2 %g";
-}
-getVI {
-    out "INST \$1;\$2?";
-    in "%g";
-    ExtraInput = Ignore;
-}
-
-

- These entries set and get the floating point value for the channel passed as the - first argument and for the parameter passed as the second argument.

-

- The corresponding additions to HPE3631ASup/devHPE3631A.db are:

-
-record(ao, "$(P)$(R)SetP6Volts")
-{
-    field(DESC, "Set +6V output volage")
-    field(DTYP, "stream")
-    field(OUT,  "@devHPE3631A.proto setVI(P6V,VOLT) $(PORT) $(A)")
-    field(EGU,  "Volts")
-    field(LOPR, "0")
-    field(HOPR, "6.18")
-    field(EGUL, "0")
-    field(EGUF, "6.18")
-    field(DRVL, "0")
-    field(DRVH, "6.18")
-}
-record(ao, "$(P)$(R)SetP6Amps")
-{
-    field(DESC, "Set +6V output current")
-    field(DTYP, "stream")
-    field(OUT,  "@devHPE3631A.proto setVI(P6V,CURR) $(PORT) $(A)")
-    field(EGU,  "Amps")
-    field(LOPR, "0")
-    field(HOPR, "5.15")
-    field(EGUL, "0")
-    field(EGUF, "5.15")
-    field(DRVL, "0")
-    field(DRVH, "5.15")
-}
-record(ao, "$(P)$(R)SetP25Volts")
-{
-    field(DESC, "Set +25V output volage")
-    field(DTYP, "stream")
-    field(OUT,  "@devHPE3631A.proto setVI(P25V,VOLT) $(PORT) $(A)")
-    field(EGU,  "Volts")
-    field(LOPR, "0")
-    field(HOPR, "25.75")
-    field(EGUL, "0")
-    field(EGUF, "25.75")
-    field(DRVL, "0")
-    field(DRVH, "25.75")
-}
-record(ao, "$(P)$(R)SetP25Amps")
-{
-    field(DESC, "Set +25V output current")
-    field(DTYP, "stream")
-    field(OUT,  "@devHPE3631A.proto setVI(P25V,CURR) $(PORT) $(A)")
-    field(EGU,  "Amps")
-    field(LOPR, "0")
-    field(HOPR, "1.03")
-    field(EGUL, "0")
-    field(EGUF, "1.03")
-    field(DRVL, "0")
-    field(DRVH, "1.03")
-}
-record(ao, "$(P)$(R)SetN25Volts")
-{
-    field(DESC, "Set -25V output volage")
-    field(DTYP, "stream")
-    field(OUT,  "@devHPE3631A.proto setVI(N25V,VOLT) $(PORT) $(A)")
-    field(EGU,  "Volts")
-    field(HOPR, "0")
-    field(LOPR, "-25.75")
-    field(EGUF, "0")
-    field(EGUL, "-25.75")
-    field(DRVH, "0")
-    field(DRVL, "-25.75")
-}
-record(ao, "$(P)$(R)SetN25Amps")
-{
-    field(DESC, "Set -25V output current")
-    field(DTYP, "stream")
-    field(OUT,  "@devHPE3631A.proto setVI(N25V,CURR) $(PORT) $(A)")
-    field(EGU,  "Amps")
-    field(LOPR, "0")
-    field(HOPR, "1.03")
-    field(EGUL, "0")
-    field(EGUF, "1.03")
-    field(DRVL, "0")
-    field(DRVH, "1.03")
-}
-record(ao, "$(P)$(R)GetP6Volts")
-{
-    field(DESC, "Get +6V output volage")
-    field(DTYP, "stream")
-    field(OUT,  "@devHPE3631A.proto getVI(P6V,VOLT) $(PORT) $(A)")
-    field(EGU,  "Volts")
-    field(LOPR, "0")
-    field(HOPR, "6.18")
-    field(EGUL, "0")
-    field(EGUF, "6.18")
-}
-record(ao, "$(P)$(R)GetP6Amps")
-{
-    field(DESC, "Get +6V output current")
-    field(DTYP, "stream")
-    field(OUT,  "@devHPE3631A.proto getVI(P6V,CURR) $(PORT) $(A)")
-    field(EGU,  "Amps")
-    field(LOPR, "0")
-    field(HOPR, "5.15")
-    field(EGUL, "0")
-    field(EGUF, "5.15")
-}
-record(ao, "$(P)$(R)GetP25Volts")
-{
-    field(DESC, "Get +25V output volage")
-    field(DTYP, "stream")
-    field(OUT,  "@devHPE3631A.proto getVI(P25V,VOLT) $(PORT) $(A)")
-    field(EGU,  "Volts")
-    field(LOPR, "0")
-    field(HOPR, "25.75")
-    field(EGUL, "0")
-    field(EGUF, "25.75")
-}
-record(ao, "$(P)$(R)GetP25Amps")
-{
-    field(DESC, "Get +25V output current")
-    field(DTYP, "stream")
-    field(OUT,  "@devHPE3631A.proto getVI(P25V,CURR) $(PORT) $(A)")
-    field(EGU,  "Amps")
-    field(LOPR, "0")
-    field(HOPR, "1.03")
-    field(EGUL, "0")
-    field(EGUF, "1.03")
-}
-record(ao, "$(P)$(R)GetN25Volts")
-{
-    field(DESC, "Get -25V output volage")
-    field(DTYP, "stream")
-    field(OUT,  "@devHPE3631A.proto getVI(N25V,VOLT) $(PORT) $(A)")
-    field(EGU,  "Volts")
-    field(LOPR, "-25.75")
-    field(HOPR, "0")
-    field(EGUL, "-25.75")
-    field(EGUF, "0")
-}
-record(ao, "$(P)$(R)GetN25Amps")
-{
-    field(DESC, "Get -25V output current")
-    field(DTYP, "stream")
-    field(OUT,  "@devHPE3631A.proto getVI(N25V,CURR) $(PORT) $(A)")
-    field(EGU,  "Amps")
-    field(LOPR, "0")
-    field(HOPR, "1.03")
-    field(EGUL, "0")
-    field(EGUF, "1.03")
-}
-  
-

- Depending on your application you might set up FLNK and/or SCAN fields to keep the - setpoint readbacks up to date. -

- - diff --git a/documentation/HowToDoSerial/Makefile b/documentation/HowToDoSerial/Makefile deleted file mode 100644 index ae59b26..0000000 --- a/documentation/HowToDoSerial/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -all: pdf - -pdf: tutorial.pdf - -tutorial.tex: tutorial.lyx - lyx --export pdflatex tutorial.lyx - -tutorial.pdf: tutorial.tex - pdflatex tutorial.tex - pdflatex tutorial.tex - rm -f tutorial.log tutorial.out tutorial.toc tutorial.ps - -install: pdf - scp tutorial.pdf $(WEB_BASE) - -clean: - rm -f *.dvi *.log *.aux *.bbl *.blg *.lof *.lot *.toc *.out *.haux *.htoc - rm -f tutorial.ps tutorial.tex tutorial.lyx~ - -realclean: clean - rm -rf tutorial.lyx~ tutorial.pdf diff --git a/documentation/HowToDoSerial/tutorial.lyx b/documentation/HowToDoSerial/tutorial.lyx deleted file mode 100644 index 2d9b04a..0000000 --- a/documentation/HowToDoSerial/tutorial.lyx +++ /dev/null @@ -1,2124 +0,0 @@ -#LyX 1.5.6 created this file. For more info see http://www.lyx.org/ -\lyxformat 276 -\begin_document -\begin_header -\textclass article -\begin_preamble -\usepackage{moreverb} -\usepackage{url} - -\textwidth=6.5in -\topmargin=0pt -\headheight=0pt -\textheight=8.6truein -\oddsidemargin=0in -\evensidemargin=0in -\footskip=40pt - -\parindent=0pt -\parskip=0.5ex -\usepackage{hyperref} -%HEVEA \def{\textbackslash}{$\backslash$} % No \textbackslash in hevea. -\end_preamble -\language english -\inputencoding auto -\font_roman times -\font_sans default -\font_typewriter default -\font_default_family default -\font_sc false -\font_osf false -\font_sf_scale 100 -\font_tt_scale 100 -\graphics default -\paperfontsize default -\spacing single -\papersize default -\use_geometry false -\use_amsmath 1 -\use_esint 0 -\cite_engine basic -\use_bibtopic false -\paperorientation portrait -\secnumdepth 3 -\tocdepth 2 -\paragraph_separation indent -\defskip medskip -\quotes_language english -\papercolumns 1 -\papersides 2 -\paperpagestyle default -\tracking_changes false -\output_changes false -\author "" -\author "" -\end_header - -\begin_body - -\begin_layout Title -How to create EPICS device support for a simple serial or GPIB device -\end_layout - -\begin_layout Author -W. - Eric Norum -\newline - -\begin_inset LatexCommand url -name "norume.aps.anl.gov" -target "mailto:norume@aps.anl.gov" - -\end_inset - - -\end_layout - -\begin_layout Section -Introduction -\end_layout - -\begin_layout Standard -This tutorial provides step-by-step instructions on how to create EPICS - support for a simple serial or GPIB (IEEE-488) device. - The steps are presented in a way that should make it possible to apply - them in cookbook fashion to create support for other devices. - For comprehensive description of all the details of the I/O system used - here, refer to the -\begin_inset LatexCommand htmlurl -name "asynDriver" -target "../asynDriver.html" - -\end_inset - - and -\begin_inset LatexCommand htmlurl -name "devGpib" -target "../devGpib.html" - -\end_inset - - documentation. -\end_layout - -\begin_layout Standard -This document isn't for the absolute newcomer though. - You must have EPICS installed on a system somewhere and know how to build - and run the example application. - In particular you must have the following installed: -\end_layout - -\begin_layout Itemize -EPICS R3.14.6 or higher. -\end_layout - -\begin_layout Itemize -EPICS modules/soft/asyn version 4.0 or higher. -\end_layout - -\begin_layout Standard -Serial and GPIB devices can now be treated in much the same way. - The EPICS 'asyn' driver devGpib module can use the low-level drivers which - communicate with serial devices connected to ports on the IOC or to Ethernet/Se -rial converters or with GPIB devices connected to local I/O cards or to - Ethernet/GPIB converters. -\end_layout - -\begin_layout Standard -I based this tutorial on the device support I wrote for a CVI Laser Corporation - AB300 filter wheel. - You're almost certainly interested in controlling some other device so - you won't be able to use the information directly. - I chose the AB300 as the basis for this tutorial since the AB300 has a - very limited command set, which keeps this document small, and yet has - commands which raise many of the issues that you'll have to consider when - writing support for other devices. - If you'd like to print this tutorial you can download -\begin_inset LatexCommand url -name "PDF version" -target "tutorial.pdf" - -\end_inset - -. -\end_layout - -\begin_layout Section -Determine the required I/O operations -\end_layout - -\begin_layout Standard -The first order of business is to determine the set of operations the device - will have to perform. - A look at the AB300 documentation reveals that there are four commands - that must be supported. - Each command will be associated with an EPICS process variable (PV) whose - type must be appropriate to the data transferred by the command. - The AB300 commands and process variable record types I choose to associate - with them are shown in table\InsetSpace ~ - -\begin_inset LatexCommand ref -reference "commandList" - -\end_inset - -. -\end_layout - -\begin_layout Standard -\begin_inset Float table -wide false -sideways false -status open - -\begin_layout Standard -\begin_inset Caption - -\begin_layout Standard -AB300 filter wheel commands -\begin_inset LatexCommand label -name "commandList" - -\end_inset - - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Standard -\align center -\begin_inset Tabular - - - - - - -\begin_inset Text - -\begin_layout Standard -CVI Laser Corporation AB300 filter wheel -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Standard - -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Standard -Command -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Standard -EPICS record type -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Standard -Reset -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Standard -longout -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Standard -Go to new position -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Standard -longout -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Standard -Query position -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Standard -longin -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Standard -Query status -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Standard -longin -\end_layout - -\end_inset - - - - -\end_inset - - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Standard -There are lots of other ways that the AB300 could be handled. - It might be useful, for example, to treat the filter position as multi-bit - binary records instead. -\end_layout - -\begin_layout Section -Create a new device support module -\end_layout - -\begin_layout Standard -Now that the device operations and EPICS process variable types have been - chosen it's time to create a new EPICS application to provide a place to - perform subsequent software development. - The easiest way to do this is with the makeSupport.pl script supplied with - the EPICS ASYN package. -\end_layout - -\begin_layout Standard -Here are the commands I ran. - You'll have to change the -\family typewriter -/home/EPICS/modules/soft/asyn -\family default - to the path where your EPICS ASYN driver is installed. -\end_layout - -\begin_layout LyX-Code -norume> -\family roman -\series bold -mkdir ab300 -\family default -\series default - -\newline -norume> -\family roman -\series bold -cd ab300 -\family default -\series default - -\newline -norume> -\family roman -\series bold -/home/EPICS/modules/soft/asyn/bin/linux-x86/makeSupport.pl -t devGpib AB300 -\end_layout - -\begin_layout Subsection -Make some changes to the files in configure/ -\end_layout - -\begin_layout Standard -Edit the -\family typewriter -configure/RELEASE -\family default - file which makeSupport.pl created and confirm that the entries describing - the paths to your EPICS base and ASYN support are correct. - For example these might be: -\end_layout - -\begin_layout LyX-Code -ASYN=/home/EPICS/modules/soft/asyn -\end_layout - -\begin_layout LyX-Code -EPICS_BASE=/home/EPICS/base -\end_layout - -\begin_layout Standard -Edit the -\family typewriter -configure/CONFIG -\family default - file which makeSupport.pl created and specify the IOC architectures on which - the application is to run. - I wanted the application to run as a soft IOC, so I uncommented the -\family typewriter -CROSS_COMPILER_TARGET_ARCHS -\family default - definition and set the definition to be empty: -\end_layout - -\begin_layout LyX-Code -CROSS_COMPILER_TARGET_ARCHS = -\end_layout - -\begin_layout Subsection -Create the device support file -\end_layout - -\begin_layout Standard -The contents of the device support file provide all the details of the communica -tion between the device and EPICS. - The makeSupport.pl command created a skeleton device support file in -\family typewriter -AB300Sup/devAB300.c -\family default -. - Of course, device support for a device similar to the one you're working - with provides an even easier starting point. -\end_layout - -\begin_layout Standard -The remainder this section describes the changes that I made to the skeleton - file in order to support the AB300 filter wheel. - You'll have to modify the steps as appropriate for your device. -\end_layout - -\begin_layout Subsubsection -Declare the DSET tables provided by the device support -\end_layout - -\begin_layout Standard -Since the AB300 provides only longin and longout records most of the -\family typewriter -DSET_ -\family default -\shape italic -xxx -\shape default - define statements can be removed. - Because of the way that the device initialization is performed you must - define an analog-in DSET even if the device provides no analog-in records - (as is the case for the AB300). -\end_layout - -\begin_layout LyX-Code -#define DSET_AI devAiAB300 -\newline -#define DSET_LI devLiAB300 -\newline -#define DSET_LO - devLoAB300 -\end_layout - -\begin_layout Subsubsection -Select timeout values -\end_layout - -\begin_layout Standard -The default value of -\family typewriter -TIMEWINDOW -\family default - (2 seconds) is reasonable for the AB300, but I increased the value of -\family typewriter -TIMEOUT -\family default - to 5\InsetSpace ~ -seconds since the filter wheel can be slow in responding. -\end_layout - -\begin_layout LyX-Code -#define TIMEOUT 5.0 /* I/O must complete within this time */ -\newline -#define - TIMEWINDOW 2.0 /* Wait this long after device timeout */ -\end_layout - -\begin_layout Subsubsection -Clean up some unused values -\end_layout - -\begin_layout Standard -The skeleton file provides a number of example character string arrays. - None are needed for the AB300 so I just removed them. - Not much space would be wasted by just leaving them in place however. -\end_layout - -\begin_layout Subsubsection -Declare the command array -\end_layout - -\begin_layout Standard -This is the hardest part of the job. - Here's where you have to figure how to produce the command strings required - to control the device and how to convert the device responses into EPICS - process variable values. -\end_layout - -\begin_layout Standard -Each command array entry describes the details of a single I/O operation - type. - The application database uses the index of the entry in the command array - to provide the link between the process variable and the I/O operation - to read or write that value. -\end_layout - -\begin_layout Standard -The command array entries I created for the AB300 are shown below. - The elements of each entry are described using the names from the -\begin_inset LatexCommand url -name "GPIB documentation" -target "../devGpib.html" - -\end_inset - -. - -\end_layout - -\begin_layout Paragraph -Command array index 0 -- Device Reset -\end_layout - -\begin_layout LyX-Code -{&DSET_LO, GPIBWRITE, IB_Q_LOW, NULL, " -\backslash -377 -\backslash -377 -\backslash -033", 10, 10, -\newline - NULL, 0, 0, NULL, NULL, " -\backslash -033"}, -\end_layout - -\begin_layout Description -dset This command is associated with an longout record. - -\end_layout - -\begin_layout Description -type A WRITE operation is to be performed. - -\end_layout - -\begin_layout Description -pri This operation will be placed on the low-priority queue of I/O requests. - -\end_layout - -\begin_layout Description -cmd Because this is a GPIBWRITE operation this element is unused. - -\end_layout - -\begin_layout Description -format The format string to generate the command to be sent to the device. - The first two bytes are the RESET command, the third byte is the ECHO command. - The AB300 sends no response to a reset command so I send the 'ECHO' to - verify that the device is responding. - The AB300 resets itself fast enough that it can see an echo command immediately - following the reset command. -\end_layout - -\begin_deeper -\begin_layout Standard -Note that the process variable value is not used (there's no printf -\family typewriter -% -\family default - format character in the command string). - The AB300 is reset whenever the EPICS record is processed. - -\end_layout - -\end_deeper -\begin_layout Description -rspLen The size of the readback buffer. - Although only one readback byte is expected I allow for a few extra bytes - just in case. - -\end_layout - -\begin_layout Description -msgLen The size of the buffer into which the command string is placed. - I allowed a little extra space in case a longer command is used some day. - -\end_layout - -\begin_layout Description -convert No special conversion function is needed. - -\end_layout - -\begin_layout Description -P1,P2,P3 There's no special conversion function so no arguments are needed. - -\end_layout - -\begin_layout Description -pdevGpibNames There's no name table. - -\end_layout - -\begin_layout Description -eos The end-of-string value used to mark the end of the readback operation. - GPIB devices can usually leave this entry NULL since they use the End-Or-Identi -fy (EOI) line to delimit messages.Serial devices which have the same end-of-strin -g value for all commands couldalso leave these entries NULL and set the - end-of-string value with theiocsh asynOctetSetInputEos command. -\end_layout - -\begin_layout Paragraph -Command array index 1 -- Go to new filter position -\end_layout - -\begin_layout LyX-Code -{&DSET_LO, GPIBWRITE, IB_Q_LOW, NULL, " -\backslash -017%c", 10, 10, -\newline - NULL, 0, 0, NULL, NULL, " -\backslash -030"}, -\end_layout - -\begin_layout Description -dset This command is associated with an longout record. - -\end_layout - -\begin_layout Description -type A WRITE operation is to be performed. - -\end_layout - -\begin_layout Description -pri This operation will be placed on the low-priority queue of I/O requests. - -\end_layout - -\begin_layout Description -cmd Because this is a GPIBWRITE operation this element is unused. - -\end_layout - -\begin_layout Description -format The format string to generate the command to be sent to the device. - The filter position (1-6) can be converted to the required command byte - with the printf -\family typewriter -%c -\family default - format. - -\end_layout - -\begin_layout Description -rspLen The size of the readback buffer. - Although only two readback bytes are expected I allow for a few extra bytes - just in case. - -\end_layout - -\begin_layout Description -msgLen The size of the buffer into which the command string is placed. - I allowed a little extra space in case a longer command is used some day. - -\end_layout - -\begin_layout Description -convert No special conversion function is needed. - -\end_layout - -\begin_layout Description -P1,P2,P3 There's no special conversion function so no arguments are needed. - -\end_layout - -\begin_layout Description -pdevGpibNames There's no name table. - -\end_layout - -\begin_layout Description -eos The end-of-string value used to mark the end of the readback operation. - -\end_layout - -\begin_layout Paragraph -Command array index 2 -- Query filter position -\end_layout - -\begin_layout LyX-Code -{&DSET_LI, GPIBREAD, IB_Q_LOW, " -\backslash -035", NULL, 0, 10, -\newline - convertPositionReply, 0, 0, NULL, NULL, " -\backslash -030"}, -\end_layout - -\begin_layout Description -dset This command is associated with an longin record. - -\end_layout - -\begin_layout Description -type A READ operation is to be performed. - -\end_layout - -\begin_layout Description -pri This operation will be placed on the low-priority queue of I/O requests. - -\end_layout - -\begin_layout Description -cmd The command string to be sent to the device. - The AB300 responds to this command by sending back three bytes: the current - position, the controller status, and a terminating -\family typewriter -' -\backslash -030' -\family default -. - -\end_layout - -\begin_layout Description -format Because this operation has its own conversion function this element - is unused. - -\end_layout - -\begin_layout Description -rspLen There is no command echo to be read. - -\end_layout - -\begin_layout Description -msgLen The size of the buffer into which the reply string is placed. - Although only three reply bytes are expected I allow for a few extra bytes - just in case. -\end_layout - -\begin_layout Description -convert There's no sscanf format that can convert the reply from the AB300 - so a special conversion function must be provided. - -\end_layout - -\begin_layout Description -P1,P2,P3 The special conversion function requires no arguments. - -\end_layout - -\begin_layout Description -pdevGpibNames There's no name table. - -\end_layout - -\begin_layout Description -eos The end-of-string value used to mark the end of the read operation. - -\end_layout - -\begin_layout Paragraph -Command array index 3 -- Query controller status -\end_layout - -\begin_layout Standard -This command array entry is almost identical to the previous entry. - The only change is that a different custom conversion function is used. - -\end_layout - -\begin_layout LyX-Code -{&DSET_LI, GPIBREAD, IB_Q_LOW, " -\backslash -035", NULL, 0, 10, -\newline - convertStatusReply, 0, 0, NULL, NULL, " -\backslash -030"}, -\end_layout - -\begin_layout Subsubsection -Write the special conversion functions -\end_layout - -\begin_layout Standard -As mentioned above, special conversion functions are need to convert reply - messages from the AB300 into EPICS PV values. - The easiest place to put these functions is just before the -\family typewriter -gpibCmds -\family default - table. - The conversion functions are passed a pointer to the -\family typewriter -gpibDpvt -\family default - structure and three values from the command table entry. - The -\family typewriter -gpibDpvt -\family default - structure contains a pointer to the EPICS record. - The custom conversion function uses this pointer to set the record's value - field. -\end_layout - -\begin_layout Standard -Here are the custom conversion functions I wrote for the AB300. -\end_layout - -\begin_layout LyX-Code -/* -\newline - * Custom conversion routines -\newline - */ -\newline -static int -\newline -convertPositionReply(struct - gpibDpvt *pdpvt, int P1, int P2, char **P3) -\newline -{ -\newline - struct longinRecord *pli - = ((struct longinRecord *)(pdpvt->precord)); -\newline - -\newline - if (pdpvt->msgInputLen - != 3) { -\newline - epicsSnprintf(pdpvt->pasynUser->errorMessage, -\newline - - pdpvt->pasynUser->errorMessageSize, -\newline - "Invalid - reply"); -\newline - return -1; -\newline - } -\newline - pli->val = pdpvt->msg[0]; -\newline - return - 0; -\newline -} -\newline -static int -\newline -convertStatusReply(struct gpibDpvt *pdpvt, int P1, int P2, - char **P3) -\newline -{ -\newline - struct longinRecord *pli = ((struct longinRecord *)(pdpvt->preco -rd)); -\newline - -\newline - if (pdpvt->msgInputLen != 3) { -\newline - epicsSnprintf(pdpvt->pasynUser->e -rrorMessage, -\newline - pdpvt->pasynUser->errorMessageSize, -\newline - - "Invalid reply"); -\newline - return -1; -\newline - } -\newline - pli->val - = pdpvt->msg[1]; -\newline - return 0; -\newline -} -\end_layout - -\begin_layout Standard -Some points of interest: -\end_layout - -\begin_layout Enumerate -Custom conversion functions indicate an error by returning -1. -\end_layout - -\begin_layout Enumerate -If an error status is returned an explanation should be left in the -\family typewriter -errorMessage -\family default - buffer. - -\end_layout - -\begin_layout Enumerate -I put in a sanity check to ensure that the end-of-string character is where - it should be. - -\end_layout - -\begin_layout Subsubsection -Provide the device support initialization -\end_layout - -\begin_layout Standard -Because of way code is stored in object libraries on different systems the - device support parameter table must be initialized at run-time. - The analog-in initializer is used to perform this operation. - This is why all device support files must declare an analog-in DSET. -\end_layout - -\begin_layout Standard -Here's the initialization for the AB300 device support. - The AB300 immediately echos the command characters sent to it so the respond2Wr -ites value must be set to 0. - All the other values are left as created by the makeSupport.pl script: -\end_layout - -\begin_layout LyX-Code -static long init_ai(int pass) -\newline -{ -\newline - if(pass==0) { -\newline - devSupParms.name = - "devAB300"; -\newline - devSupParms.gpibCmds = gpibCmds; -\newline - devSupParms.numparams - = NUMPARAMS; -\newline - devSupParms.timeout = TIMEOUT; -\newline - devSupParms.timeWindow - = TIMEWINDOW; -\newline - devSupParms.respond2Writes = 0; -\newline - } -\newline - return(0); -\newline -} -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout Subsection -Modify the device support database definition file -\end_layout - -\begin_layout Standard -This file specifies the link between the DSET names defined in the device - support file and the DTYP fields in the application database. - The makeSupport.pl command created an example file in -\family typewriter -AB300Sup/devAB300.dbd -\family default -. - If you removed any of the -\family typewriter -DSET_ -\family default -\shape italic -xxx -\shape default - definitions from the device support file you must remove the corresponding - lines from this file. - You must define an analog-in DSET even if the device provides no analog-in - records (as is the case for the AB300). -\end_layout - -\begin_layout Standard -\begin_inset ERT -status open - -\begin_layout Standard - - -\backslash -verbatiminput{AB300/AB300Sup/devAB300.dbd} -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Subsection -Create the device support database file -\end_layout - -\begin_layout Standard -This is the database describing the actual EPICS process variables associated - with the filter wheel. -\end_layout - -\begin_layout Standard -I modified the file -\family typewriter -AB300Sup/devAB300.db -\family default - to have the following contents: -\end_layout - -\begin_layout Standard -\begin_inset ERT -status open - -\begin_layout Standard - - -\backslash -verbatiminput{AB300/AB300Sup/devAB300.db} -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Standard -Notes: -\end_layout - -\begin_layout Enumerate -The numbers following the -\family typewriter -L -\family default - in the INP and OUT fields are the number of the `link' used to communicate - with the filter wheel. - This link is set up at run time by commands in the application startup - script. - -\end_layout - -\begin_layout Enumerate -The numbers following the -\family typewriter -A -\family default - in the INP and OUT fields are unused by serial devices but must be a valid - GPIB address (0-30) since the GPIB address conversion routines check the - value and the diagnostic display routines require a matching value. - -\end_layout - -\begin_layout Enumerate -The numbers following the -\family typewriter -@ -\family default - in the INP and OUT fields are the indices into the GPIB command array. - -\end_layout - -\begin_layout Enumerate -The DTYP fields must match the names specified in the devAB300.dbd database - definition. - -\end_layout - -\begin_layout Enumerate -The device support database follows the ASYN convention that the macros - $(P), $(R), $(L) and $(A) are used to specify the record name prefixes, - link number and GPIB address, respectively. -\end_layout - -\begin_layout Subsection -Build the device support -\end_layout - -\begin_layout Standard -Change directories to the top-level directory of your device support and: -\end_layout - -\begin_layout LyX-Code -norume> -\family roman -\series bold -make -\end_layout - -\begin_layout Standard -( -\series bold -gnumake -\series default - on Solaris). -\end_layout - -\begin_layout Standard -If all goes well you'll be left with a device support library in lib/ -\shape italic - -\shape default -/, a device support database definition in dbd/ and a device support database - in db/. -\end_layout - -\begin_layout Section -Create a test application -\end_layout - -\begin_layout Standard -Now that the device support has been completed it's time to create a new - EPICS application to confirm that the device support is operating correctly. - The easiest way to do this is with the makeBaseApp.pl script supplied with - EPICS. -\end_layout - -\begin_layout Standard -Here are the commands I ran. - You'll have to change the -\family typewriter -/home/EPICS/base -\family default - to the path to where your EPICS base is installed. - If you're not running on Linux you'll also have to change all the -\family typewriter -linux-x86 -\family default - to reflect the architecture you're using ( -\family typewriter -solaris-sparc -\family default -, -\family typewriter -darwin-ppc -\family default -, etc.). - I built the test application in the same as the device support, but - the application could be built anywhere. - As well, I built the application as a 'soft' IOC running on the host machine, - but the serial/GPIB driver also works on RTEMS and vxWorks. -\end_layout - -\begin_layout LyX-Code -norume> -\family roman -\series bold -cd ab300 -\family default -\series default - -\newline -norume> -\family roman -\series bold -/home/EPICS/base/bin/linux-x86/makeBaseApp.pl -t ioc AB300 -\family default -\series default - -\newline -norume> -\family roman -\series bold -/home/EPICS/base/bin/linux-x86/makeBaseApp.pl -i -t ioc AB300 -\family default -\series default - -\newline -The following target architectures are available in base: -\newline - RTEMS-pc386 -\newline - - linux-x86 -\newline - solaris-sparc -\newline - win32-x86-cygwin -\newline - vxWorks-ppc603 -\newline -What - architecture do you want to use? -\family roman -\series bold -linux-x86 -\end_layout - -\begin_layout Section -Using the device support in an application -\end_layout - -\begin_layout Standard -Several files need minor modifications to use the device support in the - test, or any other, application. -\end_layout - -\begin_layout Subsection -Make some changes to configure/RELEASE -\end_layout - -\begin_layout Standard -Edit the -\family typewriter -configure/RELEASE -\family default - file which makeBaseApp.pl created and confirm that the EPICS_BASE path is - correct. - Add entries for your ASYN and device support. - For example these might be: -\end_layout - -\begin_layout LyX-Code -AB300=/home/EPICS/modules/instrument/ab300/1-2 -\end_layout - -\begin_layout LyX-Code -ASYN=/home/EPICS/modules/soft/asyn/3-2 -\end_layout - -\begin_layout LyX-Code -EPICS_BASE=/home/EPICS/base -\end_layout - -\begin_layout Subsection -Modify the application database definition file -\end_layout - -\begin_layout Standard -Your application database definition file must include the database definition - files for your instrument and for the ASYN drivers. - There are two ways that this can be done: -\end_layout - -\begin_layout Enumerate -If you are building your application database definition from an -\shape italic -xxx -\family typewriter -\shape default -Include.dbd -\family default - file you include the additional database definitions in that file. - For example, to add support for the AB300 instrument and local and remote - serial line drivers: -\newline - -\begin_inset ERT -status open - -\begin_layout Standard - - -\backslash -verbatiminput{AB300/AB300App/src/AB300Include.dbd} -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Enumerate -If you are building your application database definition from the application - Makefile you specify the additional database definitions there: -\newline - . -\newline -. -\newline - -\shape italic -xxx -\shape default -_DBD += base.dbd -\newline - -\shape italic -xxx -\shape default -_DBD += devAB300.dbd -\newline - -\shape italic -xxx -\shape default -_DBD += drvAsynIPPort.dbd -\newline - -\shape italic -xxx -\shape default -_DBD += drvAsynSerialPort.dbd -\newline -. -\newline -. -\newline -This is the preferred method. -\end_layout - -\begin_layout Subsection -Add the device support libraries to the application -\end_layout - -\begin_layout Standard -You must link your device support library and the ASYN support library with - the application. - Add the following lines -\end_layout - -\begin_layout LyX-Code - -\family roman -\shape italic -xxx -\family default -\shape default -_LIBS += devAB300 -\end_layout - -\begin_layout LyX-Code - -\family roman -\shape italic -xxx -\family default -\shape default -_LIBS += asyn -\end_layout - -\begin_layout Standard -before the -\end_layout - -\begin_layout LyX-Code - -\family roman -\shape italic -xxx -\family default -\shape default -_LIBS += $(EPICS_BASE_IOC_LIBS) -\end_layout - -\begin_layout Standard -line in the application -\family typewriter -Makefile -\family default -. -\end_layout - -\begin_layout Subsection -Modify the application startup script -\end_layout - -\begin_layout Standard -The -\family typewriter -st.cmd -\family default - application startup script created by the makeBaseApp.pl script needs a - few changes to get the application working properly. -\end_layout - -\begin_layout Enumerate -Load the device support database records: -\end_layout - -\begin_deeper -\begin_layout LyX-Code -cd $(AB300) -\family roman -( -\family default -cd AB300 -\family roman -if using the vxWorks shell) -\end_layout - -\begin_layout LyX-Code -dbLoadRecords("db/devAB300.db","P=AB300:,R=,L=0,A=0") -\end_layout - -\end_deeper -\begin_layout Enumerate -Set up the 'port' between the IOC and the filter wheel. - -\end_layout - -\begin_deeper -\begin_layout Itemize -If you're using an Ethernet/RS-232 converter or a device which communicates - over a telnet-style socket connection you need to specify the Internet - host and port number like: -\end_layout - -\begin_deeper -\begin_layout LyX-Code -drvAsynIPPortConfigure("L0","164.54.9.91:4002",0,0,0) -\end_layout - -\end_deeper -\begin_layout Itemize -If you're using a serial line directly attached to the IOC you need something - like: -\end_layout - -\begin_deeper -\begin_layout LyX-Code -drvAsynSerialPortConfigure("L0","/dev/ttyS0",0,0,0) -\newline -asynSetOption("L0", -1, - "baud", "9600") -\newline -asynSetOption("L0", -1, "bits", "8") -\newline -asynSetOption("L0", - -1, "parity", "none") -\newline -asynSetOption("L0", -1, "stop", "1") -\newline -asynSetOption("L0", - -1, "clocal", "Y") -\newline -asynSetOption("L0", -1, "crtscts", "N") -\end_layout - -\end_deeper -\begin_layout Itemize -If you're using a serial line directly attached to a vxWorks IOC you must - first configure the serial port interface hardware. - The following example shows the commands to configure a port on a GreenSprings - UART Industry-Pack module. -\end_layout - -\begin_deeper -\begin_layout LyX-Code -ipacAddVIPC616_01("0x6000,B0000000") -\newline -tyGSOctalDrv(1) -\newline -tyGSOctalModuleInit("RS232", - 0x80, 0, 0) -\newline -tyGSOctalDevCreate("/tyGS/0/0",0,0,1000,1000) -\newline -drvAsynSerialPortConfig -ure("L0","/tyGS/0/0",0,0,0) -\newline -asynSetOption("L0",-1,"baud","9600") -\end_layout - -\end_deeper -\begin_layout Standard -In all of the above examples the first argument of the configure and set - port option commands is the link identifier and must match the -\family typewriter -L -\family default - value in the EPICS database record INP and OUT fields. - The second argument of the configure command identifies the port to which - the connection is to be made. - The third argument sets the priority of the worker thread which performs - the I/O operations. - A value of zero directs the command to choose a reasonable default value. - The fourth argument is zero to direct the device support layer to automatically - connect to the serial port on startup and whenever the serial port becomes - disconnected. - The final argument is zero to direct the device support layer to use standard - end-of-string processing on input messages. -\end_layout - -\end_deeper -\begin_layout Enumerate -(Optional) Add lines to control the debugging level of the serial/GPIB driver. - The following enables error messages and a description of every I/O operation. -\end_layout - -\begin_deeper -\begin_layout LyX-Code -asynSetTraceMask("L0",-1,0x9) -\newline -asynSetTraceIOMask("L0",-1,0x2) -\end_layout - -\begin_layout Standard -A better way to control the amount and type of diagnostic output is to add - an -\begin_inset LatexCommand url -name "asynRecord" -target "../asynRecord.html" - -\end_inset - - to your application. -\end_layout - -\end_deeper -\begin_layout Subsection -Build the application -\end_layout - -\begin_layout Standard -Change directories to the top-level directory of your application and: -\end_layout - -\begin_layout LyX-Code -norume> -\family roman -\series bold -make -\end_layout - -\begin_layout Standard -( -\series bold -gnumake -\series default - on Solaris). -\end_layout - -\begin_layout Standard -If all goes well you'll be left with an executable program in bin/linux-x86/AB30 -0. -\end_layout - -\begin_layout Subsection -Run the application -\end_layout - -\begin_layout Standard -Change directories to where makeBaseApp.pl put the application startup script - and run the application: -\end_layout - -\begin_layout LyX-Code -norume> -\family roman -\series bold -cd iocBoot/iocAB300 -\family default -\series default - -\newline -norume> -\family roman -\series bold -../../bin/linux-x86/AB300 st.cmd -\family default -\series default - -\newline -dbLoadDatabase("../../dbd/AB300.dbd",0,0) -\newline -AB300_registerRecordDeviceDriver(pdbbase) -\newline -cd - ${AB300} -\end_layout - -\begin_layout LyX-Code -dbLoadRecords("db/devAB300.db","P=AB300:,R=,L=0,A=0") -\newline -drvAsynIPPortConfigure("L0", -"164.54.3.137:4001",0,0,0) -\newline -asynSetTraceMask("L0",-1,0x9) -\newline -asynSetTraceIOMask("L0",-1,0 -x2) -\newline -iocInit() -\newline -#################################################################### -######## -\newline -### EPICS IOC CORE built on Apr 23 2004 -\newline -### EPICS R3.14.6 2008/03/25 - 18:06:21 -\newline -####################################################################### -##### -\newline -Starting iocInit -\newline -iocInit: All initialization complete -\end_layout - -\begin_layout Standard -Check the process variable names: -\end_layout - -\begin_layout LyX-Code -epics> -\family roman -\series bold -dbl -\family default -\series default - -\newline -AB300:FilterWheel:fbk -\newline -AB300:FilterWheel:status -\newline -AB300:FilterWheel -\newline -AB300:FilterWheel: -reset -\end_layout - -\begin_layout Standard -Reset the filter wheel. - The values sent between the IOC and the filter wheel are shown: -\end_layout - -\begin_layout LyX-Code -epics> -\family roman -\series bold -dbpf AB300:FilterWheel:reset 0 -\family default -\series default - -\newline -DBR_LONG: 0 0x0 -\newline -2004/04/21 12:05:14.386 164.54.3.137:4001 write - 3 -\backslash -377 -\backslash -377 -\backslash -033 -\newline -2004/04/21 12:05:16.174 164.54.3.137:4001 read 1 -\backslash -033 -\end_layout - -\begin_layout Standard -Read back the filter wheel position. - The dbtr command prints the record before the I/O has a chance to occur: -\end_layout - -\begin_layout LyX-Code -epics> -\family roman -\series bold -dbtr AB300:FilterWheel:fbk -\family default -\series default - -\newline -ACKS: NO_ALARM ACKT: YES ADEL: 0 ALST: 0 -\newline -ASG: - BKPT: 0x00 DESC: Filter Wheel Position -\newline -DISA: 0 - DISP: 0 DISS: NO_ALARM DISV: 1 -\newline -DTYP: AB300Gpib - EGU: EVNT: 0 FLNK:CONSTANT 0 -\newline -HHSV: NO_ALARM - HIGH: 0 HIHI: 0 HOPR: 6 -\newline -HSV: NO_ALARM - HYST: 0 INP:GPIB_IO #L0 A0 @2 -\newline -LALM: 0 LCNT: 0 - LLSV: NO_ALARM LOLO: 0 -\newline -LOPR: 1 LOW: 0 - LSV: NO_ALARM MDEL: 0 -\newline -MLST: 0 NAME: AB300:FilterWheel:f -bk NSEV: NO_ALARM -\newline -NSTA: NO_ALARM PACT: 1 PHAS: - 0 PINI: NO -\newline -PRIO: LOW PROC: 0 PUTF: 0 - RPRO: 0 -\newline -SCAN: Passive SDIS:CONSTANT SEVR: INVALID - SIML:CONSTANT -\newline -SIMM: NO SIMS: NO_ALARM SIOL:CONSTANT - STAT: UDF -\newline -SVAL: 0 TPRO: 0 TSE: 0 - TSEL:CONSTANT -\newline -UDF: 1 VAL: 0 -\newline -2004/04/21 12:08:01.971 164.54.3.137:400 -1 write 1 -\backslash -035 -\newline -2004/04/21 12:08:01.994 164.54.3.137:4001 read 3 -\backslash -001 -\backslash -020 -\backslash -030 -\end_layout - -\begin_layout Standard -Now the process variable should have that value: -\end_layout - -\begin_layout LyX-Code -epics> -\family roman -\series bold -dbpr AB300:FilterWheel:fbk -\family default -\series default - -\newline -ASG: DESC: Filter Wheel Position DISA: 0 -\newline -DISP: - 0 DISV: 1 NAME: AB300:FilterWheel:fbk -\newline -SEVR: NO_ALARM - STAT: NO_ALARM SVAL: 0 TPRO: 0 -\newline -VAL: 1 -\end_layout - -\begin_layout Standard -Move the wheel to position 4: -\end_layout - -\begin_layout LyX-Code -epics> -\family roman -\series bold -dbpf AB300:FilterWheel 4 -\family default -\series default - -\newline -DBR_LONG: 4 0x4 -\newline -2004/04/21 12:10:51.542 164.54.3.137:4001 - write 2 -\backslash -017 -\backslash -004 -\newline -2004/04/21 12:10:51.562 164.54.3.137:4001 read 1 -\backslash -020 -\newline -2004/04/21 12:10:52.902 164.54.3.137:4001 read 1 -\backslash -030 -\end_layout - -\begin_layout Standard -Read back the position: -\end_layout - -\begin_layout LyX-Code -epics> -\family roman -\series bold -dbtr AB300:FilterWheel:fbk -\family default -\series default - -\newline -ACKS: NO_ALARM ACKT: YES ADEL: 0 ALST: 1 -\newline -ASG: - BKPT: 0x00 DESC: Filter Wheel Position -\newline -DISA: 0 - DISP: 0 DISS: NO_ALARM DISV: 1 -\newline -DTYP: AB300Gpib - EGU: EVNT: 0 FLNK:CONSTANT 0 -\newline -HHSV: NO_ALARM - HIGH: 0 HIHI: 0 HOPR: 6 -\newline -HSV: NO_ALARM - HYST: 0 INP:GPIB_IO #L0 A0 @2 -\newline -LALM: 1 LCNT: 0 - LLSV: NO_ALARM LOLO: 0 -\newline -LOPR: 1 LOW: 0 - LSV: NO_ALARM MDEL: 0 -\newline -MLST: 1 NAME: AB300:FilterWheel:f -bk NSEV: NO_ALARM -\newline -NSTA: NO_ALARM PACT: 1 PHAS: - 0 PINI: NO -\newline -PRIO: LOW PROC: 0 PUTF: 0 - RPRO: 0 -\newline -SCAN: Passive SDIS:CONSTANT SEVR: NO_ALARM - SIML:CONSTANT -\newline -SIMM: NO SIMS: NO_ALARM SIOL:CONSTANT - STAT: NO_ALARM -\newline -SVAL: 0 TPRO: 0 TSE: 0 - TSEL:CONSTANT -\newline -UDF: 0 VAL: 1 -\newline -2004/04/21 12:11:43.372 - 164.54.3.137:4001 write 1 -\backslash -035 -\newline -2004/04/21 12:11:43.391 164.54.3.137:4001 read 3 -\backslash -004 -\backslash -020 -\backslash -030 -\end_layout - -\begin_layout Standard -And it really is 4: -\end_layout - -\begin_layout LyX-Code -epics> -\family roman -\series bold -dbpr AB300:FilterWheel:fbk -\family default -\series default - -\newline -ASG: DESC: Filter Wheel Position DISA: 0 -\newline -DISP: - 0 DISV: 1 NAME: AB300:FilterWheel:fbk -\newline -SEVR: NO_ALARM - STAT: NO_ALARM SVAL: 0 TPRO: 0 -\newline -VAL: 4 -\end_layout - -\begin_layout Section -Device Support File -\end_layout - -\begin_layout Standard -Here is the complete device support file for the AB300 filter wheel ( -\family typewriter -AB300Sup/devAB300.c -\family default -): -\end_layout - -\begin_layout Standard -\begin_inset ERT -status open - -\begin_layout Standard - - -\backslash -verbatiminput{AB300/AB300Sup/devAB300.c} -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Section -asynRecord support -\end_layout - -\begin_layout Standard -The asynRecord provides a convenient mechanism for controlling the diagnostic - messages produced by asyn drivers. - To use an asynRecord in your application: -\end_layout - -\begin_layout Enumerate -Add the line -\newline - -\newline - -\family typewriter -DB_INSTALLS += $(ASYN)/db/asynRecord.db -\family default - -\newline - -\newline -to an application -\family typewriter -Makefile -\family default -. -\end_layout - -\begin_layout Enumerate -Create the diagnostic record by adding a line like -\newline - -\newline -cd $(ASYN) -\family roman -( -\family default -cd ASYN -\family roman -if using the vxWorks shell) -\family typewriter -\size small - -\newline -dbLoadRecords("db/asynRecord.db","P=AB300,R=Test,PORT=L0,ADDR=0,IMAX=0,OMAX=0") -\family default -\size default - -\newline - -\newline -to the application startup ( -\family typewriter -st.cmd -\family default -) script. - The -\family typewriter -PORT -\family default - value must match the the value in the corresponding -\family typewriter -drvAsynIPPortConfigure -\family default - or -\family typewriter -drvAsynSerialPortConfigure -\family default - command. - The -\family typewriter -addr -\family default - value should be that of the instrument whose I/O you wish to monitor. - The -\family typewriter -P -\family default - and -\family typewriter -R -\family default - values are arbitrary and are concatenated together to form the record name. - Choose values which are unique among all IOCs on your network. - -\end_layout - -\begin_layout Standard -To run the asynRecord screen, add -\shape italic -/medm -\family default - to your -\family typewriter -EPICS_DISPLAY_PATH -\family default - environment variable and start medm with -\family typewriter -P -\family default -, -\family typewriter -R -\family default -, -\family typewriter -PORT -\family default - and -\family typewriter -ADDR -\family default - values matching those given in the -\family typewriter -dbLoadRecords -\family default - command: -\end_layout - -\begin_layout LyX-Code -medm -x -macro "P=AB300,R=Test" asynRecord.adl -\end_layout - -\begin_layout Section -Support for devices with common 'end-of-string' characters -\end_layout - -\begin_layout Standard -Devices which use the same character, or characters, to mark the end of - each command or response message need not specify these characters in the - GPIB command table entries. - They can, instead, specify the terminator sequences as part of the driver - port configuration commands. - This makes it possible for a single command table to provide support for - devices which provide a serial or Ethernet interface (and require command/respo -nse terminators) and also provide a GPIB interface (which does not require - command/response terminators). -\end_layout - -\begin_layout Standard -For example, the configuration commands for a TDS3000 digital oscilloscope - connected through an Ethernet serial port adapter might look like: -\end_layout - -\begin_layout LyX-Code -drvAsynIPPortConfigure("L0", "192.168.9.90:4003", 0, 0, 0) -\newline -asynOctetSetInputEos("L0" -,0," -\backslash -n") -\newline -asynOctetSetOutputEos("L0",0," -\backslash -n") -\end_layout - -\begin_layout Standard -The configuration command for the same oscilloscope connected to an Ethernet - GPIB adapter would be: -\end_layout - -\begin_layout LyX-Code -vxi11Configure("L0", "192.168.8.129", 0, "0.0", "gpib0", 0) -\end_layout - -\begin_layout Standard -An example command table entry for this device is shown below. - Notice that there is no -\family typewriter - -\backslash -n -\family default - at the end of the command and that the table 'eos' field is -\family typewriter -NULL -\family default -: -\end_layout - -\begin_layout LyX-Code -/* 2 : read delay : AI */ -\newline - {&DSET_AI, GPIBREAD, IB_Q_LOW, "HOR:DEL:TIM?", - "%lf", 0, 20, -\newline - NULL, 0, 0, NULL, NULL, NULL}, -\end_layout - -\end_body -\end_document diff --git a/documentation/Makefile b/documentation/Makefile deleted file mode 100644 index 7c8f665..0000000 --- a/documentation/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -HTMLFLAGS = --book --duplex --no-numbered --format pdf14 --title --size letter - -%.pdf: %.html - -htmldoc $(HTMLFLAGS) --outfile $@ $< - -all: asynDriver.pdf asynRecord.pdf devGpib.pdf doxygen install - -doxygen: - doxygen - -install: - mkdir -p ../html - cp *.html ../html - cp *.jpg ../html - cp *.png ../html - cp *.pdf ../html - cp -r asynDoxygenHTML ../html - mkdir -p ../html/gpibCoreConversion ; cp gpibCoreConversion/*html gpibCoreConversion/*css ../html/gpibCoreConversion - mkdir -p ../html/HowToDoSerial ; cp HowToDoSerial/*.html ../html/HowToDoSerial - -clean: - -realclean: clean - rm -f *.pdf diff --git a/documentation/README.md b/documentation/README.md deleted file mode 100644 index 30e75f5..0000000 --- a/documentation/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# HTML documentation - -* [Home page](http://www.aps.anl.gov/epics/modules/soft/asyn/) -* [Documentation](http://htmlpreview.github.com/?https://github.com/epics-modules/asyn/blob/master/documentation/asynDriver.html) -* [Release notes](http://htmlpreview.github.com/?https://github.com/epics-modules/asyn/blob/master/documentation/RELEASE_NOTES.html) diff --git a/documentation/README_cygwin b/documentation/README_cygwin deleted file mode 100644 index 1aa25e6..0000000 --- a/documentation/README_cygwin +++ /dev/null @@ -1,13 +0,0 @@ -In order to build ASYN on cygwin 1.5.x you need to download -and install the cygwin "Sun RPC" module. On 1.7.x you need -the "tirpc" module. - -You should add one of the following 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 - diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html deleted file mode 100755 index 72324a2..0000000 --- a/documentation/RELEASE_NOTES.html +++ /dev/null @@ -1,2820 +0,0 @@ - - - - asynDriver: Asynchronous Driver Support - Release Notes - - - -
-

- asynDriver: Release Notes

-
-
-
-

- 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: -
      -
    1. Synchronous driver, i.e. ASYN_CANBLOCK not set.
    2. -
    3. Asynchronous driver, i.e. ASYN_CANBLOCK is set.
    4. -
    5. Driver callback is done in the write() operation.
    6. -
    7. Driver callback is done in a separate thread. The callbacks are triggered with - the TriggerCallbacks record.
    8. -
    9. Single callback is done in each operation.
    10. -
    11. Multiple callbacks are done in each operation. The NumCallbacks record selects - the number of callbacks.
    12. -
    - 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:

-
    -
  1. 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.
  2. -
  3. The interrupt callback function for stringin and waveform records were not properly - locking the record when modifying the record fields.
  4. -
-

- 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:

-

- <host>:<port>[: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 - <epicsExport.h>. 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 <epicsexport.h> 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 <name> 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

-
-

- 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:

-
    -
  1. Use an EPICS timer to time-out an I/O operation, such as send(), recv() and connect().
  2. -
  3. Periodically check (every 5 seconds) during a long I/O operation to see if the - operation should be cancelled.
  4. -
-

- 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

-
-

- 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

-
-

- 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.

-
    -
  1. Local serial ports. The asyn uses the "termios" API for serial ports, and termios - is not available for native Windows.
  2. -
  3. VXI-11. The asyn VXI-11 support uses the Sun XDR API, which is not available for - native Windows.
  4. -
-

- 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

-
-

- 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

-
-

- 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

-
-

- 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

-
-

- Release 4-2

-
-

- 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 -

    - Previosly 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

-
-

- The only code change was to fix the drvAsynIPPort and drvAsynSerialPort segmentation - faults on cygwin-x86.

-
-

- Release 4-0

-
-

- 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

-
-

- 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

-
-

- 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

-
-

- 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

-
-

- 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

-
-
    -
  • 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

-
-

- 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:

-
    -
  1. Added asynSetPortOption and asynGetPortOption to manipulate port options.
  2. -
  3. Changed serial support to use asynSetPortOption/asynGetPortOption.
  4. -
  5. Added devGPIB GPIBCVTIO commmand type to allow custom conversion routine to perform - all I/O operations.
  6. -
  7. Changed rules for return value from devGPIB custom conversion routines.
  8. -
  9. Added dbior support.
  10. -
  11. Changed devGPIB to no longer cache EOS.
  12. -
-
-
-

- Release 1-0alpha2

-
-

- 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/documentation/asynDriver.html b/documentation/asynDriver.html deleted file mode 100755 index 95abebe..0000000 --- a/documentation/asynDriver.html +++ /dev/null @@ -1,6691 +0,0 @@ - - - - - asynDriver - - - -
-

- asynDriver: EPICS Driver Support

-

- Release 4-36

-

- Mark Rivers, Eric Norum, and Marty - Kraimer

-

- August 8, 2019

-

- Other Contributers

-

- Gasper Jansa (cosyLab) - linuxGpib - support.

-
-
-

- License Agreement

-

- This product is available via the open source license - described at the end of this document.

-
-

- Contents

- -
-

- Purpose

-

- asynDriver is a general purpose facility for interfacing device specific - code to low level drivers. asynDriver allows non-blocking device support that works - with both blocking and non-blocking drivers.

-

- A primary target for asynDriver is EPICS IOC device support but, other than using - libCom, much of it is independent of EPICS.

-

- asynDriver has the following key concepts:

-
    -
  • Device support communicates with drivers via interfaces -

    - Drivers take care of the details of how to communicate with a device and implement - interfaces for use by device support. Interfaces are defined for both message and - register based devices. In the past when support was written for a new type of device, - device support for standard EPICS records had to be written in addition to the driver - support. Now a driver just implements one or more of the standard interfaces.

    -
  • -
  • A port provides access to device instances -

    - A port, which has a portName, identifies a communication path to one or more device - instances. For example a GPIB port can have up to 15 devices connected to it. An - RS232 port communicates with a single device. Drivers register a port. Device support - connects to a port.

    -
  • -
  • asynManager controls access to a port -

    - asynManager, a component of asynDriver, provides exclusive access to a driver via - calls to queueRequest, lockPort/unlockPort, and queueLockPort/queueUnlockPort. Once - device support has access, it can make an arbitrary number of calls to the driver - knowing that no other support can call the driver. Device and driver support do - not need to implement queues or semaphores since asynManager does this for them.

    -
  • -
  • asynTrace provides a general purpose diagnostic facility -

    - Rules are defined for providing diagnostic messages. Provided device and driver - support follow the rules, a user can obtain several levels of diagnostic information - that can be displayed on the console, written to a file, or sent to the EPICS errlog - facility.

    -
  • -
  • asynRecord - Generic access to an device/port -

    - asynRecord is an EPICS record and set of associated MEDM displays that provide access - to:

    -
      -
    • A port or a device connected to a port -

      - The port or port,addr can be changed dynamically. Thus with one asynRecord in an - IOC, it is possible to talk to any device that has an asyn compatible driver.

      -
    • -
    • asynTrace - All asynTrace options can be controlled with the asynRecord.
    • -
    • Connection Management -

      - Display and change connection, enable, and autoConnect state

      -
    • -
    • Standard interfaces -

      - These can be used to communicate with devices. For example if a new instrument arrives - that has a serial, GPIB, or ethernet port, then it is often possible to communicate - with it just by attaching an asynRecord to it.

      -
    • -
    -
  • -
  • Extensive Serial Support -

    - asynDriver provides many facilities for communicating with RS232, RS485, GPIB, and - ethernet.

    -
  • -
-
-

- Status

-

- This version provides

-
    -
  • asynManager: the software layer between device support and drivers.
  • -
  • asynRecord: EPICS record support that provides a generic interface to asynManager, - asynCommon, asynOctet, asynGpib, and other interfaces.
  • -
  • asynPortDriver: a C++ base class that makes it easy to write asyn drivers, with - much of the boilerplate asyn code handled in the base class methods.
  • -
  • asynPortClient: C++ classes that makes it easy to write C++ asyn clients that - communicate directly with asyn port drivers without running an EPICS IOC.
  • -
  • standard interfaces: Standard message and register based interfaces are defined. - Low Level Drivers implement standard interfaces. Device support communicates with - low level drivers via standard interfaces.
  • -
  • devEpics: Generic device support for EPICS records.
  • -
  • devGpib: EPICS device support that replaces the device support layer of the Winans/Franksen - gpibCore support.
  • -
  • asynGpib: a replacement for the drvGpibCommon layer of the Franksen gpibCore support.
  • -
  • drvAsynSerialPort: Support for devices connected to serial ports.
  • -
  • drvAsynIPPort: Support for TCP/IP and UDP/IP socket communication, including serial - devices accessed via Ethernet/Serial converter boxes.
  • -
  • drvAsynIPServerPort: Support for asyn socket servers that are accessed from remote - clients. TCP/IP sockets and UDP are supported.
  • -
  • VXI-11: A replacement for the VXI-11 support of the Franksen gpibCore support.
  • -
  • Linux-gpib: Support for the Linux GPIB Package library.
  • -
  • gsIP488: A low level driver for the Greensprings IP488 Industry Pack module.
  • -
  • ni1014: A low level driver for the National Instruments VME 1014D.
  • -
  • Serial Bus Support: The asynLockPortNotify interface was added to make it easier - to support serial bus drivers that use the standard serial support.
  • -
-

- The following are some of the existing EPICS general purpose device support systems - that have been converted to use asynDriver.

-
    -
  • StreamDevice. This is the protocol file-based support for serial/GPIB/CAN from - Dirk Zimoch.
  • -
  • gpibCore. This is the operating-system-independent version of the Winans/Franksen - GPIB support.
  • -
  • synApps (The APS BCDA synchrotron applications). The mca, dxp, motor, Ip330, IpUnidig, - DAC128V and quadEM applications in this package have all been converted to asyn. - The serial and GPIB modules in this package are no longer needed, because the asyn - record replaces them. The areaDetector module was written to use asyn, and was the - original motivation for the development of asynPortDriver.
  • -
-
-

- Acknowledgments

-

- The idea of creating asynDriver resulted from many years of experience with writing - device support for serial and GPIB devices. The following individuals have been - most influential.

-
-
John Winans
-
- John provided the original EPICS GPIB support. Databases using John's support can - be used without modification with devGpib. With small modifications, device support - modules written for John's support can be used.
-
Benjamin Franksen
-
- John's support only worked on vxWorks. In addition, the driver support was implemented - as a single source file. Benjamin defined an interface between drvCommon and low - level controllers and split the code into drvGpib and the low level drivers. He - also created the support for drvVxi11.
-
Eric Norum
-
- Eric started with Benjamin's code and converted it to use the Operating System Independent - features of EPICS 3.14.
-
Marty Kraimer
-
- Marty started with Eric's version and made changes to support secondary addressing; - and to replace ioctl with code to support general bus management, universal commands, - and addressed commands.
-
Pete Owens
-
- Pete, for the Diamond Light Source, did a survey of several types of device/driver - support packages for serial devices. Diamond decided to use the StreamDevice support - developed by Dirk Zimoch.
-
Dirk Zimoch
-
- Dirk developed StreamDevice, which has a single device support model, but supports - arbitrary low level message based drivers, i.e. GPIB, serial, etc.
-
Jun-ichi Odagare
-
- Jun-ichi developed NetDev, a system that provides EPICS device support for network - based devices. It has a single device support model, but provides a general framework - for communicating with network based devices.
-
Mark Rivers
-
- Mark became an active developer of asynDriver soon after he started converting SynApps - to use asynDriver. He soon pushed to have asynDriver support synchronous drivers, - support register based drivers, and support interrupts. With these additions asynDriver - is a framework for interfacing to a large class of devices instead of just message - based asynchronous devices.
-
Yevgeny A. Gusev
-
- Yevgeny has found bugs and suggested improvements in the way asynManager handles - queue timeouts and cancels. He provides an expert and welcome set of eyes to look - at difficult code!!!
-
-
-

- Overview of asynDriver

-

- Definitions

-

- asynDriver is a software layer between device specific code and drivers that communicate - with devices. It supports both blocking and non-blocking communication and can be - used with both register and message based devices. asynDriver uses the following - terminology:

-
    -
  • interface -

    - All communication between software layers is done via interfaces. An interface definition - is a C language structure consisting entirely of function pointers. An asynDriver - interface is analogous to a C++ or Java pure virtual interface. Although the implementation - is in C, the spirit is object oriented. Thus this document uses the term "method" - rather than "function pointer".

    -
  • -
  • port -

    - A physical or logical entity which provides access to a device. A port provides - access to one or more devices.

    -
  • -
  • portDriver -

    - Code that communicates with a port.

    -
  • -
  • portThread -

    - If a portDriver can block, a thread is created for each port, and all I/O to the - portDriver is done via this thread.

    -
  • -
  • device -

    - A device (instrument) connected to a port. For example a GPIB interface can have - up to 15 devices connected to it. Other ports, e.g. RS-232 serial ports, only support - a single device. Whenever this document uses the word device without a qualifier, - it means something that is connected to a port.

    -
  • -
  • device support -

    - Code that interacts with a device.

    -
  • -
  • synchronous -

    - Support that does not voluntarily give up control of the CPU.

    -
  • -
  • asynchronous -

    - Support that is not synchronous. Some examples of asynchronous operations are epicsThreadSleep, - epicsEventWait, and stdio operations. Calls to epicsMutexTake are considered to - be synchronous operations, i.e. they are permitted in synchronous support.

    -
  • -
  • asynDriver -

    - The name for the support described in this manual. It is also the name of the header - file that describes the core interfaces.

    -
  • -
  • asynManager -

    - An interface and the code which implements the methods for interfaces asynManager - and asynTrace.

    -
  • -
  • asynchronous Driver -

    - A driver that blocks while communicating with a device. Typical examples are serial, - gpib, and network based drivers.

    -
  • -
  • synchronous Driver -

    - A driver that does not block while communicating with a device. Typical examples - are VME register based devices.

    -
  • -
  • Message Based Interfaces -

    - Interfaces that use octet arrays for read/write operations.

    -
  • -
  • Register Based Interfaces -

    - Interfaces that use integers or floats for read/write operations.

    -
  • -
  • interrupt -

    - As implemented by asynManager, interrupt just means "I have a new value for port, - address".

    -
  • -
-

- Synchronous/asynchronous and message/register are orthogonal concepts. For example - a register based driver can be either synchronous or asynchronous. The terminology - register vs message is adapted from VXI.

-

- Standard interfaces are defined so that device specific code can communicate with - multiple port drivers. For example if device support does all its communication - via reads and writes consisting of 8 bit bytes (octets), then it should work with - all port drivers that support octet messages. If device support requires more complicated - support, then the types of ports will be more limited. Standard interfaces are also - defined for drivers that accept 32 bit integers or 64 bit floats. Additional interfaces - can be defined, and it is expected that additional standard interfaces will be defined.

-

- One or more devices can be attached to a port. For example, only one device can - be attached to an RS-232 port, but up to 15 devices can be attached to a GPIB port.

-

- Multiple layers can exist between device specific code and a port driver. A software - layer calls interposeInterface in order to be placed between device specific code - and drivers. For more complicated protocols, additional layers can be created. For - example, GPIB support is implemented as an asynGpib interface which is called by - user code, and an asynGpibPort interface which is called by asynGpib.

-

- A driver normally implements multiple interfaces. For example asynGpib implements - asynCommon, asynOctet, and asynGpib.

-

- asynManager uses the Operating System Independent features of EPICS base. It is, - however, independent of record/device support. Thus, it can be used by other code, - e.g. a sequence program.

-

- Standard Interfaces

-

- These are interfaces provided by asynManager or interfaces implemented by all or - most port drivers.

-

- The interfaces are:

-

- asynManager provides services for communicating - with a device connected to a port.

-

- asynCommon is an interface that must be implemented - by all low level drivers. The methods are:

-
    -
  • report - Report status of port.
  • -
  • connect - Connect to the port or device.
  • -
  • disconnect - Disconnect from the port or device.
  • -
-

- asynTrace is an interface for generating - diagnostic messages.

-

- asynLockPortNotify is an interface that is - implemented by a driver which is an asynUser of another driver. An example is a - serial bus driver that uses standard serial support. asynManager calls asynLockPortNotify - whenever it locks or unlocks the port.

-

- asynDrvUser is an interface for communicating - information from device support to a driver without the device support knowing any - details about what is passed.

-

- Generic Interfaces

-

- In addition to asynCommon and optionally - asynDrvUser, port drivers can implement one - or more of the following message and/or register based interfaces.

-

- asynOctet methods for message based devices

-

- asynFloat64 methods for devices that read/write - IEEE float values

-

- asynFloat32Array methods for devices that - read/write arrays of IEEE 32-bit float values

-

- asynFloat64Array methods for devices that - read/write arrays of IEEE 64-bit float values

-

- asynInt32 methods for devices that read/write - integer values. Many analog I/O drivers can use this interface.

-

- asynInt8Array methods for devices that read/write - arrays of 8-bit integer values

-

- asynInt16Array methods for devices that read/write - arrays of 16-bit integer values

-

- asynInt32Array methods for devices that read/write - arrays of 32-bit integer values

-

- asynUInt32Digital methods for devices that - read/write arrays of digital values. This interface provides a mask to address individual - bits within registers.

-

- asynGenericPointer methods for devices that - read/write arbitrary structures, passed via a void* pointer. The client and the - server of course need to agree on the structure type being pointed to.

-

- asynEnum methods for devices to define enum - strings, values, and severities.

-

- asynOption methods for device configuration - using key/value pairs.

-

- asynManager

-

- asynManager is an interface and associated code. It is the "heart" of asynDriver - since it manages the interactions between device support code and drivers. It provides - the following services:

-
    -
  • reporting -

    - Method: report

    -
  • -
  • asynUser creation -

    - Methods: createAsynUser, duplicateAsynUser, freeAsynUser

    -

    - An asynUser is a "handle" for accessing asynManager services and for calling interfaces - implemented by drivers. An asynUser must only be created via a call to createAsynUser - or duplicateAsynUser since asynManager keeps private information for each asynUser. - freeAsynUser puts the asynUser on a free list rather than calling free. Clients - can continually create and free asynUsers quickly and without fragmenting memory.

    -

    - The call to createAsynUser specifies a processCallback and a timeoutCallback. These - are the callbacks that will be called as a result of a queueRequest.

    -

    - An asynUser should not be shared between parts of code that can simultaneously access - a driver. For example device support for standard EPICS records should create an - asynUser for each record instance.

    -
  • -
  • Basic asynUser services -

    - Methods: connectDevice, disconnect, findInterface

    -

    - These methods should only be called by the code that created the asynUser.

    -

    - After an asynUser is created the user calls connectDevice. The user is connected - to a port driver that can communicate with a device. findInterface is called for - each interface the user requires. disconnect is called when the user is done with - the device.

    -
  • -
  • Queuing services -

    - Methods: queueRequest, cancelRequest, lockPort, unlockPort, queueLockPort, queueUnlockPort, - blockProcessCallback, unblockProcessCallback

    -

    - queueRequest is a request to call the processCallback specified in the call to createAsynUser. - Most interface methods must only be called from processCallback via a call to queueRequest - or between calls to lockPort/unlockPort.. Exceptions to this rule must be clearly - documented (a common exception are methods registerInterruptUser/cancelInterruptUser).

    -

    - queueRequest semantics differ for ports that can block and ports that do not block

    -

    - When registerPort is called by a driver that can block, a thread is created for - the port. A set of queues, based on priority, is created for the thread. queueRequest - puts the request on one of the queues. The port thread takes the requests from the - queues and calls the associated callback. Only one callback is active at a time.

    -

    - When registerPort is called by a driver that does not block, a mutex is created - for the port. queueRequest takes the mutex, calls the callback, and releases the - mutex. The mutex guarantees that two callbacks to a port are not active at the same - time.

    -

    - lockPort is a request to lock all access to low level drivers until unlockPort is - called. If the port blocks then lockPort and all calls to the port driver may block. - lockPort/unlockPort are provided for use by code that is willing to block or for - communication with synchronous ports. A call to lockPort locks all addresses associated - with a multi-address port. Prior to asyn R4-14 pasynManager->lockPort() immediately - took the port mutex when it was available, rather than queueing a request to take - the mutex. From asyn R4-14 to R4-20 lockPort 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. In R4-21 - the queued lockPort and unlockPort functions were renamed to queueLockPort and queueUnlockPort, - and the original lightweight lockPort and unlockPort functions were restored. Up - to R4-32 when queueLockPort called queueRequest it did not specify a timeout. This - could lead to code being hung if the port disconnected after the call to queueRequest - but before the callback was called. The code would remain hung until the port reconnected. - In R4-32 the queueRequest is done with a timeout. The default timeout value is 2.0 - seconds but this can be change with the shell command asynSetQueueLockPortTimeout(portName, - double timeout). If the pasynUser->timeout passed to queueLockPort is greater - than the current port timeout value this larger timeout from the pasynUser is used - instead.

    -

    - blockProcessCallback is a request to prevent acccess to a device or port by other - asynUsers between queueRequests. blockProcessCallback can be called from a processCallback - or when the asynUser has no request queued. When called from processCallback blocking - starts immediately, otherwise blocking starts the next time processCallback is called. - Blocking means that no other asynUser's processCallback will be called until unblockProcessCallback - is called. blockProcessCallback only works with drivers that can block and an error - is returned if it is called for non-blocking drivers.

    -
  • -
  • Basic Driver services -

    - Methods: registerPort,registerInterface

    -

    - registerPort is called by a portDriver. registerInterface is called by a portDriver - or an interposeInterface.

    -

    - Each port driver provides a configuration command that is executed for each port - instance. The configuration command performs port specific initializations, calls - registerPort, and registerInterface for each interface it implements.

    -
  • -
  • Attribute Retrieval -

    - Methods: isMultiDevice, canBlock, getAddr, getPortName, isConnected, isEnabled, - isAutoConnect

    -

    - These methods can be called by any code that has access to the asynUser

    -
  • -
  • Connection services -

    - Methods: enable,autoConnect,setAutoConnectTimeout

    -

    - These methods can be called by any code that has access to the asynUser.

    -

    - These methods can be called to set the enable and autoConnect settings for a port - and/or device. If autoConnect is true then asynManager does the following:

    -
      -
    • When the port registers its asynCommon interface, asynManager queues a connection - request. It then 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 - function pasynManager->setAutoConnectTimeout(double timeout). This function can - be accessed from the iocsh shell with the 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 means that it - is very likely that the pasynCommon->connect() call will occur as soon as the - asynCommon interface is registered, which means that the driver must have already - done all initialization required for the asynCommon->connect() callback before - it registers the asynCommon interface. If the port does not connect initially, or - if it subsequently disconnects, then asynManager will queue a connection request - every 20 seconds. If autoConnect is true and port/device is enabled but the device - is not connected, then queueManager calls calling asynCommon:connect just before - it calls processCallback.
    • -
    -
  • -
  • Exception services -

    - Methods: exceptionCallbackAdd, exceptionCallbackRemove, exceptionConnect, exceptionDisconnect

    -

    - Device support code calls exceptionCallbackAdd and exceptionCallbackRemove. The - complete list of exceptions is defined in asynDriver.h as "enum asynException".

    -

    - Whenever a port driver connects or disconnects, normally as a result of a call to - asynCommon:connect or asynCommon:disconnect, it must also call exceptionConnect - or exceptionDisconnect.

    -
  • -
  • Interrupt services -

    - Methods: registerInterruptSource, getInterruptPvt, createInterruptNode, freeInterruptNode, - addInterruptUser, removeInterruptUser, interruptStart, interruptEnd

    -

    - Interrupt just means: "I have a new value." Many asyn interfaces, e.g. asynInt32, - provide interrupt support. These interfaces provide methods addInterruptUser and - removeInterruptUser. Device support calls addInterruptUser if it wants to be called - whenever an interrupt occurs. Drivers or other code that implements the interface - calls the registered users when it has new data. asynManager provides services that - help drivers implement thread-safe support for interrupts.

    -

    - A driver that supports interrupts calls registerInterruptSource for each interface - that has associated interrupts. It calls interruptStart to obtain a list of all - registered users and interruptEnd after it calls the registered users. The driver - is also responsible for calling addInterruptUser and removeInterruptUser.

    -

    - If any calls are made to addInterruptUser or removeInterruptUser between the calls - to interruptStart and interruptEnd, asynManager puts the request on a list and processes - the request after interruptEnd is called.

    -

    - Many standard interfaces, e.g. asynInt32, provide methods registerInterruptUser, - cancelInterruptUser. These interfaces also provide an auxilliary interface, e.g. - asynInt32Base, and code which implements registerInterruptUser and cancelInterruptUser.

    -

    - On operating systems like vxWorks or RTEMS interruptStart,interruptEnd MUST NOT - be called from interupt level.

    -
  • -
  • Timestamp services -

    - Methods: updateTimeStamp, getTimeStamp, setTimeStamp, registerTimeStampSource, unregisterTimeStampSource.

    -

    - These methods provide support for setting a timestamp for a port. This timestamp - is typically used to set the pasynUser->timestamp field that is passed to device - support on read or callback operations. Device support uses the pasynUser->timestamp - field to set the record TIME field. This will then be the record timestamp if the - record TSE field is -2. asynManager provides a default timestamp source function - which just calls epicsTimeGetCurrent(). However, registerTimeStampSource can be - used to supply a different user-provided timestamp source function, for example - one that calls epicsTimeGetEvent(), or some other site-specific timestamp source. - unregisterTimeStampSource reverts to the default timestamp source in pasynManager.

    -
  • -
  • General purpose freelist service -

    - Methods: memMalloc, memFree

    -

    - These methods do not require an asynUser. They are provided for code that must continually - allocate and free memory. Since memFree puts the memory on a free list instead of - calling free, they are more efficient that calloc/free and also help prevent memory - fragmentation.

    -
  • -
  • Interpose service -

    - Method: interposeInterface

    -

    - Code that calls interposeInterface implements an interface which is either not supported - by a port driver or that is "interposed" between the caller and the port driver. - For example asynInterposeEos interposes asynOctet. It performs end of string processing - for port drivers that do not support it.

    -

    - interposeInterface is recursive, i.e. an arbitrary number of interpose layers can - exist above a single port,addr.

    -
  • -
-

- Multiple Device vs Single Device Port Drivers

-

- When a low level driver calls registerPort, it declares if it handles multiple devices. - This determines how the addr argument to connectDevice is handled and what getAddr - returns.

-
    -
  • multiDevice false -

    - The addr argument to connectDevice is ignored and getAddr always returns -1

    -
  • -
  • multiDevice true -

    - If connectDevice is called with addr<0, the connection is to the port and getAddr - always returns -1. If addr>=0, then the caller is connected to the device at - the specified address. getAddr will return this address. An asynUser connected to - the port can issue requests that affect all address on the port. For example disabling - access to the port prevents access to all addresses on the port.

    -
  • -
-

- Connection Management

-

- asynManager keeps track of the following states:

-
    -
  • connection -

    - Is the port or device connected? This state is initialized to disconnected.

    -
  • -
  • enabled -

    - Is the port or device enabled? This state is initialized to enabled.

    -
  • -
  • autoConnect -

    - Does asynManager automatically attempt to connect if it finds the port or device - disconnected? This is initialized to the state specified in the call to registerPort.

    -
  • -
-

- If the port does not support multiple devices, then port and device status are the - same. If the port does support multiple devices, then asynManager keeps track of - the states for the port and for every device connected to the port.

-

- Whenever any of the states change for a port or device, then all users that previously - called exceptionCallbackAdd for that port or device are called.

-

- Low level drivers must call pasynManager:exceptionConnect whenever they connect - to a port or port,addr and exceptionDisconnect whenever they disconnect.

-

- Protecting a Thread from Blocking

-

- The methods asynManager:report and asynCommon:report can be called by any thread, - but the caller is blocked until the report finishes. lockPort, unlockPort, queueLockPort, - queueUnlockPort, and most port methods may block. The other asynManager methods - can be called by any thread including portThread. None of these methods block.

-

- Unless stated otherwise the methods for other interfaces must only be called by - processCallback or by calls between lockPort/unlockPort, or queueLockPort/queueUnlockPort.

-

- Interface methods registerInterruptUser and cancelInterruptUser must never block. - The registerInterruptUser callback must not block because it could be called by - a non blocking driver.

-

- portThread

-

- If a driver calls asynManager:registerPort with the ASYN_CANBLOCK attributes bit - set, then asynManager creates a thread for the port. Each portThread has its own - set of queues for the calls to queueRequest. Four queues are maintained. One queue - is used only for asynCommon:connect and asynCommon:disconnect requests. The other - queues provide different priorities: low, medium, and high. queueRequests to any - queue other then the connection queue will be rejected if the port is not connected. - portThread runs forever implementing the following algorithm:

-
    -
  1. Wait for work by calling epicsEventMustWait. Other code such as queueRequest call - epicsEventSignal.
  2. -
  3. If the port is disabled, go back to 1.
  4. -
  5. For every element in queue, asynQueuePriorityConnect: -
      -
    • Removes the element from the queue.
    • -
    • Calls the user's callback
    • -
    -
  6. -
  7. For each element of the queues asynQueuePriorityHigh, ...,asynQueuePriorityLow. -
      -
    • If disabled, skip this element.
    • -
    • If not connected and autoConnect is true for the device, then attempt to connect - to the device.
    • -
    • If not connected, skip this element.
    • -
    • If blocked by another thread, skip this element.
    • -
    • If not blocked and user has requested blocking, then blocked.
    • -
    • Remove from queue and: -
        -
      • lock port
      • -
      • call user callback
      • -
      • unlock port
      • -
      -
    • -
    -
  8. -
-

- The actual code is more complicated because it unlocks before it calls code outside - asynManager. This means that the queues can be modified and exceptions may occur.

-

- Overview of Queuing

-

- When discussing queuing it is useful to think of 3 components of asyn:

-
    -
  1. asynManager. This is the core part of asyn. It knows nothing about EPICS records. - In fact it is completely independent of EPICS except that it uses libCom for OS-independent - things like mutexes, message queues, events, etc. The queuing it provides is for - callback requests to communicate with asynchronous drivers (ASYN_CANBLOCK) via pasynManager->queueRequest().
  2. -
  3. Standard asyn device support (devEpics directory). This is the only part of asyn - that knows about EPICS records and depends on EPICS components other than libCom. - It supports callbacks from the driver under 3 conditions: -
      -
    1. Input records with SCAN=I/O Intr
    2. -
    3. Input records with periodic scanning (asynInt32Average and asynFloat64Average - only)
    4. -
    5. Output records with asyn:READBACK=1.
    6. -
    - The callback values can be placed in a ring buffer so that values are not lost if - the callbacks happen faster than the record can process. The size of the ring buffer - can be controlled with the asyn:FIFO info tag. The default is 10 for scalar records. - The default is 0 for waveform records, and for stringout and stringin records. If - the ring buffer is in use then each driver callback results in pushing a new value - into the buffer and a request to process the record in a separate callback thread. - If the ring buffer is full then the oldest value in the queue is discarded and the - new value is added. This guarantees that the record will eventually have the value - of the most recent callback, but it may skip some before this. If ASYN_TRACE_WARNING - is set then a warning message is printed. The driver callbacks do not block waiting - for the record to process.
  4. -
  5. asynPortDriver. asynPortDriver does not support queueing. It does have a parameter - library that stores the most recent value of scalar parameters. It does not store - values for array parameters.
  6. -
-
-

- Theory of Operation

-

- Initialization

-

- During initialization, port drivers register each communication port as well as - all supported interfaces.

-

- User code creates an asynUser, which is a "handle" for accessing asynDriver facilities, - by calling

-
    pasynManager->createAsynUser(processCallback,timeoutCallback);
-

- An asynUser has the following features:

-
    -
  • An asynUser is the means by which asynManager manages multiple requests for accessing - a port.
  • -
  • processCallback,which is used by queueRequest described below, is the addresss - of a user supplied callback routine.
  • -
  • timeoutCallback is the address of caller supplied callback that will be called - if a queueRequest remains on the queue too long.
  • -
  • Device support code should create an asynUser for each "atomic" access to low - level drivers, i.e. a set of calls that must not be interlaced with other calls - to the low level drivers. For example device support for EPICS record support should - create an asynUser for each record instance.
  • -
  • Device support code should NOT try to share an asynUser between multiple sources - of requests for access to a port. If this is done then device support must itself - handle contention issues that are already handled by asynManager.
  • -
-

- User code connects to a low level driver via a call to

-
    status = pasynManager->connectDevice(pasynUser,portName,addr);
-

- This call must specify the name of the port and the address of the device. It then - calls findInterface to locate the interfaces with which it calls the driver. For - example:

-
     pasynInterface = pasynManager->findInterface(pasynUser,asynOctetType,1);
-

- Requesting access to a port

-

- User code can request access to a port by two methods:

-
    -
  • queueRequest - -

    - The processCallback passed to createAsynUser makes calls to the port interfaces.

    -
  • -
  • lockPort/unlockPort, queueLockPort/queueUnlockPort - -

    - The caller can make calls to the port interfaces while the lock is held. These calls - and calls to the port may block and thus should NOT be used by code that should - not block, e.g. synchronous device support for EPICS records.

    -
  • -
-

- queueRequest - Flow of Control

-

- User code requests access to a port by calling:

-
    status = pasynManager->queueRequest(pasynUser,priority,timeout);
-

- This results in either processCallback or timeoutCallback being called. Most requests - to a port must be made from processCallback. queueRequest does not block. If queueRequest - is called for a port that can block the request is queued to a thread dedicated - to the port. If queueRequest is called for a port does not block it just calls processCallback. - guarantee is valid only if low level drivers are only accessed by calling queueRequest, - lockPort/unlockPort, and/or queueLockPort/queueUnlockPort

-

- The following examples are based on EPICS IOC record/device support.

-

- The first example shows access to a port that can block.

-

-

-
- AsynFlow.jpg -

-

-

- Figure 1: Asynchronous Control Flow

-
-

- The sequence of record device support events that occurs starting with an application - thread is pictured above in Figure 1, and explained below in the following steps:

-
    -
  1. Record processing calls device support with PACT 0 (Processing is not active).
  2. -
  3. Device support calls queueRequest.
  4. -
  5. queueRequest places the request on the driver work queue. The application thread - is now able to go on and perform other operations. Subsequent operations for this - I/O request are handled in the port driver thread.
  6. -
  7. The portThread removes the I/O request from the work queue.
  8. -
  9. The portThread calls the processCallback located in Record device support.
  10. -
  11. processCallback calls the low-level driver. The low-level driver read or write - routine blocks until the I/O completes or until a timeout occurs. The low-level - driver routine returns the results of the I/O operation to processCallback.
  12. -
  13. processCallback requests that the record be processed. NOTE: The process request - will be made by one of the standard callback requests rather than the port thread.
  14. -
  15. Record support calls device support again, this time with PACT 1(processing is - active). Device support updates fields in the record and returns to record support - which completes record processing.
  16. -
-

- The second example shows access to a port that cannot block.

-

-

-
- AsynSynFlow.jpg -

- Figure 2: Synchronous Control Flow

-
-

- The sequence of record device support events that occurs starting with an application - thread is pictured above in Figure 2, and explained below in the following steps:

-
    -
  1. Record processing calls device support.
  2. -
  3. Device support calls queueRequest.
  4. -
  5. Since the port is synchronous, i.e. can not block, queueRequest locks the port - and then calls the processCallback.
  6. -
  7. processCallback calls the low-level driver read or write routine. The low-level - driver routine returns the results of the I/O operation to processCallback.
  8. -
  9. processCallback returns to queueRequest, which unlocks the port and returns to - device support, which returns to record support, which completes record processing.
  10. -
-
-

- asynDriver Structures and Interfaces

-

- asynDriver.h describes the following:

-
    -
  • asynStatus - An enum that describes the status returned by many methods.
  • -
  • asynException - An enum that describes exceptions.
  • -
  • asynQueuePriority - An enum that describes the queue priorities.
  • -
  • asynUser - A struture that contains generic information and is the "handle" for - calling most methods.
  • -
  • asynInterface - a structure that describes an interface.
  • -
  • userCallback - a typedef for the user process callback function described above.
  • -
  • exceptionCallback - a typedef for a user callback to be called when exceptions - occur.
  • -
  • timeStampCallback - a typedef for a user callback function that will be called - by updateTimeStamp.
  • -
  • asynManager - An interface for communicating with asynDriver.
  • -
  • asynCommon - An interface providing methods that must be implemented by all low - level drivers.
  • -
  • asynTrace - An interface plus associated functions and definitions that implement - the trace facility.
  • -
-

- asynStatus

-

- Defines the status returned by most methods. If a method returns a status other - than asynSuccess, and one of the arguments to the method is pasynUser, then the - method is expected to write a message into pasynUser->errorMessage.

-
typedef enum {
-    asynSuccess,asynTimeout,asynOverflow,asynError,asynDisconnected,asynDisabled
-}asynStatus;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynStatus
- asynSuccess - The request was successful.
- asynTimeout - The request failed with a timeout.
- asynOverflow - The driver has lost input data. This can happen if an internal buffer or the user - supplied buffer is too small. Whenever possible, low level drivers should be written - so that the user can read input in small pieces.
- asynError - Some other error occured.
- asynDisconnected - The request failed because the port is not connected.
- asynDisabled - The request failed because the port or device is disabled.
-

- asynException

-

- Defines the exceptions for method exceptionOccurred

-
typedef enum {
-    asynExceptionConnect,asynExceptionEnable,asynExceptionAutoConnect,
-    asynExceptionTraceMask,asynExceptionTraceIOMask,asynExceptionTraceInfoMask,
-    asynExceptionTraceFile,asynExceptionTraceIOTruncateSize
-} asynException;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynException
- asynExceptionConnect - The connection state of the port or device has changed.
- asynExceptionEnable - The enable state of the port or device has changed.
- asynExceptionAutoConnect - The autoConnect state of the port or device has changed.
- asynExceptionTraceMask - The traceMask for the port or device has changed.
- asynExceptionTraceIOMask - The traceIOMask for the port or device has changed.
- asynExceptionTraceInfoMask - The traceInfoMask for the port or device has changed.
- asynExceptionTraceFile - The trace file for the port or device has changed.
- asynExceptionTraceIOTruncateSize - The traceIOTruncateSize for the port or device has changed.
-

- asynQueuePriority

-

- This defines the priority passed to queueRequest.

-
typedef enum {
-    asynQueuePriorityLow,asynQueuePriorityMedium,asynQueuePriorityHigh,
-    asynQueuePriorityConnect
-}asynQueuePriority;
- - - - - - - - - - - - - - - - - - - - -
- asynQueuePriority
- asynQueuePriorityLow - Lowest queue priority.
- asynQueuePriorityMedium - Medium queue priority.
- asynQueuePriorityHigh - High queue priority.
- asynQueuePriorityConnect - Queue a connect or disconnect request. This priority must be used for and only for - connect/disconnect requests.
-

- asynUser

-

- Describes a structure that user code passes to most asynManager and driver methods. - Code must allocate and free an asynUser by calling asynManager:createAsynUser (or - asynManager:duplicateAsynUser) and asynManager:freeAsynUser.

-
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; 
-    /* The following is for use by driver */
-    void          *drvUser;
-    /* The following is normally set by driver via asynDrvUser->create() */
-    int            reason;
-    epicsTimeStamp timestamp;
-    /* The following are for additional information from method calls */
-    int            auxStatus;     /* For auxillary status*/
-    int            alarmStatus;   /* Typically for EPICS record alarm status */
-    int            alarmSeverity; /* Typically for EPICS record alarm severity */
-}asynUser;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynUser
- errorMessage - When a method returns asynError it should put an error message into errorMessage - via a call to: -
epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
-
              "<format>",...)
- The error message should not end with (nor contain) a newline character - sequence (e.g. \n). It is up to user code to decide whether and how to - display the error message. Keeping newlines out of the error message make it easy - for user code to embed the error message in another message or output format. -
- errorMessageSize - The size of errorMessage. The user can not change this value.
- timeout - The number of seconds before timeout for I/O requests. This is set by the user and - can be changed between calls to a driver. If a call to a low level driver results - in the driver making many I/O requests this is the time for each I/O request. -

- The meaning is as follows:

-

- > 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.

-
- userPvt - For use by the user. The user should set this immediately after the call to pasynManager->createAsynUser. -

- If this is changed while asynUser is queued, the results are undefined, e.g. it - could cause a crash.

-
- userData - Also for use by the user.
- drvUser - A driver can use this to hold asynUser specific data. The asynDrvUser interface - is used for communication between asynUser and the driver.
- reason - Drivers and asynUsers can use this as a general purpose field. By convention it - is used to determine what "command" is being sent over a particular interface. For - example an A/D driver implementing the asynInt32 interface might define reason=0 - to mean "return the A/D conversion", while reason=1 might mean "return the amplifier - gain". Typically drivers implement the asynDrvUser interface, and use this to convert - from descriptive strings for commands (e.g. "DATA" or "GAIN" in this example) to - the enum "reason". A driver that is calling an interrupt users often uses reason - to decide if the users callback should be called. Values of reason less than 0 are - reserved for standard meanings. For example ASYN_REASON_SIGNAL is used to mean "out - of band" request. The devGpib support uses this to report SRQs.
- timestamp - Devices which provide their own time stamps use this field to provide the time value - for records whose TSE field is set to "-2".
- auxStatus - Any method can provide additional return information in auxStatus. The meaning is - determined by the method. Callbacks can use auxStatus to set record alarm status - in device support callback functions.
- alarmStatus - Any method can provide additional return information in alarmStatus. The meaning - is determined by the method. Callbacks can use alarmStatus to set record alarm status - in device support callback functions.
- alarmSeverity - Any method can provide additional return information in alarmStatus. The meaning - is determined by the method. Callbacks can use alarmSeverity to set record alarm - severity in device support callback functions.
-

- asynInterface

-

- This defines an interface registered with asynPortManager:registerPort or asynManager:interposeInterface.

-
typedef struct asynInterface{
-    const char *interfaceType; /*For example, asynCommonType */
-    void *pinterface;          /*For example, pasynCommon */
-    void *drvPvt;
-}asynInterface;
- - - - - - - - - - - - - - - - -
- asynInterface
- interfaceType - A character string describing the interface.
- pinterface - A pointer to the interface. The user must cast this to the correct type.
- drvPvt - For the exclusive use of the code that called registerPort or interposeInterface. -
-

- asynManager

-

- This is the main interface for communicating with asynDriver.

-
/*registerPort attributes*/
-#define ASYN_MULTIDEVICE  0x0001
-#define ASYN_CANBLOCK     0x0002
-
-/*standard values for asynUser.reason*/
-#define ASYN_REASON_SIGNAL -1
-
-#define ASYN_REASON_RESERVED_LOW 0x70000000
-#define ASYN_REASON_RESERVED_HIGH 0x7FFFFFFF
-
-#define ASYN_REASON_QUEUE_EVEN_IF_NOT_CONNECTED ASYN_REASON_RESERVED_LOW
-
-typedef void (*userCallback)(asynUser *pasynUser);
-typedef void (*exceptionCallback)(asynUser *pasynUser,asynException exception);
-typedef void (*timeStampCallback)(void *userPvt, epicsTimeStamp *pTimeStamp);
-
-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);
-    asynUser  *(*duplicateAsynUser)(asynUser *pasynUser,
-                                 userCallback queue,userCallback timeout);
-    asynStatus (*freeAsynUser)(asynUser *pasynUser);
-    void       *(*memMalloc)(size_t size);
-    void       (*memFree)(void *pmem,size_t size);
-    asynStatus (*isMultiDevice)(asynUser *pasynUser,
-                                const char *portName,int *yesNo);
-    /* addr = (-1,>=0) => connect to (port,device) */
-    asynStatus (*connectDevice)(asynUser *pasynUser,
-                                const char *portName,int addr);
-    asynStatus (*disconnect)(asynUser *pasynUser);
-    asynStatus (*exceptionCallbackAdd)(asynUser *pasynUser,
-                                       exceptionCallback callback);
-    asynStatus (*exceptionCallbackRemove)(asynUser *pasynUser);
-    asynInterface *(*findInterface)(asynUser *pasynUser,
-                            const char *interfaceType,int interposeInterfaceOK);
-    asynStatus (*queueRequest)(asynUser *pasynUser,
-                              asynQueuePriority priority,double timeout);
-    asynStatus (*cancelRequest)(asynUser *pasynUser,int *wasQueued);
-    asynStatus (*blockProcessCallback)(asynUser *pasynUser, int allDevices);
-    asynStatus (*unblockProcessCallback)(asynUser *pasynUser, int allDevices);
-    asynStatus (*lockPort)(asynUser *pasynUser);
-    asynStatus (*unlockPort)(asynUser *pasynUser);
-    asynStatus (*queueLockPort)(asynUser *pasynUser);
-    asynStatus (*queueUnlockPort)(asynUser *pasynUser);
-    asynStatus (*setQueueLockPortTimeout)(asynUser *pasynUser, double timeout);
-    asynStatus (*canBlock)(asynUser *pasynUser,int *yesNo);
-    asynStatus (*getAddr)(asynUser *pasynUser,int *addr);
-    asynStatus (*getPortName)(asynUser *pasynUser,const char **pportName);
-    /* drivers call the following*/
-    asynStatus (*registerPort)(const char *portName,
-                              int attributes,int autoConnect,
-                              unsigned int priority,unsigned int stackSize);
-    asynStatus (*registerInterface)(const char *portName,
-                              asynInterface *pasynInterface);
-    asynStatus (*exceptionConnect)(asynUser *pasynUser);
-    asynStatus (*exceptionDisconnect)(asynUser *pasynUser);
-    /*any code can call the following*/
-    asynStatus (*interposeInterface)(const char *portName, int addr,
-                              asynInterface *pasynInterface,
-                              asynInterface **ppPrev);
-    asynStatus (*enable)(asynUser *pasynUser,int yesNo);
-    asynStatus (*autoConnect)(asynUser *pasynUser,int yesNo);
-    asynStatus (*isConnected)(asynUser *pasynUser,int *yesNo);
-    asynStatus (*isEnabled)(asynUser *pasynUser,int *yesNo);
-    asynStatus (*isAutoConnect)(asynUser *pasynUser,int *yesNo);
-    asynStatus (*setAutoConnectTimeout)(double timeout);
-    asynStatus (*waitConnect)(asynUser *pasynUser, double timeout);
-    /*The following are methods for interrupts*/
-    asynStatus (*registerInterruptSource)(const char *portName,
-                               asynInterface *pasynInterface, void **pasynPvt);
-    asynStatus (*getInterruptPvt)(asynUser *pasynUser,
-                               const char *interfaceType, void **pasynPvt);
-    interruptNode *(*createInterruptNode)(void *pasynPvt);
-    asynStatus (*freeInterruptNode)(asynUser *pasynUser,interruptNode *pnode);
-    asynStatus (*addInterruptUser)(asynUser *pasynUser,
-                                  interruptNode*pinterruptNode);
-    asynStatus (*removeInterruptUser)(asynUser *pasynUser,
-                                  interruptNode*pinterruptNode);
-    asynStatus (*interruptStart)(void *pasynPvt,ELLLIST **plist);
-    asynStatus (*interruptEnd)(void *pasynPvt);
-    /* Time stamp functions */
-    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);
-
-    const char *(*strStatus)(asynStatus status);
-}asynManager;
-epicsShareExtern asynManager *pasynManager;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynManager
- report - Reports status about the asynPortManager. If portName is non-NULL it reports for - a specific port. If portName is NULL then it reports for each registered port. It - also calls asynCommon:report for each port being reported.
- createAsynUser - Creates an asynUser. The caller specifies two callbacks, process and timeout. These - callback are only called as a result of a queueRequest. The timeout callback is - optional. errorMessageSize characters are allocated for errorMessage. The amount - of storage can not be changed. This method doesn't return if it is unable to allocate - the storage.
- duplicateAsynUser - Creates an asynUser by calling createAsynUser. It then initializes the new asynUser - as follows: The fields timeout, userPvt, userData, and drvUser are initialized with - values taken from pasynUser. Its connectDevice state is the same as that for pasynUser. -
- freeAsynUser - Free an asynUser. The user must free an asynUser only via this call. If the asynUser - is connected to a port, asynManager:disconnect is called. If the disconnect fails, - this call will also fail. The storage for the asynUser is saved on a free list and - will be reused in later calls to createAsynUser or duplicateAsynUser. Thus continually - calling createAsynUser (or duplicateAsynUser) and freeAsynUser is efficient.
- memMalloc -

- memFree

-
- Allocate/Free memory. memMalloc/memFree maintain a set of freelists of different - sizes. Thus any application that needs storage for a short time can use memMalloc/memFree - to allocate and free the storage without causing memory fragmentation. The size - passed to memFree MUST be the same as the value specified in the call to memMalloc. -
- isMultiDevice - Answers the question "Does the port support multiple devices?" This method can be - called before calling connectDevice.
- connectDevice - Connect the asynUser structure to a device specified by portName, addr. The port - Name is the same as that specified in a call to registerPort. The call will fail - if the asynUser is already connected to a device. If the port does not support multiple - devices, than addr is ignored. connectDevice only connects the asynUser to the port - driver for the portName,addr. The port driver may or may not be connected to the - actual device. Thus, connectDevice and asynCommon:connect are completely different. -

- See the Theory of Operation section for a description of the difference between - single and multi-device port drivers.

-
- disconnect - Disconnect the asynUser from the port,addr to which it is connected via a previous - call to connectDevice. The call will fail if the asynUser is queued or locked, or - has a callback registered via exceptionCallbackAdd. Note that asynManager:disconnect - and asynCommon:disconnect are completely different.
- exceptionCallbackAdd - Callback will be called whenever one of the exceptions defined by asynException - occurs. The callback can call isConnected, isEnabled, or isAutoConnect to find the - connection state. asynTrace provides methods to find out the current trace settings. -
- exceptionCallbackRemove - Callback is removed. This must be called before disconnect.
- findInterface - Find a driver interface. If interposeInterfaceOK is true, then findInterface returns - the last interface registered or interposed. Otherwise, the interface registered - by registerPort is returned. It returns 0 if the interfaceType is not supported. -

- The user needs the address of the driver's interface and of pdrvPvt so that calls - can be made to the driver. For example:

-
asynInterface *pasynInterface;
-asynOctet *pasynOctet;
-void *pasynOctetPvt;
-...
-pasynInterface = pasynManager->findInterface(
-        pasynUser,asynOctetType,1);
-if(!pasynInterface) { /*error do something*/}
-pasynOctet = (asynOctet *)pasynInterface->pinterface;
-pasynOctetPvt = pasynInterface->pdrvPvt;
-...
-/* The following call must be made from a callback */
-pasynOctet->read(pasynOctetPvt,pasynUser,...
-        
-
- queueRequest -

- When registerPort is called, the caller must specify if it can block, i.e. attribute - bit ASYN_CANBLOCK is set or cleared. If the port has been registered with ASYN_CANBLOCK - true then the request is put on a queue for the thread associated with the queue. - If the port has been registered with ASYN_CANBLOCK false then queueRequest locks - the port and calls the process callback. In either case the process callback specified - in the call to createAsynUser is called.

-

- If the asynUser is already on a queue, asynError is returned. The timeout starts - when the request is queued. A value less than or equal to 0.0 means no timeout. - The request is removed from the queue before the callback is called. Callbacks are - allowed to make requests to asynManager such as queueRequest, blockProcessCallback, - etc. It is even permissible to call freeAsynUser from a callback but the request - will be delayed until after the callback completes.

-

- The priority asynQueuePriorityConnect must be used for asynCommon:connect and asynCommon:disconnect - calls, and must NOT be used for any other calls.

-

- If a timeout callback was not passed to createAsynUser and a queueRequest with a - non-zero timeout is requested, the request fails.

-

- Attempts to queue a request other than a connection request to a disconnected port - will fail unless the reason is ASYN_REASON_QUEUE_EVEN_IF_NOT_CONNECTED.

-
- cancelRequest - If a asynUser is queued, remove it from the queue. If either the process or timeout - callback is active when cancelRequest is called than cancelRequest will not return - until the callback completes.
- blockProcessCallback -

- unblockProcessCallback

-
- blockProcessCallback is a request to prevent acccess to a device or port by other - asynUsers between queueRequests. blockProcessCallback can be called from a processCallback - or when the asynUser has no request queued. When called from processCallback blocking - starts immediately, otherwise blocking starts the next time processCallback is called. - Blocking means that no other asynUser's processCallback will be called until unblockProcessCallback - is called. Note the following restrictions for blockProcessCallback: -
    -
  • blockProcessCallback only works with drivers that can block and an error is returned - if it is called for non-blocking drivers.
  • -
  • queueRequests that specify a priority of asynQueuePriorityConnect are not blocked.
  • -
- It is permissible to simultaneously block allDevices and also the device to which - the asynUser is connected.
- lockPort/unlockPort - Lock access to a port driver. This is used by code that is willing to block while - making calls to a port driver. The code can call lockPort, make an arbitrary number - of calls to the port driver, and than call unlockPort. Other code that calls queueRequest - and/or lockPort will be delayed between the calls to lockPort and unlockPort. -
- queueLockPort/queueUnlockPort - Lock access to a port driver. This is used by code that is willing to block while - making calls to a port driver. The code can call queueLockPort, make an arbitrary - number of calls to the port driver, and than call queueUnlockPort. Other code that - calls queueRequest and/or lockPort will be delayed between the calls to queueLockPort - and queueUnlockPort. The difference between lockPort and queueLockPort is that queueLockPort - queues a request to lock the port, using the same queues as queueRequest. This means - that a thread that repeatedly calls queueLockPort without sleeping between calls - will still allow other threads to access the port. This is not true with lockPort, - which will take a mutex as soon as the port is free, and can prevent other threads - from accessing the port at all.
- setQueueLockPortTimeout - Sets the timeout passed to queueRequest() in queueLockPort(). The default value - of 2.0 seconds is set when the port is created. This function can be used to change - that value. Note that if the pasynUser->timeout value passed to queueLockPort - is larger than the current value then this larger timeout value is used.
- canBlock - yesNo is set to (0,1), i.e. (false,true) if calls to the low level driver can block. - The value is determined by the attributes passed to registerPort.
- getAddr - *addr is set equal to the address which the user specified in the call to connectDevice - or -1 if the port does not support multiple devices. -

- See the Theory of Operation section for a description of the difference between - single and multi-device port drivers.

-
- getPortName - *pportName is set equal to the name of the port to which the user is connected. -
- registerPort - This method is called by drivers. A call is made for each port instance. Attributes - is a set of bits. Currently two bits are defined: ASYN_MULTIDEVICE and ASYN_CANBLOCK. - The driver must specify these properly. autoConnect, which is (0,1) for (no,yes), - provides the initial value for the port and all devices connected to the port. priority - and stacksize are only relevant if ASYN_CANBLOCK=1, in which case asynManager uses - these values when it creates the port thread with epicsThreadCreate(). If priority - is 0, then the default value epicsThreadPriorityMedium will be assigned. If stackSize - is 0, the default value of epicsThreadGetStackSize(epicsThreadStackMedium) will - be assigned. The portName argument specifies the name by which the upper levels - of the asyn code will refer to this communication interface instance. The registerPort - method makes an internal copy of the string to which the name argument points. -
- registerInterface - This is called by port drivers for each supported interface. This method does - not make a copy of the asynInterface to which the pasynInterface argument - points. Callers must store the asynInteface in a location which is retained for - the lifetime of the port. This is commonly done by placing the asynInterface structure - in the 'driver private' structure.
- exceptionConnect - This method must be called by the driver when and only when it connects to a port - or device.
- exceptionDisconnect - This method must be called by the driver when and only when it disconnects from - a port or device.
- interposeInterface - This is called by a software layer between client code and the port driver. For - example, if a device echos writes then a software module that issues a read after - each write could be created and call interposeInterface for interface asynOctet. -

- Multiple interposeInterface calls for a port/addr/interface can be issued. *ppPrev - is set to the address of the previous asynInterface. Thus the software module that - last called interposeInterface is called by user code. It in turn can call the software - module that was the second to last to call interposeInterface. This continues until - the actual port driver is called.

-

- interposeInterface can also be called with an asynInterface that has not been previously - registered or replaced. In this case *ppPrev will be null. Thus, new interfaces - that are unknown to the low level driver can be implemented.

-
- enable - If enable is set yes, then queueRequests are not dequeued unless their queue timeout - occurs.
- autoConnect - If autoConnect is true and the port or device is not connected when a user callback - is scheduled to be called, asynManager calls pasynCommon->connect. See the discussion - of Flow of Control below for details.
- isConnected - *yesNo is set to (0,1) if the port or device (is not, is) connected.
- isEnabled - *yesNo is set to (0,1) if the port or device (is not, is) enabled.
- isAutoConnect - *yesNo is set to (0,1) if the portThread (will not, will) autoConnect for the port - or device.
- setAutoConnectTimeout - Changes the timeout when waiting for the initial connection callback from port drivers. - This callback occurs in response to asynManager queueing a connection request, which - happens when the port driver registers its asynCommon interface. The default timeout - is 0.5 seconds.
- waitConnect - Wait for up to timeout seconds for the port/device to connect.
- registerInterruptSource - If a low level driver supports interrupts it must call this for each interface that - supports interrupts. pasynPvt must be the address of a void * that will be given - a value by registerInterruptSource. This argument is passed interruptStart and interruptEnd. -
- getInterruptPvt - Any code that wants to call createInterruptNode but does not know the adresss of - pasynPvt can find it via this method. The caller must be connected to a device, - i.e. must have called connectDevice. If the caller is not connected, getInterruptPvt - returns asynError.
- createInterruptNode -

- freeInterruptNode

-
- These methods are the only way a user can allocate and free an interruptNode. pasynPvt - is the value obtained from getInterruptPvt. createInterruptNode/freeInterruptNode - are separate methods rather than being done automatically by addInterruptUser/removeInterruptUser - so that addInterruptUser/removeInterruptUser can be efficient.
- addInterruptUser -

- removeInterruptUser

-
- Code that implements registerInterruptUser/cancelInterruptUser must call addInterruptUser/removeInterruptUser - to add and remove users from the list or else calls to interruptStart/interruptEnd - will not work. This is an efficient operation so that a user can repeatedly call - registerInterruptUser/cancelInterruptUser. If either of these is called while a - interrupt is being processed, i.e. between calls to interruptStart/interruptEnd, - the call will block until interruptEnd is called. The process callback for the asynUser - specified in the call to addInterruptUser must not call removeInterruptUser or it - will block forever.
- interruptStart -

- interruptEnd

-
- The code that implements interrupts is interface dependent. The only service asynManager - provides is a thread-safe implemention of the user list. When the code wants to - call the callback specified in the calls to registerInterruptUser, it calls interruptStart - to obtain the list of callbacks. When it is done it calls interruptEnd. If any requests - are made to addInterruptUser/removeInterruptUser between the calls to interruptStart - and interruptEnd, asynManager delays the requests until interruptEnd is called. -
- registerTimeStampSource - Registers a user-defined time stamp callback function.
- unregisterTimeStampSource - Unregisters any user-defined timestamp callback function and reverts to the default - timestamp source function in asynManager, which simply calls epicsTimeGetCurrent(). -
- updateTimeStamp - Set the current time stamp for this port by calling either the default timestamp - source, or a user-defined timestamp source that was registered with registerTimeStampSource. -
- getTimeStamp - Get the current time stamp for this port that was returned by the most recent call - to updateTimeStamp.
- setTimeStamp - Set the current time stamp for this port directly from the timestamp value passed - to this function.
- strStatus - Returns a descriptive string corresponding to the asynStatus value.
-

- asynCommon

-

- asynCommon describes the methods that must be implemented by drivers.

-
/* Device Interface supported by ALL asyn drivers*/
-#define asynCommonType "asynCommon"
-typedef struct  asynCommon {
-    void       (*report)(void *drvPvt,FILE *fp,int details);
-    /*following are to connect/disconnect to/from hardware*/
-    asynStatus (*connect)(void *drvPvt,asynUser *pasynUser);
-    asynStatus (*disconnect)(void *drvPvt,asynUser *pasynUser);
-}asynCommon;
- - - - - - - - - - - - - - - - -
- asynCommon
- report - Generates a report about the hardware device. This is the only asynCommon method - that does not have to be called by the queueRequest callback or between calls to - lockPort/unlockPort.
- connect - Connect to the hardware device or communication path. The queueRequest must specify - priority asynQueuePriorityConnect.
- disconnect - Disconnect from the hardware device or communication path. The queueRequest must - specify priority asynQueuePriorityConnect.
-

- asynCommonSyncIO

-

- asynCommonSyncIO provides a convenient interface for software that needs to perform - "synchronous" operations to an asyn device, i.e. that blocks while waiting for the - port to be available and for the operation to complete. The code does not need to - handle callbacks or understand the details of the asynManager and asynCommon interfaces.

-
typedef struct asynCommonSyncIO {
-    asynStatus (*connect)(const char *port, int addr, 
-                          asynUser **ppasynUser, const char *drvInfo);
-    asynStatus (*disconnect)(asynUser *pasynUser);
-    asynStatus (*connectDevice)(asynUser *pasynUser);
-    asynStatus (*disconnectDevice)(asynUser *pasynUser);
-    asynStatus (*report)(asynUser *pasynUser, FILE *fd, int details);
-} asynCommonSyncIO;
-epicsShareExtern asynCommonSyncIO *pasynCommonSyncIO;
-

- Note that there is a potential for confusion in the connect* and disconnect* function - names of this interface. For consistency with the other SyncIO interfaces, connect - calls pasynManager->connectDevice, disconnect calls pasynManager->disconnect, - connectDevice calls asynCommon->connect, and disconnectDevice calls asynCommon->disconnect.

-

- asynDrvUser

-

- asynDrvUser provides methods that allow an asynUser to communicate user specific - information to/from a port driver

-
#define asynDrvUserType "asynDrvUser"
-typedef struct  asynDrvUser {
-    /*The following do not have to be called via queueRequest callback*/
-    asynStatus (*create)(void *drvPvt,asynUser *pasynUser,
-        const char *drvInfo, const char **pptypeName,size_t *psize);
-    asynStatus (*getType)(void *drvPvt,asynUser *pasynUser,
-        const char **pptypeName,size_t *psize);
-    asynStatus (*destroy)(void *drvPvt,asynUser *pasynUser);
-}asynDrvUser;
- - - - - - - - - - - - - - - - -
- asynDrvUser
- create - The user, i.e. device support calls create. The driver can create any resources - it needs. It can use pasynUser->drvUser to provide access to the resources. If - the asynUser and the driver both know how to access the resources they must agree - about the name for the resource and a size. If pptypeName is not null the driver - can give a value to *pptypeName. If psize is not null the driver can give a value - to *psize. Unless asynUser receives a typeName and size that it recognizes it must - not access asynUser.drvUser.
- getType - If other code, e.g. an interposeInterface wants to access asynUser.drvUser it must - call this and verify that typeName and size are what it expects.
- destroy - Destroy the resources created by create and set asynUser.drvUser null.
-

- asynLockPortNotify

-

- This is provided for port drivers that are an asynUser of another port driver. For - example a serial bus driver can be implemented by connecting to a standard serial - port to perform the actual I/O. When the serial bus port is locked, either by the - requester calling lockPort or because a queueRequest was dequeued, then the serial - bus driver needs to lock the associated serial port.

-

- The serial bus driver registers interface asynLockPortNotify. Whenever the serial - bus port is locked, asynManager calls pasynLockPortNotify.lock. The serial bus driver - calls asynManager.lockPort for the serial port to which it is connected. Similarly - for unlockPort. Thus while the serial bus port is locked, the serial bus is also - locked.

-

- asynLockPortNotify is used only by asynManager itself. It is not put in the list - of interfaces for the port.

-

- asynLockPortNotify is:

-
#define asynLockPortNotifyType "asynLockPortNotify"
-typedef struct  asynLockPortNotify {
-    asynStatus (*lock)(void *drvPvt,asynUser *pasynUser);
-    asynStatus (*unlock)(void *drvPvt,asynUser *pasynUser);
-}asynLockPortNotify;
- - - - - - - - - - - - -
- asynLockPortNotify
- lock - Called when asynManager.lockPort is called. The driver normally calls asynManager.lockPort - for the port to which it is connected.
- unlock - Called when asynManager.unlockPort is called. The driver normally calls asynManager.unlockPort - for the port to which it is connected.
-

- asynOption

-

- asynOption provides a generic way of setting driver specific options. For example - the serial port driver uses this to specify baud rate, stop bits, etc.

-
#define asynOptionType "asynOption"
-/*The following are generic methods to set/get device options*/
-typedef struct asynOption {
-    asynStatus (*setOption)(void *drvPvt, asynUser *pasynUser,
-                                const char *key, const char *val);
-    asynStatus (*getOption)(void *drvPvt, asynUser *pasynUser,
-                                const char *key, char *val, int sizeval);
-}asynOption;
- - - - - - - - - - - - -
- asynOption
- setOption - Set value associated with key.
- getOption - Get value associated with key.
-

- Trace Interface

-
/*asynTrace is implemented by asynManager*/
-/*All asynTrace methods can be called from any thread*/
-/* traceMask definitions*/
-#define ASYN_TRACE_ERROR     0x0001
-#define ASYN_TRACEIO_DEVICE  0x0002
-#define ASYN_TRACEIO_FILTER  0x0004
-#define ASYN_TRACEIO_DRIVER  0x0008
-#define ASYN_TRACE_FLOW      0x0010
-#define ASYN_TRACE_WARNING   0x0020
-
-/* traceIO mask definitions*/
-#define ASYN_TRACEIO_NODATA 0x0000
-#define ASYN_TRACEIO_ASCII  0x0001
-#define ASYN_TRACEIO_ESCAPE 0x0002
-#define ASYN_TRACEIO_HEX    0x0004
-
-/* traceInfo mask definitions*/
-#define ASYN_TRACEINFO_TIME 0x0001
-#define ASYN_TRACEINFO_PORT 0x0002
-#define ASYN_TRACEINFO_SOURCE 0x0004
-#define ASYN_TRACEINFO_THREAD 0x0008
-
-/* asynPrint and asynPrintIO are macros that act like
-   int asynPrintSource(asynUser *pasynUser,int reason, __FILE__, __LINE__, const char *format, ... );
-   int asynPrintIOSource(asynUser *pasynUser,int reason,
-        const char *buffer, size_t len, __FILE__, __LINE__, const char *format, ... );
-*/
-typedef struct asynTrace {
-    /* lock/unlock are only necessary if caller performs I/O other than */
-    /* by calling asynTrace methods                                     */
-    asynStatus (*lock)(asynUser *pasynUser);
-    asynStatus (*unlock)(asynUser *pasynUser);
-    asynStatus (*setTraceMask)(asynUser *pasynUser,int mask);
-    int        (*getTraceMask)(asynUser *pasynUser);
-    asynStatus (*setTraceIOMask)(asynUser *pasynUser,int mask);
-    int        (*getTraceIOMask)(asynUser *pasynUser);
-    asynStatus (*setTraceInfoMask)(asynUser *pasynUser,int mask);
-    int        (*getTraceInfoMask)(asynUser *pasynUser);
-    asynStatus (*setTraceFile)(asynUser *pasynUser,FILE *fp);
-    FILE       *(*getTraceFile)(asynUser *pasynUser);
-    asynStatus (*setTraceIOTruncateSize)(asynUser *pasynUser,size_t size);
-    size_t     (*getTraceIOTruncateSize)(asynUser *pasynUser);
-#if defined(__GNUC__) && (__GNUC__ < 3)
-    /* GCC 2.95 does not allow EPICS_PRINTF_STYLE on function pointers */
-    int        (*print)(asynUser *pasynUser,int reason, const char *pformat, ...);
-    int        (*printSource)(asynUser *pasynUser,int reason, const char *fileName, int line, const char *pformat, ...);
-    int        (*vprint)(asynUser *pasynUser,int reason, const char *pformat, va_list pvar);
-    int        (*vprintSource)(asynUser *pasynUser,int reason, const char *file, int line, const char *pformat, va_list pvar);
-    int        (*printIO)(asynUser *pasynUser,int reason,
-                    const char *buffer, size_t len,const char *pformat, ...);
-    int        (*printIOSource)(asynUser *pasynUser,int reason,
-                    const char *buffer, size_t len,const char *file, int line, const char *pformat, ...);
-    int        (*vprintIO)(asynUser *pasynUser,int reason,
-                    const char *buffer, size_t len,const char *pformat, va_list pvar);
-    int        (*vprintIOSource)(asynUser *pasynUser,int reason,
-                    const char *buffer, size_t len,const char *file, int line, const char *pformat, va_list pvar);
-#else
-    int        (*print)(asynUser *pasynUser,int reason, const char *pformat, ...) EPICS_PRINTF_STYLE(3,4);
-    int        (*printSource)(asynUser *pasynUser,int reason, const char *fileName, int line, const char *pformat, ...) EPICS_PRINTF_STYLE(5,6);
-    int        (*vprint)(asynUser *pasynUser,int reason, const char *pformat, va_list pvar) EPICS_PRINTF_STYLE(3,0);
-    int        (*vprintSource)(asynUser *pasynUser,int reason, const char *file, int line, const char *pformat, va_list pvar) EPICS_PRINTF_STYLE(5,0);
-    int        (*printIO)(asynUser *pasynUser,int reason,
-                    const char *buffer, size_t len,const char *pformat, ...) EPICS_PRINTF_STYLE(5,6);
-    int        (*printIOSource)(asynUser *pasynUser,int reason,
-                    const char *buffer, size_t len,const char *file, int line, const char *pformat, ...) EPICS_PRINTF_STYLE(7,8);
-    int        (*vprintIO)(asynUser *pasynUser,int reason,
-                    const char *buffer, size_t len,const char *pformat, va_list pvar) EPICS_PRINTF_STYLE(5,0);
-    int        (*vprintIOSource)(asynUser *pasynUser,int reason,
-                    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;
-
-

- asynTrace

-

- asynDriver provides a trace facility with the following attributes:

-
    -
  • Tracing is turned on/off for individual devices, i.e. a portName, addr.
  • -
  • Trace has a global trace mask for asynUsers not connected to a port or port, addr.
  • -
  • The output is sent to a file or to stdout or to errlog.
  • -
  • A mask determines the type of information that can be displayed. The various choices - can be ORed together. The default value of this mask when a port is created is ASYN_TRACE_ERROR. -
      -
    • ASYN_TRACE_ERROR Run time errors are reported, e.g. timeouts.
    • -
    • ASYN_TRACEIO_DEVICE Device support reports I/O activity.
    • -
    • ASYN_TRACEIO_FILTER Any layer between device support and the low level driver - reports any filtering it does on I/O.
    • -
    • ASYN_TRACEIO_DRIVER Low level driver reports I/O activity.
    • -
    • ASYN_TRACE_FLOW Report logic flow. Device support should report all queue requests, - callbacks entered, and all calls to drivers. Layers between device support and low - level drivers should report all calls they make to lower level drivers. Low level - drivers report calls they make to other support.
    • -
    • ASYN_TRACE_WARNING Report warnings, i.e. conditions that are between ASYN_TRACE_ERROR - and ASYN_TRACE_FLOW.
    • -
    -
  • -
  • Another mask determines how message buffers are printed. The various choices can - be ORed together. The default value of this mask when a port is created is ASYN_TRACEIO_NODATA. -
      -
    • ASYN_TRACEIO_NODATA Don't print any data from the message buffers.
    • -
    • ASYN_TRACEIO_ASCII Print with a "%s" style format.
    • -
    • ASYN_TRACEIO_ESCAPE Call epicsStrPrintEscaped.
    • -
    • ASYN_TRACEIO_HEX Print each byte with " %2.2x".
    • -
    -
  • -
  • Another mask determines what information is printed at the beginning of each message. - The various choices can be ORed together. The default value of this mask when a - port is created is ASYN_TRACEINFO_TIME. -
      -
    • ASYN_TRACEINFO_TIME prints 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 or asynPrintIO statement occurs.
    • -
    • ASYN_TRACEINFO_THREAD prints the thread name, thread ID and thread priority, i.e. - [epicsThreadGetNameSelf(), epicsThreadGetIdSelf(), epicsThreadGetPrioritySelf()].
    • -
    -
  • -
-

- In order for the trace facility to perform properly; device support and all drivers - must use the trace facility. Device and driver support can directly call the asynTrace - methods. The asynPrint and asynPrintIO macros are provided so that it is easier - for device/driver support. Support can have calls like:

-
    asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s Calling queueRequest\n",
-        someName);
-

- The asynPrintIO call is designed for device support or drivers that issue read or - write requests. They make calls like:

-
    asynPrintIO(pasynUser,ASYN_TRACEIO_DRIVER,data,nchars,"%s nchars %d",
-
                someName,nchars);
-

- The asynTrace methods are implemented by asynManager. These methods can be used - by any code that has created an asynUser and is connected to a device. All methods - can be called by any thread. That is, an application thread and/or a portThread. - If a thread performs all I/O via calls to print or printIO, then it does not have - to call lock or unlock. If it does want to do its own I/O, it must lock before any - I/O and unlock after. For example:

-
    pasynTrace->lock(pasynUser);
-    fd = pasynTrace->getTraceFile(pasynUser);
-    /*perform I/O to fd */
-    pasynTrace->unlock(pasynUser);
-

- If the asynUser is not connected to a port, i.e. pasynManager->connectDevice - has not been called, then a "global" device is assumed. This is useful when asynPrint - is called before connectDevice.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynTrace
- lock/unlock - These are only needed for code that call asynTrace.print or asynTrace.printIO instead - of asynPrint and asynPrintIO. -

- print, and printIO both lock while performing their operations. The get methods - do not lock (except for getTraceFile) and they are safe. Except for setTraceFile - the set methods do not block, since worst that can happen is that the user gets - a little more or a little less output.

-
- setTraceMask - Set the trace mask. Normally set by the user requesting it via a shell command or - the devTrace device support. Setting the trace mask for a port also sets the trace - mask for all devices connected to that port
- getTraceMask - Get the trace mask. Device support that wants to issue trace messages calls this - to see what trace options have been requested.
- setTraceIOMask - Set the traceIO mask. Normally set by the user requesting it via a shell command - or the devTrace device support. Setting the traceIO mask for a port also sets the - traceIO mask for all devices connected to that port
- getTraceIOMask - Get the traceIO mask. Support that wants to issue its own IO messages instead of - calling asynPrintIO should call this and honor the mask settings. Most code will - not need it.
- setTraceInfoMask - Set the traceInfo mask. Normally set by the user requesting it via a shell command - or the devTrace device support. Setting the traceInfo mask for a port also sets - the traceInfo mask for all devices connected to that port
- getTraceInfoMask - Get the traceInfo mask. Support that wants to issue its own IO messages instead - of calling asynPrint should call this and honor the mask settings. Most code will - not need it.
- setTraceFile - Set the stream to use for output. A NULL argument means use errlog. Normally set - by the user requesting it via a shell command or by the devTrace device support. - If the current output stream is none of (NULL, stdout, stderr) then the current - output stream is closed before the new stream is used.
- getTraceFile - Get the file descriptor to use for output. Device support that wants to issue its - own IO messages instead of calling asynPrintIO should call this and honor the mask - settings. In this case, lock must have been called first. Most code will not need - it. If the return value is 0, then ouput should be directed to errlog.
- setTraceIOTruncateSize - Determines how much data is printed by printIO. In all cases it determines how many - bytes of the buffer are displayed. The actual number of characters printed depends - on the traceIO mask. For example ASYN_TRACEIO_HEX results in 3 characters being - printed for each byte. Normally set by the user requesting it via a shell command - or the devTrace device support.
- getTraceIOTruncateSize - Get the current truncate size. Called by asynPrintIO. Code that does its own I/O - should also support the traceIO mask.
- print - If reason ORed with the current traceMask is not zero, then the message is printed. - This method is provided for backwards compatibility. The asynPrint macro now calls - printSource().
- printSource - If reason ORed with the current traceMask is not zero, then the message is printed. - Most code should call asynPrint instead of calling this method. This method is the - same as print() but with the additional file and line arguments. -
- vprint - This is the same as print, but using a va_list as its final argument.
- vprintSource - This is the same as printSource, but using a va_list as its final argument.
- printIO - If reason ORed with the current traceMask is not zero then the message is printed. - If len is >0, then the buffer is printed using the traceIO mask and getTraceIOTruncateSize. - This method is provided for backwards compatibility. The asynPrintIO macro now calls - printIOSource().
- printIOSource - If reason ORed with the current traceMask is not zero then the message is printed. - If len is >0, then the buffer is printed using the traceIO mask and getTraceIOTruncateSize. - Most code should call asynPrintIO instead of calling this method. This method is - the same as printIO() but with the additional file and line arguments. -
- vprintIO - This is the same as printIO, but using a va_list as its final argument.
- vprintIOSource - This is the same as printIOSource, but using a va_list as its final argument. -
-
-

- Standard Message Based Interfaces

-

- These are interfaces for communicating with message based devices, where message - based means that the device communicates via octet strings, i.e. arrays of 8 bit - bytes. Three interfaces are provided: asynOctet, asynOctetBase, and asynOctetSyncIO. - asynOctet is generic message based interface. asynOctetBase is an interface used - by port drivers that implement asynOctet. It's primary purpose is to help with interrupt - support. asynOctetSyncIO provides a synchronous inteface to asynOctet and can be - used by code that is willing to block.

-

- asynOctet

-

- asynOctet describes the methods implemented by drivers that use octet strings for - sending commands and receiving responses from a device.

-

- NOTE: The name octet is used instead of ASCII because it implies that communication - is done via 8-bit bytes.

-
#define ASYN_EOM_CNT 0x0001 /*Request count reached*/
-#define ASYN_EOM_EOS 0x0002 /*End of String detected*/
-#define ASYN_EOM_END 0x0004 /*End indicator detected*/
-
-typedef void (*interruptCallbackOctet)(void *userPvt, asynUser *pasynUser,
-              char *data,size_t numchars, int eomReason);
-
-typedef struct asynOctetInterrupt {
-    asynUser *pasynUser;
-    int      addr;
-    interruptCallbackOctet callback;
-    void *userPvt;
-}asynOctetInterrupt;
-
-
-#define asynOctetType "asynOctet"
-typedef struct asynOctet{
-    asynStatus (*write)(void *drvPvt,asynUser *pasynUser,
-                    const char *data,size_t numchars,size_t *nbytesTransfered);
-    asynStatus (*read)(void *drvPvt,asynUser *pasynUser,
-                    char *data,size_t maxchars,size_t *nbytesTransfered,
-                    int *eomReason);
-    asynStatus (*flush)(void *drvPvt,asynUser *pasynUser);
-    asynStatus (*registerInterruptUser)(void *drvPvt,asynUser *pasynUser,
-                    interruptCallbackOctet callback, void *userPvt,
-                    void **registrarPvt);
-    asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser,
-                    void *registrarPvt);
-    asynStatus (*setInputEos)(void *drvPvt,asynUser *pasynUser,
-                    const char *eos,int eoslen);
-    asynStatus (*getInputEos)(void *drvPvt,asynUser *pasynUser,
-                    char *eos, int eossize, int *eoslen);
-    asynStatus (*setOutputEos)(void *drvPvt,asynUser *pasynUser,
-                    const char *eos,int eoslen);
-    asynStatus (*getOutputEos)(void *drvPvt,asynUser *pasynUser,
-                    char *eos, int eossize, int *eoslen);
-}asynOctet;
-/* asynOctetBase does the following:
-   calls  registerInterface for asynOctet.
-   Implements registerInterruptUser and cancelInterruptUser
-   Provides default implementations of all methods.
-   registerInterruptUser and cancelInterruptUser can be called
-   directly rather than via queueRequest.
-*/
-
-#define asynOctetBaseType "asynOctetBase"
-typedef struct asynOctetBase {
-    asynStatus (*initialize)(const char *portName,
-        asynDriverasynInterface *pasynOctetInterface,
-        int processEosIn,int processEosOut,int interruptProcess);
-    void       (*callInterruptUsers)(asynUser *pasynUser,void *pasynPvt,
-        char *data,size_t *nbytesTransfered,int *eomReason);
-} asynOctetBase;
-epicsShareExtern asynOctetBase *pasynOctetBase;
-

-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynOctet
- write - Send a message to the device. *nbytesTransfered is the number of 8-bit bytes sent - to the device. Interpose or driver code may add end of string terminators to the - message but the extra characters are not included in *nbytesTransfered.
- read - Read a message from the device. *nbytesTransfered is the number of 8-bit bytes read - from the device. If read returns asynSuccess than eomReason ( some combination of - ASYN_EOM_CNT, ASYN_EOM_EOS, and ASYN_EOM_END)tells why the read completed. Interpose - or driver code may strip end of string terminators from the message. If it does - the first eos character will be replaced by null and the eos characters will not - be included in nbytesTransfered.
- flush - Flush the input buffer.
- registerInterruptUser - Register a user that will be called whenever a new message is received. NOTE: The - callback must not block and must not call registerInterruptUser or cancelInterruptUser. -
- cancelInterruptUser - Cancel a registered user.
- setInputEos - Set End Of String for input. For example "\n". Note that gpib drivers usually accept - at most a one character terminator.
- getInputEos - Get the current End of String.
- setOutputEos - Set End Of String for output.
- getOutputEos - Get the current End of String.
-

- asynOctetBase is an interface and implementation for drivers that implement interface - asynOctet. asynOctetBase implements registerInterruptUser and cancelInterruptUser.

-

- For single device support, it can optionally implement interrupt support. A driver - that implements interrupts must call registerInterruptSource. If it asks asynOctetBase - to handle interrupts it calls asynOctetBase:callInterruptUsers when it has new data.

-

- For single device support asynOctetBase can optionally call asynInterposeEosConfig - to handle end of string processing for input and/or output.

-

- Any null method in the interface passed to initialize are replaced by a method supplied - by asynOctetBase.

-

- For an example of how to use asynOctetBase look at - asyn/testApp/src/echoDriver.c

- - - - - - - - - - - - -
- asynOctetBase
- initialize - After a driver calls registerPort it can call: -
pasynOctetBase->initialize(...
- Any null methods in the asynInterface are replaced by default implementations. If - the port is not multi-device and either processEosIn or processEosOut is specified, - asynInterposeEosConfig is called. If the port is not multi-device and interruptProcess - is specified, then whenever read is called, asynBase calls all the registered interrupt - users. asynOctetBase can not implement processEosIn, processEosOut, and interruptProcess - if the port is a multi-device port. Since this method is called only during initialization - it can be called directly rather than via queueRequest.
- callInterruptUsers - Calls the callbacks registered via registerInterruptUser.
-

- asynOctetSyncIO

-

- asynOctetSyncIO provides a convenient interface for software that needs to perform - "synchronous" I/O to an asyn device, i.e. that starts an I/O operation and then - blocks while waiting for the response. The code does not need to handle callbacks - or understand the details of the asynManager and asynOctet interfaces. Examples - include motor drivers running in their own threads, SNL programs, and the shell - commands described later in this document.

-
typedef struct asynOctetSyncIO {
-   asynStatus (*connect)(const char *port, int addr,
-                         asynUser **ppasynUser, const char *drvInfo);
-   asynStatus (*disconnect)(asynUser *pasynUser);
-   asynStatus (*write)(asynUser *pasynUser,
-                  char const *buffer, size_t buffer_len,
-                  double timeout,size_t *nbytesTransfered);
-   asynStatus (*read)(asynUser *pasynUser, char *buffer, size_t buffer_len,
-                  double timeout, size_t *nbytesTransfered,int *eomReason);
-   asynStatus (*writeRead)(asynUser *pasynUser,
-                  const char *write_buffer, size_t write_buffer_len,
-                  char *read_buffer, size_t read_buffer_len,
-                  double timeout,
-                  size_t *nbytesOut, size_t *nbytesIn, int *eomReason);
-   asynStatus (*flush)(asynUser *pasynUser);
-   asynStatus (*setInputEos)(asynUser *pasynUser,
-                  const char *eos,int eoslen);
-   asynStatus (*getInputEos)(asynUser *pasynUser,
-                  char *eos, int eossize, int *eoslen);
-   asynStatus (*setOutputEos)(asynUser *pasynUser,
-                  const char *eos,int eoslen);
-   asynStatus (*getOutputEos)(asynUser *pasynUser,
-                  char *eos, int eossize, int *eoslen);
-   asynStatus (*writeOnce)(const char *port, int addr,
-                  char const *buffer, size_t buffer_len, double timeout,
-                  size_t *nbytesTransfered, const char *drvInfo);
-   asynStatus (*readOnce)(const char *port, int addr,
-                  char *buffer, size_t buffer_len, double timeout,
-                  size_t *nbytesTransfered,int *eomReason, const char *drvInfo);
-   asynStatus (*writeReadOnce)(const char *port, int addr,
-                  const char *write_buffer, size_t write_buffer_len,
-                  char *read_buffer, size_t read_buffer_len,
-                  double timeout,
-                  size_t *nbytesOut, size_t *nbytesIn, int *eomReason,
-                  const char *drvInfo);
-   asynStatus (*flushOnce)(const char *port, int addr,const char *drvInfo);
-   asynStatus (*setInputEosOnce)(const char *port, int addr,
-                  const char *eos,int eoslen,const char *drvInfo);
-   asynStatus (*getInputEosOnce)(const char *port, int addr,
-                  char *eos, int eossize, int *eoslen,const char *drvInfo);
-   asynStatus (*setOutputEosOnce)(const char *port, int addr,
-                  const char *eos,int eoslen,const char *drvInfo);
-   asynStatus (*getOutputEosOnce)(const char *port, int addr,
-                  char *eos, int eossize, int *eoslen,const char *drvInfo);
-} asynOctetSyncIO;
-epicsShareExtern asynOctetSyncIO *pasynOctetSyncIO;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynOctetSyncIO
- connect - Connects to an asyn port and address, returns a pointer to an asynUser structure. -
- disconnect - Disconnect. This frees all resources allocated by connect.
- write - Calls asynOctet->write and waits for the operation to complete or time out. -
- read - Calls asynOctet->read. Waits for the operation to complete or time out.
- writeRead - Calls pasynOctet->flush, pasynOctet->write, and asynOctet->read. Waits - for the operations to complete or time out.
- flush - Calls pasynOctet->flush
- setInputEos - Calls pasynOctet->setInputEos
- getInputEos - Calls pasynOctet->getInputEos
- setOutputEos - Calls pasynOctet->setOutputEos
- getOutputEos - Calls pasynOctet->getOutputEos
- writeOnce - This does a connect, write, and disconnect.
- readOnce - This does a connect, read, and disconnect.
- readOnce - This does a connect, read, and disconnect.
- writeReadOnce - This does a connect, writeRead, and disconnect.
-

- End of String Support

-

- asynOctet provides methods for handling end of string (message) processing. It does - not specify policy. Device support code, interpose layers, or low level drivers - can all handle EOS processing. An application developer must decide what policy - will be followed for individual devices. The policy will be determined by the device, - the device support, and the driver.

-
-

- Standard Register Based Interfaces

-

- Introduction

-

- This section descibes interfaces for register based devices. Support is provided - for:

-
    -
  • Int32 - registers appear as 32 integers
  • -
  • UInt32Digital - registers appear a 32 bit unsigned integers and masks can be used - to address specific bits.
  • -
  • Float64 - registers appear as double precision floats.
  • -
  • Int8Array - Arrays of 8 bit integers.
  • -
  • Int16Array - Arrays of 16 bit integers.
  • -
  • Int32Array - Arrays of 32 bit integers.
  • -
  • Float32Array - Arrays of single precision floats.
  • -
  • Float64Array - Arrays of double precision floats.
  • -
  • Enum - Arrays of strings, integer values and integer severities.
  • -
  • GenericPointer - void* pointer.
  • -
-

- Note that hardware may have registers with smaller sizes, e.g. 16 bit registers. - The standard interfaces can still be used by setting the unused bits to 0.

-

- For all of these interfaces a default implementation and a synchronous inplementation - are provided. Lets use Int32 as an example.

-
    -
  • asynInt32 - An interface with methods: read, write, getBounds, registerInterruptUser, - and cancelInterruptUser.
  • -
  • asynInt32Base - An interface used by drivers that implement asynInt32. It also - has an implementation that: -
      -
    • registers the asynInt32 interface
    • -
    • has default methods for read, write, and getBounds. A null method in the interface - passed to initialize is replaced by a method implemented by asynInt32Base.
    • -
    • implements registerInterruptUser and cancelInterruptUser. The caller should leave - these methods null because asynInt32Base always replaces them by it's implementation.
    • -
    - Drivers that implement asynInt32 normally call asynInt32Base:initialize. It implements - registerInterruptUser and cancelInterruptUser. If the driver provides interrupt - support it must: -
      -
    • Call pasynInt32Base->initialize
    • -
    • Call pasynManager->registerInterruptSource
    • -
    • Interact with asynManager to call the users that have registered with asynInt32Base:registerInterruptUser. - The driver calls users when there is new data available.
    • -
    - asyn/testEpicsApp/src/int32Driver.c provides - an example of how to provide support for interrupts.
  • -
  • asynInt32SyncIO - A synchronous interface to asynInt32
  • -
-

- addr - What does it mean for register based interfaces?

-

- Low level register based drivers are normally multi-device. The meaning of addr - is:

-
    -
  • Int32 - The driver supports an array of Int32 values. addr selects an array element. - For example a 16 channel ADC would support addr 0 through 15.
  • -
  • Int8Array - Each addr is an array of Int8 values.
  • -
  • Int16Array - Each addr is an array of Int16 values.
  • -
  • Int32Array - Each addr is an array of Int32 values.
  • -
  • Float64 - The driver supports an array of Float64 values. addr selects an array - element.
  • -
  • Float32Array - Each addr is an array of Float32 values.
  • -
  • Float64Array - Each addr is an array of Float64 values.
  • -
  • UInt32Digital - The driver supports an array of UInt32 values. addr selects an - array element. For example a 128 bit digital I/O module appears as an array of four - UInt32 registers.
  • -
-

- Example Drivers

-

- Two examples of drivers that might implement and use the interfaces are:

-
    -
  • Analog to Digital Convertor. -

    - An example is a 16 channel ADC. The driver implements interfaces asynCommon and - asynInt32. It uses interface asynInt32Base. It can call asynManager:interruptStart - and asynManager:interruptEnd to support interrupts. It can use pasynUser->reason - and addr to decide which callbacks to call. asyn/testEpicsApp/int32Driver.c - is a soft example of how to implement a driver that implements asynInt32 and also - asynFloat64.

    -
  • -
  • Digital I/O module -

    - An example is a 64 bit combination digital input and digital output module. The - driver implements interfaces asynCommon and asynUInt32Digital. It uses interface - asynUInt32DigitalBase. It can call asynManager:interruptStart and asynManager:interruptEnd - to support interrupts. It can use reason, mask, and addr to decide which callbacks - to call. asyn/testEpicsApp/uint32DigitalDriver.c - is a soft example of a driver that implements asynUInt32Digital.

    -
  • -
-

- asynInt32

-

- asynInt32 describes the methods implemented by drivers that use integers for communicating - with a device.

-
typedef void (*interruptCallbackInt32)(void *userPvt, asynUser *pasynUser, 
-                                       epicsInt32 data);
-typedef struct asynInt32Interrupt {
-    int addr;
-    asynUser *pasynUser;
-    interruptCallbackInt32 callback;
-    void *userPvt;
-} asynInt32Interrupt;
-#define asynInt32Type "asynInt32"
-typedef struct asynInt32 {
-    asynStatus (*write)(void *drvPvt, asynUser *pasynUser, epicsInt32 value);
-    asynStatus (*read)(void *drvPvt, asynUser *pasynUser, epicsInt32 *value);
-    asynStatus (*getBounds)(void *drvPvt, asynUser *pasynUser,
-                           epicsInt32 *low, epicsInt32 *high);
-    asynStatus (*registerInterruptUser)(void *drvPvt,asynUser *pasynUser,
-                           interruptCallbackInt32 callback, void *userPvt,
-                           void **registrarPvt);
-    asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser,
-                    void *registrarPvt);
-} asynInt32;
-
-/* asynInt32Base does the following:
-   calls  registerInterface for asynInt32.
-   Implements registerInterruptUser and cancelInterruptUser
-   Provides default implementations of all methods.
-   registerInterruptUser and cancelInterruptUser can be called
-   directly rather than via queueRequest.
-*/
-
-#define asynInt32BaseType "asynInt32Base"
-typedef struct asynInt32Base {
-    asynStatus (*initialize)(const char *portName,
-                            asynInterface *pint32Interface);
-} asynInt32Base;
-epicsShareExtern asynInt32Base *pasynInt32Base;
- - - - - - - - - - - - - - - - - - - - - - - - -
- asynInt32
- write - Write an integer value to the device.
- read - Read an integer value from the device.
- getBounds - Get the bounds. For example a 16 bit ADC might set low=-32768 and high = 32767. -
- registerInterruptUser - Registers a callback that will be called whenever new data is available. Since it - can be called directly rather than via a queueRequest this method must not block. -
- cancelInterruptUser - Cancels the callback. Since it can be called directly rather than via a queueRequest - this method must not block.
-

-

-

- asynInt32Base is an interface and associated code that is used by drivers that implement - interface asynInt32. asynInt32Base provides code to handle registerInterruptUser/cancelInterruptUser. - The driver must itself call the callbacks via calls to asynManager:interruptStart - and asynManager:interruptEnd.

- - - - - - - - -
- asynInt32Base
- initialize - After a driver calls registerPort it can call: -
pasynInt32Base->initialize(...
- Any null methods in the asynInterface are replaced by default implementations. -
-

-

-

- The default implementation of each method does the following:

- - - - - - - - - - - - - - - - - - - - - - - - -
- asynInt32
- write - Reports an error "write is not supported" and returns asynError
- read - Reports an error "read is not supported" and returns asynError
- getBounds - Reports an error "getBounds is not supported" and returns asynError
- registerInterruptUser - registers an interrupt callback.
- cancelInterruptUser - Cancels the callback
-

- asynInt32SyncIO

-

- asynInt32SyncIO describes a synchronous interface to asynInt32. The code that calls - it must be willing to block.

-
#define asynInt32SyncIOType "asynInt32SyncIO"
-typedef struct asynInt32SyncIO {
-    asynStatus (*connect)(const char *port, int addr,
-                          asynUser **ppasynUser, const char *drvInfo);
-    asynStatus (*disconnect)(asynUser *pasynUser);
-    asynStatus (*write)(asynUser *pasynUser, epicsInt32 value,double timeout);
-    asynStatus (*read)(asynUser *pasynUser, epicsInt32 *pvalue,double timeout);
-    asynStatus (*getBounds)(asynUser *pasynUser,
-                    epicsInt32 *plow, epicsInt32 *phigh);
-    asynStatus (*writeOnce)(const char *port, int addr,
-                    epicsInt32 value,double timeout, const char *drvInfo);
-    asynStatus (*readOnce)(const char *port, int addr,
-                    epicsInt32 *pvalue,double timeout, const char *drvInfo);
-    asynStatus (*getBoundsOnce)(const char *port, int addr,
-                    epicsInt32 *plow, epicsInt32 *phigh,const char *drvInfo);
-} asynInt32SyncIO;
-epicsShareExtern asynInt32SyncIO *pasynInt32SyncIO;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynInt32SyncIO
- connect - Connects to a port and address, returns a pointer to an asynUser.
- disconnect - Disconnect. This frees all resources allocated by connect.
- write - Calls pasynInt32->write and waits for the operation to complete or time out. -
- read - Calls pasynInt32->read and waits for the operation to complete or time out. -
- getBounds - Calls pasynInt32->getBounds and waits for the operation to complete or time out. -
- writeOnce - This does a connect, write, and disconnect.
- readOnce - This does a connect, read, and disconnect.
- getBoundsOnce - This does a connect, getBounds, and disconnect.
-

- asynUInt32Digital

-

- asynUInt32Digital describes the methods for communicating via bits of an Int32 register.

-
typedef enum {
-    interruptOnZeroToOne, interruptOnOneToZero, interruptOnBoth
-} interruptReason;
-
-typedef void (*interruptCallbackUInt32Digital)(void *userPvt, 
-                 asynUser *pasynUser, epicsUInt32 data);
-typedef struct asynUInt32DigitalInterrupt {
-    epicsUInt32 mask;
-    int addr;
-    asynUser *pasynUser;
-    interruptCallbackUInt32Digital callback;
-    void *userPvt;
-} asynUInt32DigitalInterrupt;
-#define asynUInt32DigitalType "asynUInt32Digital"
-typedef struct asynUInt32Digital {
-    asynStatus (*write)(void *drvPvt, asynUser *pasynUser,
-         epicsUInt32 value, epicsUInt32 mask);
-    asynStatus (*read)(void *drvPvt, asynUser *pasynUser,
-        epicsUInt32 *value, epicsUInt32 mask);
-    asynStatus (*setInterrupt)(void *drvPvt, asynUser *pasynUser,
-        epicsUInt32 mask, interruptReason reason);
-    asynStatus (*clearInterrupt)(void *drvPvt, asynUser *pasynUser,
-        epicsUInt32 mask);
-    asynStatus (*getInterrupt)(void *drvPvt, asynUser *pasynUser,
-        epicsUInt32 *mask, interruptReason reason);
-    asynStatus (*registerInterruptUser)(void *drvPvt, asynUser *pasynUser,
-        interruptCallbackUInt32Digital callback,void *userPvt,epicsUInt32 mask,
-        void **registrarPvt);
-    asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser,
-                    void *registrarPvt);
-} asynUInt32Digital;
-
-/* asynUInt32DigitalBase does the following:
-   calls  registerInterface for asynUInt32Digital.
-   Implements registerInterruptUser and cancelInterruptUser
-   Provides default implementations of all methods.
-   registerInterruptUser and cancelInterruptUser can be called
-   directly rather than via queueRequest.
-*/
-
-#define asynUInt32DigitalBaseType "asynUInt32DigitalBase"
-typedef struct asynUInt32DigitalBase {
-    asynStatus (*initialize)(const char *portName,
-                            asynInterface *pasynUInt32DigitalInterface);
-} asynUInt32DigitalBase;
-epicsShareExtern asynUInt32DigitalBase *pasynUInt32DigitalBase;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynUInt32Digital
- write - Modify the bits specified by mask with the corresponding bits in value.
- read - Read the bits specified by mask into value. The other bits of value will be set - to 0.
- setInterrupt - Set the bits specified by mask to interrupt for reason.
- clearInterrupt - Clear the interrupt bits specified by mask.
- getInterrupt - Set each bit of mask that is enabled for reason.
- registerInterruptUser - Register a callback that will be called whenever the driver detects a change in - any of the bits specified by mask. Since it can be called directly rather than via - a queueRequest this method must not block.
- cancelInterruptUser - Cancels the registered callback. Since it can be called directly rather than via - a queueRequest this method must not block.
-

-

-

- asynUInt32DigitalBase is an interface and associated code that is used by drivers - that implement interface asynUInt32Digital. asynUInt32DigitalBase provides code - to implement registerInterruptUser and cancelInterruptUser.

- - - - - - - - -
- asynUInt32DigitalBase
- initialize - After a driver calls registerPort it can call: -
pasynUInt32DigitalBase->initialize(...
- Any null methods in the asynInterface are replaced by default implementations. -
-

- The default implementation of each method does the following:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynUInt32Digital
- write - Reports an error "write is not supported" and returns asynError
- read - Reports an error "read is not supported" and returns asynError
- setInterrupt - Reports an error "setInterrupt is not supported" and returns asynError
- clearInterrupt - Reports an error "clearInterrupt is not supported" and returns asynError
- getInterrupt - Reports an error "getInterrupt is not supported" and returns asynError
- registerInterruptUser - registers the interrupt user. The low level driver must call the registered callbacks - via calls to asynManager:interruptStart and asynManager:interruptEnd.
- cancelInterruptUser - Cancels the callback
-

- asynUInt32DigitalSyncIO

-

- asynUInt32DigitalSyncIO describes a synchronous interrace to asynUInt32Digital. - The code that calls it must be willing to block.

-
#define asynUInt32DigitalSyncIOType "asynUInt32DigitalSyncIO"
-typedef struct asynUInt32DigitalSyncIO {
-    asynStatus (*connect)(const char *port, int addr,
-                       asynUser **ppasynUser, const char *drvInfo);
-    asynStatus (*disconnect)(asynUser *pasynUser);
-    asynStatus (*write)(asynUser *pasynUser,
-                       epicsUInt32 value,epicsUInt32 mask,double timeout);
-    asynStatus (*read)(asynUser *pasynUser,
-                       epicsUInt32 *pvalue,epicsUInt32 mask,double timeout);
-    asynStatus (*setInterrupt)(asynUser *pasynUser,
-                       epicsUInt32 mask, interruptReason reason,double timeout);
-    asynStatus (*clearInterrupt)(asynUser *pasynUser,
-                       epicsUInt32 mask,double timeout);
-    asynStatus (*getInterrupt)(asynUser *pasynUser,
-                       epicsUInt32 *mask, interruptReason reason,double timeout);
-    asynStatus (*writeOnce)(const char *port, int addr,
-                       epicsUInt32 value,epicsUInt32 mask,double timeout,
-                       const char *drvInfo);
-    asynStatus (*readOnce)(const char *port, int addr,
-                       epicsUInt32 *pvalue,epicsUInt32 mask,double timeout,
-                       const char *drvInfo);
-    asynStatus (*setInterruptOnce)(const char *port, int addr,
-                       epicsUInt32 mask, interruptReason reason,double timeout,
-                       const char *drvInfo);
-    asynStatus (*clearInterruptOnce)(const char *port, int addr,
-                       epicsUInt32 mask,double timeout,const char *drvInfo);
-    asynStatus (*getInterruptOnce)(const char *port, int addr,
-                       epicsUInt32 *mask, interruptReason reason,double timeout,
-                       const char *drvInfo);
-} asynUInt32DigitalSyncIO;
-epicsShareExtern asynUInt32DigitalSyncIO *pasynUInt32DigitalSyncIO;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynUInt32DigitalSyncIO
- connect - Connects to a port and address, returns a pointer to an asynUser structure.
- disconnect - Disconnect. This frees all resources allocated by connect.
- write - Calls pasynUInt32Digital->write and waits for the operation to complete or time - out.
- read - Calls pasynUInt32Digital->read and waits for the operation to complete or time - out.
- setInterrupt - Calls pasynUInt32Digital->setInterrupt and waits for the operation to complete - or time out.
- clearInterrupt - Calls pasynUInt32Digital->clearInterrupt and waits for the operation to complete - or time out.
- getInterrupt - Calls pasynUInt32Digital->getInterrupt and waits for the operation to complete - or time out.
- writeOnce,...,getInterruptOnce - Does a connect, (write,...,getInterrupt), and disconnect.
-

- asynFloat64

-

- asynFloat64 describes the methods for communicating via IEEE double precision float - values.

-
typedef void (*interruptCallbackFloat64)(void *userPvt, asynUser *pasynUser,
-            epicsFloat64 data);
-typedef struct asynFloat64Interrupt {
-    asynUser *pasynUser;
-    int addr;
-    interruptCallbackFloat64 callback;
-    void *userPvt;
-} asynFloat64Interrupt;
-#define asynFloat64Type "asynFloat64"
-typedef struct asynFloat64 {
-    asynStatus (*write)(void *drvPvt, asynUser *pasynUser, epicsFloat64 value);
-    asynStatus (*read)(void *drvPvt, asynUser *pasynUser, epicsFloat64 *value);
-    asynStatus (*registerInterruptUser)(void *drvPvt, asynUser *pasynUser,
-        interruptCallbackFloat64 callback, void *userPvt,void **registrarPvt);
-    asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser,
-                    void *registrarPvt);
-} asynFloat64;
-
-/* asynFloat64Base does the following:
-   calls  registerInterface for asynFloat64.
-   Implements registerInterruptUser and cancelInterruptUser
-   Provides default implementations of all methods.
-   registerInterruptUser and cancelInterruptUser can be called
-   directly rather than via queueRequest.
-*/
-
-#define asynFloat64BaseType "asynFloat64Base"
-typedef struct asynFloat64Base {
-    asynStatus (*initialize)(const char *portName,
-                            asynInterface *pasynFloat64Interface);
-} asynFloat64Base;
-epicsShareExtern asynFloat64Base *pasynFloat64Base;
- - - - - - - - - - - - - - - - - - - - -
- asynFloat64
- write - Write a value.
- read - Read a value.
- registerInterruptUser - Register a callback that is called whenever new data is available. Since it can - be called directly rather than via a queueRequest this method must not block. -
- cancelInterruptUser - Cancel the callback. Since it can be called directly rather than via a queueRequest - this method must not block.
- - - - - - - - -
- asynFloat64Base
- initialize - After a driver calls registerPort it can call: -
pasynFloat64Base->initialize(...
- Any null methods in the asynInterface are replaced by default implementations. -
-

- The default implementation of each method does the following:

- - - - - - - - - - - - - - - - - - - - -
- asynFloat64
- write - Reports an error "write is not supported" and returns asynError
- read - Reports an error "read is not supported" and returns asynError
- registerInterruptUser - registers the interrupt user. The low level driver must call the registered callbacks - via calls to asynManager:interruptStart and asynManager:interruptEnd.
- cancelInterruptUser - Cancels the callback
-

- asynFloat64SyncIO

-

- asynFloat64SyncIO describes a synchronous interrace to asynFloat64. The code that - calls it must be willing to block.

-
#define asynFloat64SyncIOType "asynFloat64SyncIO"
-typedef struct asynFloat64SyncIO {
-    asynStatus (*connect)(const char *port, int addr,
-                       asynUser **ppasynUser, const char *drvInfo);
-    asynStatus (*disconnect)(asynUser *pasynUser);
-    asynStatus (*write)(asynUser *pasynUser,epicsFloat64 value,double timeout);
-    asynStatus (*read)(asynUser *pasynUser,epicsFloat64 *pvalue,double timeout);
-    asynStatus (*writeOnce)(const char *port, int addr,
-                       epicsFloat64 value,double timeout,const char *drvInfo);
-    asynStatus (*readOnce)(const char *port, int addr,
-                       epicsFloat64 *pvalue,double timeout,const char *drvInfo);
-} asynFloat64SyncIO;
-epicsShareExtern asynFloat64SyncIO *pasynFloat64SyncIO;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynFloat64SyncIO
- connect - Connects to a port and address, returns a pointer to an asynUser structure.
- disconnect - Disconnect. This frees all resources allocated by connect.
- write - Calls pasynFloat64->write and waits for the operation to complete or time out. -
- read - Calls pasynFloat64->read and waits for the operation to complete or time out. -
- writeOnce - This does a connect, write, and disconnect.
- readOnce - This does a connect, read, and disconnect.
-

- asynXXXArray (XXX=Int8, Int16, Int32, Float32 or Float64)

-

- asynXXXArray describes the methods for communicating via 8, 16, or 32-bit integers, - or 32 or 64-bit IEEE float values.

-
typedef void (*interruptCallbackXXXArray)(
-              void *userPvt, asynUser *pasynUser,
-              epicsXXX *data, size_t nelements);
-typedef struct asynXXXArrayInterrupt {
-    asynUser *pasynUser;
-    int addr;
-    interruptCallbackXXXArray callback;
-    void *userPvt;
-} asynXXXArrayInterrupt;
-#define asynXXXArrayType "asynXXXArray"
-typedef struct asynXXXArray {
-    asynStatus (*write)(void *drvPvt, asynUser *pasynUser,
-                       epicsXXX *value, size_t nelements);
-    asynStatus (*read)(void *drvPvt, asynUser *pasynUser,
-                       epicsXXX *value, size_t nelements, size_t *nIn);
-    asynStatus (*registerInterruptUser)(void *drvPvt, asynUser *pasynUser,
-         interruptCallbackXXXArray callback,
-         void *userPvt,void **registrarPvt);
-    asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser,
-                    void *registrarPvt);
-} asynXXXArray;
-
-/* asynXXXArrayBase does the following:
-   calls  registerInterface for asynXXXArray.
-   Implements registerInterruptUser and cancelInterruptUser
-   Provides default implementations of all methods.
-   registerInterruptUser and cancelInterruptUser can be called
-   directly rather than via queueRequest.
-*/
-
-#define asynXXXArrayBaseType "asynXXXArrayBase"
-typedef struct asynXXXArrayBase {
-    asynStatus (*initialize)(const char *portName,
-                            asynInterface *pXXXArrayInterface);
-} asynXXXArrayBase;
-epicsShareExtern asynXXXArrayBase *pasynXXXArrayBase;
- - - - - - - - - - - - - - - - - - - - -
- asynXXXArray
- write - Write an array of values.
- read - Read an array of values.
- registerInterruptUser - Register a callback that is called whenever new data is available.
- cancelInterruptUser - Cancel the callback
-

-

- - - - - - - - -
- asynXXXArrayBase
- initialize - After a driver calls registerPort it can call: -
pasynXXXArrayBase->initialize(...
- Any null methods in the asynInterface are replaced by default implementations. -
-
-

-

-

- The default implementation of each method does the following:

- - - - - - - - - - - - - - - - - - - - -
- asynXXXArrayBase
- write - Reports an error "write is not supported" and returns asynError
- read - Reports an error "read is not supported" and returns asynError
- registerInterruptUser - Registers an interrupt callback.
- cancelInterruptUser - Cancels the callback
-

- asynXXXArraySyncIO

-

- asynXXXArraySyncIO describes a synchronous interface to asynXXXArray. The code that - calls it must be willing to block.

-
#define asynXXXArraySyncIOType "asynXXXArraySyncIO"
-typedef struct asynXXXArraySyncIO {
-    asynStatus (*connect)(const char *port, int addr,
-                          asynUser **ppasynUser, const char *drvInfo);
-    asynStatus (*disconnect)(asynUser *pasynUser);
-    asynStatus (*write)(asynUser *pasynUser, epicsXXX *pvalue,size_t nelem,double timeout);
-    asynStatus (*read)(asynUser *pasynUser, epicsXXX *pvalue,size_t nelem,size_t *nIn,double timeout);
-    asynStatus (*writeOnce)(const char *port, int addr,
-                    epicsXXX *pvalue,size_t nelem,double timeout, const char *drvInfo);
-    asynStatus (*readOnce)(const char *port, int addr,
-                    epicsXXX *pvalue,size_t nelem,size_t *nIn,double timeout, const char *drvInfo);
-} asynXXXArraySyncIO;
-epicsShareExtern asynXXXArraySyncIO *pasynXXXArraySyncIO;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynXXXArraySyncIO
- connect - Connects to a port and address, returns a pointer to an asynUser.
- disconnect - Disconnect. This frees all resources allocated by connect.
- write - Calls pasynXXXArray->write and waits for the operation to complete or time out. -
- read - Calls pasynXXXArray->read and waits for the operation to complete or time out. -
- writeOnce - This does a connect, write, and disconnect.
- readOnce - This does a connect, read, and disconnect.
- getBoundsOnce - This does a connect, getBounds, and disconnect.
-

- asynEnum

-

- asynEnum describes the methods implemented by drivers to define the enum strings, - values, and severities for a device. -

-

- This interface is typically used by drivers to set the enum strings and values for - EPICS bi, bo, mbbi, and mbbo records. The strings[] are used to define the ZNAM - and ONAM fields in bi and bo records, and the ZRST, ONST, ...FFST fields in mbbi - and mbbo records. The integer values[] are ignored for bi and bo records, since - these always have the values of 0 and 1 corresponding to the ZNAM and ONAM states. - The integer values[] are used to assign the ZRVL, ONVL, ... FFVL fields for mbbi - and mbbo records. The integer severities[] are used to set the ZSV and OSV fields - of bi and bo records, and the ZRSV, ONSV, ... FFSV fields of mbbi and mbbo records. - The nelements parameter in the write() and read() functions is used by the client - to specify the dimensions of the strings[], values[], and severities[] arrays. The - driver must not access these arrays beyond element nElements-1. The nIn parameter - in the read() is used by the driver to set the actual number of value enum strings, - values, and severities. There is no size limitation on nElements imposed by the - asynEnum interface. However, the bi and bo records limit nElements to 2, and mbbi - and mbbo records limit nElements to 16. There is no size limitation on the strings - imposed by the asynEnum interface. However, the string fields in the bi, bo, mbbo, - and mbbi records are currently limited to 26 characters.

-

- Clients must ensure that the char* pointers passed in strings[] in the read() function - are either set to NULL or have been allocated by malloc(). The driver read() function - must first call free() if a string pointer contains a non-NULL value. The driver - must then allocate the strings using malloc() before copying the current enum string - values to them.

-
typedef void (*interruptCallbackEnum)
-              void *userPvt, asynUser *pasynUser,
-              char *strings[], int values[], int severities[], size_t nelements);
-typedef struct asynEnumInterrupt {
-    asynUser *pasynUser;
-    int addr;
-    interruptCallbackEnum callback;
-    void *userPvt;
-} asynEnumInterrupt;
-#define asynEnumType "asynEnum"
-typedef struct asynEnum {
-    asynStatus (*write)(void *drvPvt, asynUser *pasynUser,
-                       char *strings[], int values[], int severities[], size_t nelements);
-    asynStatus (*read)(void *drvPvt, asynUser *pasynUser,
-                       char *strings[], int values[], int severities[], size_t nelements, size_t *nIn);
-    asynStatus (*registerInterruptUser)(void *drvPvt, asynUser *pasynUser,
-             interruptCallbackEnum callback, void *userPvt,
-             void **registrarPvt);
-    asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser,
-             void *registrarPvt);
-} asynEnum;
-
-/* asynEnumBase does the following:
-   calls registerInterface for asynEnum.
-   Implements registerInterruptUser and cancelInterruptUser
-   Provides default implementations of all methods.
-   registerInterruptUser and cancelInterruptUser can be called
-   directly rather than via queueRequest.
-*/
-
-#define asynEnumBaseType "asynEnumBase"
-typedef struct asynEnumBase {
-    asynStatus (*initialize)(const char *portName,
-                            asynInterface *pEnumInterface);
-} asynEnumBase;
-epicsShareExtern asynEnumBase *pasynEnumBase;
-
- - - - - - - - - - - - - - - - - - - - -
- asynEnum
- write - Writes the enum strings, enum values and enum severities to the driver.
- read - Reads the enum strings, enum values and enum severities to the driver.
- registerInterruptUser - Registers a callback that will be called whenever there are new enum strings, values - and severities. Since it can be called directly rather than via a queueRequest this - method must not block.
- cancelInterruptUser - Cancels the callback. Since it can be called directly rather than via a queueRequest - this method must not block.
-

-

-

- asynEnumBase is an interface and associated code that is used by drivers that implement - interface asynEnum. asynEnumBase provides code to handle registerInterruptUser/cancelInterruptUser. - The driver must itself call the callbacks via calls to asynManager:interruptStart - and asynManager:interruptEnd.

- - - - - - - - -
- asynEnumBase
- initialize - After a driver calls registerPort it can call: -
pasynEnumBase->initialize(...
- Any null methods in the asynInterface are replaced by default implementations. -
-

-

-

- The default implementation of each method does the following:

- - - - - - - - - - - - - - - - - - - - -
- asynEnum
- write - Reports an error "write is not supported" and returns asynError
- read - Reports an error "read is not supported" and returns asynError
- registerInterruptUser - registers an interrupt callback.
- cancelInterruptUser - Cancels the callback
-

- asynEnumSyncIO

-

- asynEnumSyncIO describes a synchronous interface to asynEnum. The code that calls - it must be willing to block.

-
#define asynEnumSyncIOType "asynEnumSyncIO"
-typedef struct asynEnumSyncIO {
-    asynStatus (*connect)(const char *port, int addr, 
-                          asynUser **ppasynUser, const char *drvInfo);
-    asynStatus (*disconnect)(asynUser *pasynUser);
-    asynStatus (*write)(asynUser *pasynUser, char *strings[], int values[], int severities[], 
-                       size_t nElements, double timeout);
-    asynStatus (*read)(asynUser *pasynUser, char *string[], int values[],  int severities[], 
-                       size_t nElements, size_t *nIn, double timeout);
-    asynStatus (*writeOnce)(const char *port, int addr, char *strings[], int values[],  int severities[], 
-                           size_t nElements, double timeout, const char *drvInfo);
-    asynStatus (*readOnce)(const char *port, int addr, char *strings[], int values[],  int severities[], 
-                           size_t nElements, size_t *nIn, double timeout, const char *drvInfo);
-} asynEnumSyncIO;
-epicsShareExtern asynEnumSyncIO *pasynEnumSyncIO;
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynEnumSyncIO
- connect - Connects to a port and address, returns a pointer to an asynUser.
- disconnect - Disconnect. This frees all resources allocated by connect.
- write - Calls pasynEnum->write and waits for the operation to complete or time out. -
- read - Calls pasynEnum->read and waits for the operation to complete or time out. -
- writeOnce - This does a connect, write, and disconnect.
- readOnce - This does a connect, read, and disconnect.
- getBoundsOnce - This does a connect, getBounds, and disconnect.
-

- asynGenericPointer

-

- asynGenericPointer describes the methods for communicating via void* pointers. asyn - clients and port drivers must agree on the type of object that is being pointed - to!

-
typedef void (*interruptCallbackGenericPointer)(void *userPvt, asynUser *pasynUser,
-            void *pdata);
-typedef struct asynGenericPointerInterrupt {
-    asynUser *pasynUser;
-    int addr;
-    interruptCallbackGenericPointer callback;
-    void *userPvt;
-} asynGenericPointerInterrupt;
-#define asynGenericPointerType "asynGenericPointer"
-typedef struct asynGenericPointer {
-    asynStatus (*write)(void *drvPvt, asynUser *pasynUser, void *pvalue);
-    asynStatus (*read)(void *drvPvt, asynUser *pasynUser, void *pvalue);
-    asynStatus (*registerInterruptUser)(void *drvPvt, asynUser *pasynUser,
-        interruptCallbackGenericPointer callback, void *userPvt,void **registrarPvt);
-    asynStatus (*cancelInterruptUser)(void *drvPvt, asynUser *pasynUser,
-                    void *registrarPvt);
-} asynGenericPointer;
-
-/* asynGenericPointerBase does the following:
-   calls  registerInterface for asynGenericPointer.
-   Implements registerInterruptUser and cancelInterruptUser
-   Provides default implementations of all methods.
-   registerInterruptUser and cancelInterruptUser can be called
-   directly rather than via queueRequest.
-*/
-
-#define asynGenericPointerBaseType "asynGenericPointerBase"
-typedef struct asynGenericPointerBase {
-    asynStatus (*initialize)(const char *portName,
-                            asynInterface *pasynGenericPointerInterface);
-} asynGenericPointerBase;
-epicsShareExtern asynGenericPointerBase *pasynGenericPointerBase;
- - - - - - - - - - - - - - - - - - - - -
- asynGenericPointer
- write - Write a value.
- read - Read a value.
- registerInterruptUser - Register a callback that is called whenever new data is available. Since it can - be called directly rather than via a queueRequest this method must not block. -
- cancelInterruptUser - Cancel the callback. Since it can be called directly rather than via a queueRequest - this method must not block.
-

-

- - - - - - - - -
- asynGenericPointerBase
- initialize - After a driver calls registerPort it can call: -
pasynGenericPointerBase->initialize(...
- Any null methods in the asynInterface are replaced by default implementations. -
-

- The default implementation of each method does the following:

- - - - - - - - - - - - - - - - - - - - -
- asynGenericPointer
- write - Reports an error "write is not supported" and returns asynError
- read - Reports an error "read is not supported" and returns asynError
- registerInterruptUser - registers the interrupt user. The low level driver must call the registered callbacks - via calls to asynManager:interruptStart and asynManager:interruptEnd.
- cancelInterruptUser - Cancels the callback
-

- asynGenericPointerSyncIO

-

- asynGenericPointerSyncIO describes a synchronous interrace to asynGenericPointer. - The code that calls it must be willing to block.

-
#define asynGenericPointerSyncIOType "asynGenericPointerSyncIO"
-typedef struct asynGenericPointerSyncIO {
-    asynStatus (*connect)(const char *port, int addr,
-                       asynUser **ppasynUser, const char *drvInfo);
-    asynStatus (*disconnect)(asynUser *pasynUser);
-    asynStatus (*write)(asynUser *pasynUser,void *pvalue,double timeout);
-    asynStatus (*read)(asynUser *pasynUser,void *pvalue,double timeout);
-    asynStatus (*writeRead)(asynUser *pasynUser,void *pwrite_buffer,void *pread_buffer,double timeout);
-    asynStatus (*writeOnce)(const char *port, int addr,
-                       void *pvalue,double timeout,const char *drvInfo);
-    asynStatus (*readOnce)(const char *port, int addr,
-                       void *pvalue,double timeout,const char *drvInfo);
-    asynStatus (*writeReadOnce)(const char *port, int addr,
-                       void *pwrite_buffer,void *pread_buffer,double timeout,const char *drvInfo);
-} asynGenericPointerSyncIO;
-epicsShareExtern asynGenericPointerSyncIO *pasynGenericPointerSyncIO;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynGenericPointerSyncIO
- connect - Connects to a port and address, returns a pointer to an asynUser structure.
- disconnect - Disconnect. This frees all resources allocated by connect.
- write - Calls pasynGenericPointer->write and waits for the operation to complete or time - out.
- read - Calls pasynGenericPointer->read and waits for the operation to complete or time - out.
- writeRead - Calls pasynGenericPointer->write, then pasynGenericPointer->read. Waits for - the operations to complete or time out.
- writeOnce - This does a connect, write, and disconnect.
- readOnce - This does a connect, read, and disconnect.
- writeReadOnce - This does a connect, writeRead, and disconnect.
-

- asynStandardInterfacesBase

-

- asynStandardInterfacesBase is an interface designed as a convenience to minimize - the amount of code that must be written in the initialization routine of a port - driver that uses the standard asyn message-based or register-based interfaces that - are described above. Without asynStandardInterfacesBase a port driver needs to call - asynRegisterInterface(), and possibly asynRegisterInterruptSource() for each interface - that it supports, and handle any errors that may occur in these calls. It also needs - to explicitly include several fields in its drvPvt structure for each interface. - asynStandardInterfacesBase provides an interface that allows port drivers to include - a single structure in its drvPvt structure, and define values in this structure. - It then calls a single function to register all interfaces that it supports, and - to register itself as an interrupt source on one or more of those interfaces. This - can reduce the number of lines of code in the driver initialization routine by a - factor of four or more.

-

- asynStandardInterfaces structure

-

- The following is the definition of the asynStandardInterfaces structure. Drivers - will normally have a structure of this type contained in their drvPvt structure. - If this structure is initialized to all zeros when drvPvt is created, then all that - is necessary is to fill in the addresses of each of each of the supported interfaces - (in that interface's .pinterface field), and to set the CanInterrupt flag to 1 for - those interfaces that are interrupt sources.

-
typedef struct asynStandardInterfaces {
-    asynInterface common;
-
-    asynInterface drvUser;
-
-    asynInterface option;
-
-    asynInterface octet;
-    int octetProcessEosIn;
-    int octetProcessEosOut;
-    int octetInterruptProcess;
-    int octetCanInterrupt;
-    void *octetInterruptPvt;
-
-    asynInterface uInt32Digital;
-    int uInt32DigitalCanInterrupt;
-    void *uInt32DigitalInterruptPvt;
-
-    asynInterface int32;
-    int int32CanInterrupt;
-    void *int32InterruptPvt;
-
-    asynInterface float64;
-    int float64CanInterrupt;
-    void *float64InterruptPvt;
-
-    asynInterface int8Array;
-    int int8ArrayCanInterrupt;
-    void *int8ArrayInterruptPvt;
-
-    asynInterface int16Array;
-    int int16ArrayCanInterrupt;
-    void *int16ArrayInterruptPvt;
-
-    asynInterface int32Array;
-    int int32ArrayCanInterrupt;
-    void *int32ArrayInterruptPvt;
-
-    asynInterface float32Array;
-    int float32ArrayCanInterrupt;
-    void *float32ArrayInterruptPvt;
-
-    asynInterface float64Array;
-    int float64ArrayCanInterrupt;
-    void *float64ArrayInterruptPvt;
-
-    asynInterface genericPointer;
-    int genericPointerCanInterrupt;
-    void *genericPointerInterruptPvt;
-
-    asynInterface Enum;
-    int enumCanInterrupt;
-    void *enumInterruptPvt;
-
-} asynStandardInterfaces;
-

- asynStandardInterfacesBase interface

-

- The following is the definition of the asynStandardInterfacesBase interface.

-
typedef struct asynStandardInterfacesBase {
-    asynStatus (*initialize)(const char *portName, asynStandardInterfaces *pInterfaces, 
-                             asynUser *pasynUser, void *pPvt);
-} asynStandardInterfacesBase;
-
-epicsShareExtern asynStandardInterfacesBase *pasynStandardInterfacesBase;
-

- asynStandardInterfacesBase has a single method, initialize(), which calls registerInterface - or Base->initialize for each interface which has a non-NULL value in its .pinterface - field. It also calls registerInterruptSource for interfaces that are defined and - that have the CanInterrupt flag set to 1. The pasynUser argument to the initialize() - method is used only to provide a place for the method to return an error message - (in pasynUser->errorMessage) so the invoking routine may reuse or free the asynUser - structure when the method has returned.

-

- The following is an example of the code required in a port driver that uses the - asynStandardInterfacesBase interface.

-
#include <asynStandardInterfaces.h>
-...
-typedef struct drvADPvt {
-...
-    /* The asyn interfaces this driver implements */
-    asynStandardInterfaces asynStdInterfaces;
-
-    /* asynUser connected to ourselves for asynTrace */
-    asynUser *pasynUser;
-...
-} drvADPvt;
-...
-/* Structures with function pointers for each of the asyn interfaces */
-static asynCommon ifaceCommon = {
-    report,
-    connect,
-    disconnect
-};
-
-static asynInt32 ifaceInt32 = {
-    writeInt32,
-    readInt32,
-    getBounds
-};
-
-static asynFloat64 ifaceFloat64 = {
-    writeFloat64,
-    readFloat64
-};
-
-static asynOctet ifaceOctet = {
-    writeOctet,
-    NULL,
-    readOctet,
-};
-
-static asynDrvUser ifaceDrvUser = {
-    drvUserCreate,
-    drvUserGetType,
-    drvUserDestroy
-};
-
-static asynGenericPointer ifaceGenericPointer = {
-    writeADImage,
-    readADImage
-};
-...
-
-int simDetectorConfig(const char *portName, int maxSizeX, int maxSizeY, int dataType)
-
-{
-    drvADPvt *pPvt;
-    int status = asynSuccess;
-    char *functionName = "simDetectorConfig";
-    asynStandardInterfaces *pInterfaces;
-
-    pPvt = callocMustSucceed(1, sizeof(*pPvt), functionName);
-    pPvt->portName = epicsStrDup(portName);
-
-    status = pasynManager->registerPort(portName,
-                                        ASYN_MULTIDEVICE | ASYN_CANBLOCK,
-                                        1,  /*  autoconnect */
-                                        0,  /* medium priority */
-                                        0); /* default stack size */
-    if (status != asynSuccess) {
-        printf("%s ERROR: Can't register port\n", functionName);
-        return(asynError);
-    }
-
-    /* Create asynUser for debugging */
-    pPvt->pasynUser = pasynManager->createAsynUser(0, 0);
-
-    pInterfaces = &pPvt->asynStdInterfaces;
-    
-    /* Initialize interface pointers */
-    pInterfaces->common.pinterface         = (void *)&ifaceCommon;
-    pInterfaces->drvUser.pinterface        = (void *)&ifaceDrvUser;
-    pInterfaces->octet.pinterface          = (void *)&ifaceOctet;
-    pInterfaces->int32.pinterface          = (void *)&ifaceInt32;
-    pInterfaces->float64.pinterface        = (void *)&ifaceFloat64;
-    pInterfaces->genericPointer.pinterface = (void *)&ifaceGenericPointer;
-
-    /* Define which interfaces can generate interrupts */
-    pInterfaces->octetCanInterrupt          = 1;
-    pInterfaces->int32CanInterrupt          = 1;
-    pInterfaces->float64CanInterrupt        = 1;
-    pInterfaces->genericPointerCanInterrupt = 1;
-
-    status = pasynStandardInterfacesBase->initialize(portName, pInterfaces,
-                                                     pPvt->pasynUser, pPvt);
-    if (status != asynSuccess) {
-        printf("%s ERROR: Can't register interfaces: %s.\n",
-               functionName, pPvt->pasynUser->errorMessage);
-        return(asynError);
-    }
-...
-}
-

- Standard Interpose Interfaces

-

- asynInterposeEos

-

- This can be used to simulate EOS processing for asynOctet if the port driver doesn't - provide EOS support. If an EOS is specified it looks for the eos on each read. It - is started by the shell command:

-
    asynInterposeEosConfig port addr processEosIn processEosOut
-

- where

-
    -
  • port is the name of the port.
  • -
  • addr is the address
  • -
  • processEosIn (0,1) means (do not, do) implement eosIn commands.
  • -
  • processEosOut (0,1) means (do not, do) implement eosOut commands.
  • -
-

- This command should appear immediately after the command that initializes a port. - Some drivers provide configuration options to call this automatically.

-

- asynInterposeFlush

-

- This can be used to simulate flush processing for asynOctet if the port driver doesn't - provide support for flush. It just reads and discards characters until no more characters - arive before timeout seconds have occured. It is started by the shell command:

-
    asynInterposeFlushConfig port addr timeout
-

- where

-
    -
  • port is the name of the port.
  • -
  • addr is the address
  • -
  • timeout is the time to wait for more characters
  • -
-

- This command should appear immediately after the command that initializes a port.

-

- asynInterposeCom

-

- This provides the ability to configure serial ports on terminal servers using the - RFC 2117 protocol. It is not configured from the iocsh directly, but is rather configured - automatically by the drvAsynIPPort driver if the COM protocol is specified. It supports - the same options as drvAsynSerialPort, i.e. "baud", "bits", "parity", "stop", "crtscts", - and "ixon". -

-

- asynInterposeDelay

-

- This can be used to wait for a specified delay after sending each character before - sending the next. Some poorly designed devices require this. It is started by the - shell command:

-
    asynInterposeDelay port addr delay
-

- where

-
    -
  • port is the name of the port.
  • -
  • addr is the address
  • -
  • delay is the time to wait after sending each character
  • -
-

- This command should appear immediately after the command that initializes a port. - At run-time the delay can be examined or changed using the asyn option interface - with the `delay` option which is added by this interpose layer.

-
    asynShowOption port, address, "delay"
-   asynSetOption port, address, "delay", delay(sec)
-
-

- asynInterposeEcho

-

- This can be used to wait for each character to be echoed by the device before sending - the next character. Some poorly designed devices require this. It is started by - the shell command:

-
    asynInterposeEcho port addr
-

- where

-
    -
  • port is the name of the port.
  • -
  • addr is the address
  • -
-

- This command should appear immediately after the command that initializes a port.

-
-

- Generic Device Support for EPICS records

-

- Generic device support is provided for standard EPICS records. This support should - be usable for a large class of low level register based drivers. For complicated - devices other support is required. This release provides the following:

-
    -
  • devAsynInt32 - support for drivers that implement interface asynInt32
  • -
  • devAsynInt32TimeSeries - waveform record support for drivers that implement callbacks - on interface asynInt32
  • -
  • devAsynInt8Array - support for drivers that implement interface asynInt8Array
  • -
  • devAsynInt16Array - support for drivers that implement interface asynInt16Array
  • -
  • devAsynInt32Array - support for drivers that implement interface asynInt32Array
  • -
  • devAsynUInt32Digital - support for drivers that implement interface asynUInt32Digital
  • -
  • devAsynFloat64 - support for drivers that implement interface asynFloat64
  • -
  • devAsynFloat64TimeSeries - waveform record support for drivers that implement - callbacks on interface asynFloat64
  • -
  • devAsynFloat32Array - support for drivers that implement interface asynFloat32Array
  • -
  • devAsynFloat64Array - support for drivers that implement interface asynFloat64Array
  • -
  • devAsynOctet - support for drivers that implement interface asynOctet
  • -
  • devEpics - This is just a single file devEpics.dbd that includes the dbd files - for the above support.
  • -
  • asynEpicsUtils.c - This provides utility functions. parseLink(), parseLinkMask() - and parseLinkFree() parse record the record INP and OUT links described below. asynStatusToEpicsAlarm() - converts asynStatus enum values to EPICS record STAT and SEVR values setting record - alarms.
  • -
-

- The support uses the following conventions for DTYP and INP. OUT fields are the - same as INP.

-
    field(DTYP,"asynXXX")
-    field(INP,"@asyn(portName,addr,timeout)drvParams")
-     or
-    field(INP,"@asynMask(portName,addr,mask,timeout)drvParams")
-
where
-
    -
  • XXX - The name of the type of interface supported.
  • -
  • portName - The name of the port.
  • -
  • addr - The address. If addr is not specified the default is 0.
  • -
  • mask - This is for devAsynUInt32Digital. It is also used by devAsynInt32 to specify - the number of bits of the hardware device for drivers that do not support getBounds().
  • -
  • timeout - The timeout value for asynUser.timeout. If not specified the default - is 1.0.
  • -
  • drvParams - This is passed to the low level driver via the asynDrvUser interface. - It is optional.
  • -
-

- For example:

-
    field(DTYP,"asynInt32")
-    field(INP,"@asyn(portA,0,.1)thisIsForDriver")
-

- asynManager interrupts and EPICS device support

-

- All of the device support files can call registerInterruptUser for input records. - The callback is used in one of two ways:

-
    -
  • Input Records except Average and TimeSeries -

    - It is used to support SCAN = "I/O Intr".

    -
  • -
  • Input records that are averaged, i.e. asynInt32Average or asynFloat64Average. -

    - These records can be scanned either periodically or with SCAN=I/O Intr. The registerInterruptUser - callback is used to add the current value to the sum of values between record processing.

    -

    - If the record is periodically processed, then the average is computed each time - the record processes. If the record is processed before new data have arrived (numAverage==0) - the record is set to UDF/INVALID, UDF is set to TRUE, and the value is left unchanged.

    -

    - If the record has SCAN=I/O Intr then the average is computed and the record is processed - each time 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. This means that simulation mode cannot be used with asynInt32Average - or asynFloat64Average device support if SCAN=I/O Intr. This is probably not a significant - limitation. Support for SCAN=I/O Intr was added in R4-34.

    -
  • -
  • Input records that are waveform time series, i.e. asynInt32TimeSeries or asynFloat64TimeSeries. -

    - These records are normally scanned periodically. The registerInterruptUser callback - is used to append values to the time series.

    -
  • -
-

- Initial values of output records

-

- The device support for output records on register based interfaces (bo, mbbo, ao, - longout) does an initial read() of the value from the driver in init_record. If - this read() returns asynSuccess then the record value is set to the value returned - from read(). If read() returns anything other than asynSuccess then the record value - is not modified. This mechanism supports "bumpless reboots" where the initial value - of output records will match the current value of the hardware when the IOC starts. - Drivers should only return asynSuccess from the read() function if the value is - known to be valid. Note that this value read from the device will replace the value - in the database when iocInit begins. However, the value read from the device may - in turn be replaced by any value from save/restore, because the auto restore happens - later in iocInit.

-

- Beginning in R4-30 devAsynOctet was changed to also support the initial readback - for stringout and waveform output records. The initial readback is only done if - the record in the database contains the following line:
- info(asyn:INITIAL_READBACK, "1")
- .

-

- Enum values for bi, bo, mbbi, and mbbo records

-

- Beginning in asyn R4-19 support was added for asyn port drivers to control the values - of the enum strings, enum values and enum severities in bi, bo, mbbi, and mbbo records. - This is implemented in the asynInt32 and asynUInt32Digital device support as follows:

-
    -
  • In the device support init_record function the device support attempts to find - the asynEnum interface in the driver. If it is found then the driver calls pasynEnumSyncIO->read() - to read the current values of the enums from the driver. If the read() returns asynSuccess - then the enum fields are set to the values returned by the driver. If the asynEnum - interface is not supported, or if read() returns anything except asynSuccess then - the enum fields are not modified.
  • -
  • Device support registers for callbacks on the asynEnum interface. Drivers can - make callbacks to dynamically change the values of enums at run-time. For example, - changing the gain of an ADC might change the allowed choices for the speed, etc. - Device support calls db_post_events(pr, &pr->val, DBE_PROPERTY) when the - enum fields change. This notifies clients that the enum values have changed. Older - clients like medm and edm will not change the enum widgets until the window is closed - and reopened, but newer clients like CSS should dynamically change the enum widgets.
  • -
-

- Callback updates for output records

-

- Beginning in asyn R4-26 support was added for updating output records from driver - interrupt callbacks. This feature allows output records to reflect changes in the - underlying hardware that are caused by manual front-panel operation, changes caused - by another output record, etc. -

-

- By default output records do not update when a driver does interrupt callbacks. - However, if the following info tag is added for a record in the database file then - callbacks will be enabled and the output record will be updated whenever the driver - does a callback for that value.
- info(asyn:READBACK, "1")
- If the value of the info tag is 0 or if the info tag is not present then updates - of output records on interrupt callbacks are disabled. -

-

- Buffering of driver callbacks

-

- It is possible for the time between driver callbacks to be less than the time for - record processing. asyn device support provides a ring-buffer (FIFO) mechanism to - buffer values so that the record will process all callback values from a short burst - of callbacks. For all records except stringin, stringout, and waveform records the - default buffer size is 10 values. For stringin, stringout, and waveform records - the default buffer size is 0, i.e. there is no buffering. For all record types the - size of the buffer can be controlled by the following info tag for a record in the - database file: -
- info(asyn:FIFO, "20")
- In this example the buffer size was set to 20. Ring buffer support was added in - asyn R4-10 for all records except stringin, stringout, and waveform. Waveform record - support for numeric arrays was added in asyn R4-25. asynOctet support for stringin, - stringout, and waveform records was added in asyn R4-26. In R4-35 a deadlock issue - with asyn:READBACK was found. To fix this with asynOctet output records a ring buffer - is required. Thus, a minimum ring buffer size of 1 is enforced in the driver for - these records if asyn:REABACK=1 even if asyn:FIFO is not specified. asyn:FIFO can - still be used to select a larger ring buffer size. -

-

- Time stamps -

-

- Beginning in asyn R4-20 support was added for asyn port drivers to set the TIME - field of input records. This is done by setting the TSE field of the record to "-2" - and setting the desired value into the timestamp field of the pasynUser structure - referred to in the device read method or interrupt callback. -

-

- Beginning in asyn R4-22 the timestamp support functions were added to asynManager - to update, get and set the most recent timestamp for the port in asynManager. Support - was also added for user-supplied timestamp source functions. Timestamp support was - also added to asynPortDriver for the base-class read functions and callback functions. -

-

- asynInt32 device support

-

- The following support is available:

-
device(ai,INST_IO,asynAiInt32,"asynInt32")
-device(ai,INST_IO,asynAiInt32Average,"asynInt32Average")
-device(ao,INST_IO,asynAoInt32,"asynInt32")
-device(bi,INST_IO,asynBiInt32,"asynInt32")
-device(bo,INST_IO,asynBoInt32,"asynInt32")
-device(mbbi,INST_IO,asynMbbiInt32,"asynInt32")
-device(mbbo,INST_IO,asynMbboInt32,"asynInt32")
-device(longin,INST_IO,asynLiInt32,"asynInt32")
-device(longout,INST_IO,asynLoInt32,"asynInt32")
-

- devAsynInt32.c provides EPICS device support for drivers that implement interface - asynInt32.

-

- For ai and ao records either of the following specifications for the INP and OUT - fields can be used:

-
    
-    field(INP,"@asyn(portName,addr,timeout) drvParams")
-     or
-    field(INP,"@asynMask(portName,addr,nbits,timeout) drvParams")
-

- The asynMask format allows device support to work with drivers that cannot return - meaningful values from 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.  Values will be masked to the specified number of bits.
-
-nbits < 0 Device is bipolar with a range from -2^(abs(nbits)-1) to 2^((abs(nbits)-1)-1 - Values read with the asynInt32 interface will be sign extended - using the sign bit (e.g. bit abs(nbits)-1 starting at bit 0).
-
    -
  • aiRecord -

    - A value is given to rval. Linear conversions are supported if the driver implements - getBounds, or if nbits is specified as explained above.

    -
      -
    • asynInt32 - SCAN "I/O Intr" is supported. If the record is "I/O Intr" scanned - then when the registerInterruptUser callback is called, it saves the value and calls - scanIoRequest. When the record is processed the saved value is put into rval. If - the record is not "I/O Intr" scanned then each time the record is processed, a new - value is read via a call to pasynInt32->read.
    • -
    • asynInt32Average - The registerInterruptUser callback adds the new value to a - sum and also increments the number of samples. When the record is processed the - average is computed and the sum and number of samples is set to zero. If the record - is processed before new data have arrived (numAverage==0) the record is set to UDF/INVALID, - UDF is set to TRUE, and the value is left unchanged. The record can be scanned either - periodically or with SCAN=I/O Intr. If the record has SCAN=I/O Intr then the average - is computed and the record is processed each time NumAverage callback readings have - been received. The SVAL field in the ai record is used to set NumAverage.
    • -
    -
  • -
  • aoRecord -

    - rval is written. Linear conversions are supported if the driver properly implements - getBounds, or if nbits is specified as explained above.

    -
  • -
  • longinRecord -

    - A value is given to val. Each time the record is processed a new value is read. - SCAN "I/O Intr" is supported similar to aiRecord.

    -
  • -
  • longoutRecord -

    - val is written.

    -
  • -
  • biRecord -

    - A value is given to rval. The mask field in the record is not used. Each time the - record is processed a new value is read. SCAN "I/O Intr" is supported similar to - aiRecord.

    -
  • -
  • boRecord -

    - rval is written. The mask field in the record is not used.

    -
  • -
  • mbbiRecord -

    - A value is given to rval. mask is computed from nobt and shft. Each time the record - is processed a new value is read. SCAN "I/O Intr" is supported similar to aiRecord.

    -
  • -
  • mbboRecord -

    - rval is written. mask is computed from nobt and shft.

    -
  • -
-

- Analog Input Example Records

-
   record(ai,"aiInt32") {
-        field(SCAN,"I/O Intr")
-        field(DTYP,"asynInt32")
-        field(INP,"@asyn($(port),$(addr))")
-        field(EGUF,"10.0")
-        field(EGUL,"-10.0")
-        field(PREC,"3")
-   }
-   # This record is for a 12-bit bipolar ADC for a driver that does not
-   # support getBounds()
-   record(ai,"aiInt32") {
-        field(SCAN,"I/O Intr")
-        field(DTYP,"asynInt32")
-        field(INP,"@asynMask($(port),$(addr),-12)")
-        field(EGUF,"10.0")
-        field(EGUL,"-10.0")
-        field(PREC,"3")
-   }
-   record(ai,"aiInt32Average") {
-        field(SCAN,"10 second")
-        field(DTYP,"asynInt32Average")
-        field(INP,"@asyn($(port),$(addr))")
-        field(EGUF,"10.0")
-        field(EGUL,"-10.0")
-        field(PREC,"3")
-   }
-

- Analog Output Example Record

-
   record(ao,"aoInt32") {
-        field(DTYP,"asynInt32")
-        field(OUT,"@asyn($(port),$(addr))")
-        field(EGUF,"10.0")
-        field(EGUL,"-10.0")
-        field(PREC,"3")
-   }
-

- Long Input Example Records

-
   record(longin,"liInt32") {
-        field(SCAN,"I/O Intr")
-        field(DTYP,"asynInt32")
-        field(INP,"@asyn($(port),$(addr))")
-   }
-

- Long Output Example Record

-
   record(longout,"loInt32") {
-        field(DTYP,"asynInt32")
-        field(OUT,"@asyn($(port),$(addr))")
-   }
-

- Multibit Binary Input Example Records

-
   record(mbbi,"mbbiInt32") {
-        field(SCAN,"I/O Intr")
-        field(DTYP,"asynInt32")
-        field(INP,"@asyn($(port),$(addr))")
-        field(NOBT,"2")
-        field(SHFT,"2")
-        field(ZRST,"zeroVal")
-        field(ONST,"oneVal")
-        field(TWST,"twoVal")
-        field(THST,"threeVal")
-   }
-

- Multibit Binary Output Example Record

-
   record(mbbo,"mbboInt32") {
-        field(DTYP,"asynInt32")
-        field(OUT,"@asyn($(port),$(addr))")
-        field(NOBT,"2")
-        field(SHFT,"16")
-        field(ZRST,"zeroVal")
-        field(ONST,"oneVal")
-        field(TWST,"twoVal")
-        field(THST,"threeVal")
-   }
-

- asynIntXXXArray device support (XXX=8, 16 or 32)

-

- The following support is available:

-
device(waveform,INST_IO,asynIntXXXArrayWfIn,"asynIntXXXArrayIn")
-device(waveform,INST_IO,asynIntXXXArrayWfOut,"asynIntXXXArrayOut")
-

- devAsynIntXXXArray.c provides EPICS device support for drivers that implement interface - asynIntXXXArray. It has support for both reading and writing a waveform. SCAN "I/O - Intr" is supported similar to the aiRecord in devAsynInt32 device support.

-

- asynXXXTimeSeries device support (XXX=Int32 or Float64)

-

- The following support is available:

-
device(waveform,INST_IO,asynInt32TimeSeries,"asynInt32TimeSeries")
-device(waveform,INST_IO,asynFloat64TimeSeries,"asynFloat64TimSeries")
-

- devAsynXXXTimeSeries.c provides EPICS device support to collect a time series of - values into a waveform record. It works with drivers that implement callbacks on - the asynInt32 or asynFloat64 interfaces. This permits more rapid and efficient acquisition - of values from a driver than can be obtained using record support and database operations. - The waveform record RARM field is used to control acquisition as follows:

-
    -
  • RARM=1 Erase and start acquisition, i.e. clear the waveform record to 0, set NORD=0, - BUSY=1 and enable callbacks.
  • -
  • RARM=2 Stop acquisition, set BUSY=0.
  • -
  • RARM=3 Start acquisition (set BUSY=1) without clearing the waveform or setting - NORD=0.
  • -
-

- asynUInt32Digital device support

-

- The following support is available:

-
device(bi,INST_IO,asynBiUInt32Digital,"asynUInt32Digital")
-device(bo,INST_IO,asynBoUInt32Digital,"asynUInt32Digital")
-device(longin,INST_IO,asynLiUInt32Digital,"asynUInt32Digital")
-device(longout,INST_IO,asynLoUInt32Digital,"asynUInt32Digital")
-device(mbbi,INST_IO,asynMbbiUInt32Digital,"asynUInt32Digital")
-device(mbbo,INST_IO,asynMbboUInt32Digital,"asynUInt32Digital")
-device(mbbiDirect,INST_IO,asynMbbiDirectUInt32Digital,"asynUInt32Digital")
-device(mbboDirect,INST_IO,asynMbboDirectUInt32Digital,"asynUInt32Digital")
-

- devAsynUInt32Digital.c provides EPICS device support for drivers that implement - interface asynUInt32Digital. The INP or OUT field must define asynMask. The mask - specified in the argument to asynMask is used in the calls to asynUInt32Digital - methods. In addition it is used to set the mask fields in bi and bo records and - the mask and shft fields in mbbi, mbbo, mbbiDirect, and mbboDirect records.

-
    -
  • biRecord -

    - A value is given to rval. asynInt32 - SCAN "I/O Intr" is supported. If the record - is "I/O Intr" scanned then when the registerInterruptUser callback is called, it - saves the value and calls scanIoRequest. When the record is processed the saved - value is put into rval. If the record is not "I/O Intr" scanned then each time the - record is processed, a new value is read via a call to pasynUInt32Digital->read.

    -
  • -
-
    -
  • boRecord -

    - rval is written.

    -
  • -
  • longinRecord -

    - A value is given to val. Each time the record is processed a new value is read. - SCAN "I/O Intr" is supported similar to aiRecord.

    -
  • -
-
    -
  • longoutRecord -

    - val is written.

    -
  • -
  • mbbiRecord -

    - A value is given to rval. Each time the record is processed a new value is read. - SCAN "I/O Intr" is supported similar to aiRecord.

    -
  • -
  • mbboRecord -

    - rval is written.

    -
  • -
  • mbbiDirectRecord -

    - A value is given to rval. Each time the record is processed a new value is read. - SCAN "I/O Intr" is supported similar to aiRecord.

    -
  • -
  • mbboDirectRecord -

    - rval is written.

    -
  • -
-

- Binary Input Example Record

-
record(bi,"biUInt32Bit0") {
-    field(SCAN,"I/O Intr")
-    field(DTYP,"asynUInt32Digital")
-    field(INP,"@asynMask( $(port) , 0, 0x1 , 1.0) ")
-    field(ZNAM,"zero")
-    field(ONAM,"one")
-}
-

- Binary Output Example Record

-
record(bo,"boUInt32Bit2") {
-    field(DTYP,"asynUInt32Digital")
-    field(OUT,"@asynMask( $(port) , 0, 0x4 , 1.0) ")
-    field(ZNAM,"zero")
-    field(ONAM,"one")
-}
-

- Long Input Example Record

-
record(longin,"liUInt32") {
-    field(SCAN,"I/O Intr")
-    field(DTYP,"asynUInt32Digital")
-    field(INP,"@asynMask( $(port) , 0, 0xffffffff , 1.0) ")
-}
-

- Long Output Example Record

-
record(longout,"loUInt32") {
-    field(DTYP,"asynUInt32Digital")
-    field(OUT,"@asynMask( $(port) , 0, 0xffffffff , 1.0) ")
-}
-

- Multibit Input Example Record

-
record(mbbi,"mbbiUInt32") {
-    field(SCAN,"I/O Intr")
-    field(DTYP,"asynUInt32Digital")
-    field(INP,"@asynMask( digital , 0, 0x3 , 1.0) ")
-    field(ZRST,"zero")
-    field(ONST,"one")
-    field(TWST,"two")
-    field(THST,"three")
-    field(ZRVL,"0x0")
-    field(ONVL,"0x1")
-    field(TWVL,"0x2")
-    field(THVL,"0x3")
-}
-

- Multibit Output Example Record

-
record(mbbo,"mbboUInt32") {
-    field(DTYP,"asynUInt32Digital")
-    field(OUT,"@asynMask( digital , 0, 0x7 , 1.0) ")
-    field(ZRST,"zero")
-    field(ONST,"one")
-    field(TWST,"two")
-    field(THST,"three")
-    field(FRST,"four")
-    field(FVST,"five")
-    field(SXST,"six")
-    field(SVST,"seven")
-    field(ZRVL,"0x0")
-    field(ONVL,"0x1")
-    field(TWVL,"0x2")
-    field(THVL,"0x3")
-    field(FRVL,"0x4")
-    field(FVVL,"0x5")
-    field(SXVL,"0x6")
-    field(SVVL,"0x7")
-}
-

- asynFloat64 device support

-

- The following support is available:

-
device(ai,INST_IO,asynAiFloat64,"asynFloat64")
-device(ai,INST_IO,asynAiFloat64Average,"asynFloat64Average")
-device(ao,INST_IO,asynAoFloat64,"asynFloat64")
-

- devAsynFloat64.c provides EPICS device support for drivers that implement interface - asynFloat64.

-
    -
  • aiRecord -

    - A value is given to val. Beginning with R4-33 scaling via the ASLO/AOFF record fields, - and smoothing via the SMOO field are supported. -

    -
      -
    • asynFloat64 - SCAN "I/O Intr" is supported. If the record is "I/O Intr" scanned - then when the registerInterruptUser callback is called, it saves the value and calls - scanIoRequest. When the record is processed the saved value is put into val. If - the record is not "I/O Intr" scanned then each time the record is processed, a new - value is read via a call to pasynFloat64->read.
    • -
    • asynFloat64Average - The registerInterruptUser callback adds the new value to - a sum and also increments the number of samples. When the record is processed the - average is computed and the sum and number of samples is set to zero. If the record - is processed before new data have arrived (numAverage==0) the record is set to UDF/INVALID, - UDF is set to TRUE, and the value is left unchanged. The record can be scanned either - periodically or with SCAN=I/O Intr. If the record has SCAN=I/O Intr then the average - is computed and the record is processed each time NumAverage callback readings have - been received. The SVAL field in the ai record is used to set NumAverage.
    • -
    -
  • -
  • aoRecord -

    - val is written. Beginning with R4-33 scaling via the ASLO/AOFF record fields is - supported.

    -
  • -
-

- asynFloatXXXArray device support (XXX=32 or 64)

-

- The following support is available:

-
device(waveform,INST_IO,asynFloatXXXArrayWfIn,"asynFloatXXXArrayIn")
-device(waveform,INST_IO,asynFloatXXXArrayWfOut,"asynFloatXXXArrayOut")
-

- devAsynFloatXXXArray.c provides EPICS device support for drivers that implement - interface asynFloatXXXArray. It has support for both reading and writing a waveform. - SCAN "I/O Intr" is supported similar to the aiRecord in devAsynInt32 device support.

-

- asynOctet device support

-

- The following support is available:

-
device(stringin,INST_IO,asynSiOctetCmdResponse,"asynOctetCmdResponse")
-device(stringin,INST_IO,asynSiOctetWriteRead,"asynOctetWriteRead")
-device(stringin,INST_IO,asynSiOctetRead,"asynOctetRead")
-device(stringout,INST_IO,asynSoOctetWrite,"asynOctetWrite")
-device(waveform,INST_IO,asynWfOctetCmdResponse,"asynOctetCmdResponse")
-device(waveform,INST_IO,asynWfOctetWriteRead,"asynOctetWriteRead")
-device(waveform,INST_IO,asynWfOctetRead,"asynOctetRead")
-device(waveform,INST_IO,asynWfOctetWrite,"asynOctetWrite")
-device(waveform,INST_IO,asynWfOctetWriteBinary,"asynOctetWriteBinary")
-

- Support for drivers that implement interface asynOctet. The support is for stringin/stringout - and waveform records. The waveform support is similar to the string support. The - waveform records must define FTVL to be CHAR or UCHAR, i.e. it must be an array - of octets. The waveform provides the following features not provided by the string - support:

-
    -
  • unlimited size - string records hold a maximum of 40 characters.
  • -
  • both string and binary data. Beginning in R4-30 asynWfWriteOctet calls strnlen() - to determine the length of the string, and passes this length to the driver, i.e. - does not include the trailing nil. This is consistent with the behavior of the devAsynOctet - for the stringout record. The asynOctetWriteBinary support added in R4-30 always - uses NORD as the length that it passes to the driver, and does not call strnlen().
  • -
-

- Four types of support are provided:

-
    -
  • CmdResponse The INP field is of the form: -
        field(INP,"@asyn(portName,addr,timeout) cmd")
    - During record initialization, cmd is converted by dbTranslateEscape. The resultant - string is the command to send to the device. When the record is processed the command - is sent to the device and the response read into the record.
  • -
  • WriteRead The INP field is of the form: -
        field(INP,"@asyn(portName,addr,timeout) pvname")
    - pvname must refer to a field in a record in the same IOC. During record initialization - the pvname is located. When the record is processed dbGet is called to read the - current value of pvname. This value is sent to the device. A read is then issued - and the result stored in the record. For asynSiOctetWriteRead, the value obtained - from pvname is passed through dbTranslateEscape before sending it. For asynWfOctetWriteRead - it is not passed through dbTranslateEscape.
  • -
  • Write The INP(OUT) field is of the form: -
        field(INP,"@asyn(portName,addr,timeout) drvUser")
    - drvUser is information that is passed to the portDriver if it implements interface - asynDrvUser. When the record is processed the value stored in the record is sent - to the device.
  • -
  • Read The INP field is of the form: -
        field(INP,"@asyn(portName,addr,timeout) drvUser")
    - drvUser is information that is passed to the portDriver if it implements interface - asynDrvUser. When the record is processed a read request is made. The result is - read into the record.
  • -
-

- Record alarms

-

- The generic EPICS device support sets the record alarm status and severity when - errors occur. Beginning in R4-30 the alarmStatus and alarmSeverity fields were added - to the asynUser structure. Drivers can use these fields to explicitly control the - record STAT and SEVERITY fields, independent of the function return status or the - asynUser.auxStatus field.

-

- If the pasynUser->alarmStatus or pasynUser->alarmSeverity field is zero then - the record alarm status or severity is controlled by the function return status - or the asynUser.auxStatus field. For records that do not use callbacks (not SCAN=I/O - Intr or asynXXXAverage or asynXXXTimeSeries) the status information is passed from - the driver to device support in the asynStatus return of the interface function - call, e.g. pasynInt32->read(). The driver maps the asynStatus values to the record - STAT and SEVR values using the function pasynEpicsUtils->asynUserToEpicsAlarm(). - The SEVR field is currently always set to INVALID_ALARM for any error. The STAT - field is set using following mapping:

-
  asynSuccess = epicsAlarmNone
-  asynTimeout = epicsAlarmTimeout
-  asynOverflow = epicsAlarmHWLimit
-  asynError = epicsAlarmRead or epicsAlarmWrite
-  asynDisconnected = epicsAlarmComm
-  asynDisabled = epicsAlarmDisable
-  
-

- For records that use callbacks, the status information is passed from the driver - to device support using the pasynUser->auxStatus field in the pasynUser that - is passed in the callback. This feature was added in asyn R4-19. Prior to that release - it was not possible for drivers to control the alarm state of records that used - callbacks. Drivers should set pasynUser->auxStatus to asynSuccess for normal - operation and to another value to indicate a problem. The same mapping described - above is used to control the values of STAT and SEVR. If the pasynUser->alarmStatus - or pasynUser->alarmSeverity fields are non-zero then these values are used to - set the record STAT and SEVR fields, regardless of the value of asynUser.auxStatus. -

-
-

- asynRecord: Generic EPICS Record Support

-

- A special record type asynRecord is provided. Details are described in - asynRecord. This section provides a brief description of how to use it.

-

-

-

- Each IOC can load one or more instances of asynRecord. An example is:

-
cd $(ASYN)
-dbLoadRecords("db/asynRecord.db","P=asyn,R=Test,PORT=L0,ADDR=15,IMAX=0,OMAX=0")
-

- The example creates a record with name "asynTest" (formed from the concatenation - of the P and R macros) that will connect to port "L0" and addr 15. After the ioc - is started, it is possible to change PORT and/or ADDR. Thus, a single record can - be used to access all asyn devices connected to the IOC. Multiple records are only - needed if one or more devices need a dedicated record.

-

- An medm display is available for accessing an asynRecord. It is started as follows:

-
cd <asyn>/medm
-medm -x -macro "P=asyn,R=Test" asynRecord.adl
-

- The following medm display appears.

-
-

- asynRecord.png

-
-
-

- asynGpib

-

- GPIB has additional features that are not supported by asynCommon and asynOctet. - asynGpib defines two interfaces.

-
    -
  • asynGpib - This is the interface that device support calls. It provides the following: -
      -
    • A set of GPIB specific methods that device support can call.
    • -
    • Code that handles generic GPIB functions like SRQ polling.
    • -
    • A registerPort method which is called by GPIB port drivers. -

      -

      -
    • -
    -
  • -
  • asynGpibPort - A set of methods implemented by GPIB drivers
  • -
-

- asynGpibDriver.h

-

- asynGpibDriver.h contains the following definitions:

-
/* GPIB Addressed Commands*/
-#define IBGTL "\x01"    /* Go to local */
-#define IBSDC "\x04"    /* Selective Device Clear */
-#define IBGET "\x08"    /* Group Execute Trigger */
-#define IBTCT "\x09"    /* Take Control */
-
-/* GPIB Universal Commands*/
-#define IBDCL 0x14      /* Device Clear */
-#define IBLLO 0x11      /* Local Lockout */
-#define IBSPE 0x18      /* Serial Poll Enable */
-#define IBSPD 0x19      /* Serial Poll Disable */
-#define IBUNT 0x5f      /* Untalk */
-#define IBUNL 0x3f      /* Unlisten */
-
-/* Talk, Listen, Secondary base addresses */
-#define TADBASE    0x40   /* offset to GPIB listen address 0 */
-#define LADBASE    0x20   /* offset to GPIB talk address 0 */
-#define SADBASE    0x60   /* offset to GPIB secondary address 0 */
-
-#define NUM_GPIB_ADDRESSES    32
-#include "asynDriver.h"
-#include "asynInt32.h"
-#define asynGpibType "asynGpib"
-/* GPIB drivers */
-typedef struct asynGpib asynGpib;
-typedef struct asynGpibPort asynGpibPort;
-/*asynGpib defines methods called by gpib aware users*/
-struct asynGpib{
-    /*addressedCmd,...,ren are just passed to device handler*/
-    asynStatus (*addressedCmd) (void *drvPvt,asynUser *pasynUser,
-        const char *data, int length);
-    asynStatus (*universalCmd) (void *drvPvt,asynUser *pasynUser,int cmd);
-    asynStatus (*ifc) (void *drvPvt,asynUser *pasynUser);
-    asynStatus (*ren) (void *drvPvt,asynUser *pasynUser, int onOff);
-    /* The following are implemented by asynGpib */
-    asynStatus (*pollAddr)(void *drvPvt,asynUser *pasynUser, int onOff);
-    /* The following are called by low level gpib drivers */
-    /*srqHappened is passed the pointer returned by registerPort*/
-    void *(*registerPort)(
-        const char *portName,
-        int attributes,int autoConnect,
-        asynGpibPort *pasynGpibPort, void *asynGpibPortPvt,
-        unsigned int priority, unsigned int stackSize);
-    void (*srqHappened)(void *asynGpibPvt);
-};
-epicsShareExtern asynGpib *pasynGpib;
-
-struct asynGpibPort {
-    /*asynCommon methods */
-    void (*report)(void *drvPvt,FILE *fd,int details);
-    asynStatus (*connect)(void *drvPvt,asynUser *pasynUser);
-    asynStatus (*disconnect)(void *drvPvt,asynUser *pasynUser);
-    /*asynOctet methods passed through from asynGpib*/
-    asynStatus (*read)(void *drvPvt,asynUser *pasynUser,
-                      char *data,int maxchars,int *nbytesTransfered,
-                      int *eomReason);
-    asynStatus (*write)(void *drvPvt,asynUser *pasynUser,
-                      const char *data,int numchars,int *nbytesTransfered);
-    asynStatus (*flush)(void *drvPvt,asynUser *pasynUser);
-    asynStatus (*setEos)(void *drvPvt,asynUser *pasynUser,
-                const char *eos,int eoslen);
-    asynStatus (*getEos)(void *drvPvt,asynUser *pasynUser,
-                char *eos, int eossize, int *eoslen);
-    /*asynGpib methods passed thrtough from asynGpib*/
-    asynStatus (*addressedCmd) (void *drvPvt,asynUser *pasynUser,
-                const char *data, int length);
-    asynStatus (*universalCmd) (void *drvPvt, asynUser *pasynUser, int cmd);
-    asynStatus (*ifc) (void *drvPvt,asynUser *pasynUser);
-    asynStatus (*ren) (void *drvPvt,asynUser *pasynUser, int onOff);
-    /*asynGpibPort specific methods */
-    asynStatus (*srqStatus) (void *drvPvt,int *isSet);
-    asynStatus (*srqEnable) (void *drvPvt, int onOff);
-    asynStatus (*serialPollBegin) (void *drvPvt);
-    asynStatus (*serialPoll) (void *drvPvt, int addr, double timeout,int *status);
-    asynStatus (*serialPollEnd) (void *drvPvt);
-};
-

- asynGpib

-

- asynGpib describes the interface for device support code. It provides gpib specific - functions like SRQ handling. It makes calls to asynGpibPort. asynGpib.c implements - asynCommon and asynOctet. It supports asynInt32 by using the methods from asynInt32Base. - asynInt32 is the way asynGpib reports SRQs to asynUsers.

-

- An asynUser that wishes to receive SRQs calls pasynInt32->registerInterruptUser - and must set asynUser.reason = ASYN_REASON_SIGNAL. Although most gpib controllers - are multidevice drivers, the VXI11 standard allows for a controller (VXI-11.2) that - attached to a single device, i.e. it is a single address port driver. For such controllers, - the use must specify addr = 0 in order to use SRQs. Also see the vxi support below - for more details.

-

-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynGpib
- addressedCmd - The request is passed to the low level driver.
- universalCmd - The request is passed to the low level driver.
- ifc - The request is passed to the low level driver.
- ren - The request is passed to the low level driver.
- pollAddr - Set SRQ polling on or off. onOff = (0,1) means (disable, enable) SRQ polling of - specified address.
- registerPort - Register a port. When asynGpib receives this request, it calls asynManager.registerPort. -
- srqHappened - Called by low level driver when it detects that a GPIB device issues an SRQ.
-

- asynGpibPort

-

- asynGpibPort is the interface that is implemented by gpib drivers, e.g. the VXI-11. - It provides:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- asynGpibPort
- asynCommon methods - All the methods of asynCommon
- asynOctet methods - All the methods of asynOctet
- addressedCmd - Issue a GPIB addressed command.
- universalCmd - Issue a GPIB universal command.
- ifc - Issue a GPIB Interface Clear command.
- ren - Issue a GPIB Remote Enable command
- srqStatus - If return is asynSuccess then isSet is (0,1) if SRQ (is not, is) active. Normally - only called by asynGpib.
- srqEnable - Enable or disable SRQs. Normally only called by asynGpib.
- serialPollBegin - Start of serial poll. Normally only called by asynGpib.
- serialPoll - Poll the specified address and set status to the response. Normally only called - by asynGpib.
- serialPollEnd - End of serial poll. Normally only called by asynGpib.
-
-

- Port Drivers

-

- Local Serial Port

-

- The drvAsynSerialPort driver supports devices connected to serial ports on the IOC.

-

- Serial ports are configured with the drvAsynSerialPortConfigure and asynSetOption - commands:

-
   drvAsynSerialPortConfigure("portName","ttyName",priority,noAutoConnect,
-        noProcessEosIn)
-   asynSetOption("portName",addr,"key","value")
-

- where the arguments are:

-
    -
  • portName - The portName that is registered with asynGpib.
  • -
  • ttyName - The name of the local serial port (e.g. "/dev/ttyS0", "COM1").
  • -
  • priority - Priority at which the asyn I/O thread will run. If this is zero or - missing,then epicsThreadPriorityMedium is used.
  • -
  • addr - This argument is ignored since serial devices are configured with multiDevice=0.
  • -
  • noAutoConnect - Zero or missing indicates that portThread should automatically - connect. Non-zero if explicit connect command must be issued.
  • -
  • noProcessEos If 0 then asynInterposeEosConfig is called specifying both processEosIn - and processEosOut.
  • -
-

- The setEos and getEos methods have no effect and return asynError. The read method - blocks until at least one character has been received or until a timeout occurs. - The read method transfers as many characters as possible, limited by the specified - count. asynInterposeEos can be used to support EOS.

-

- The following table summarizes the drvAsynSerialPort driver asynSetOption keys and - values. When a serial port connects the current values are fetched.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Key - - Value -
- baud - 50 75 110 134 150 200 300 600 1200 2400 9600 ...
- bits - 8 7 6 5
- parity - none even odd
- stop - 1 2
- clocal - Y N
- crtscts - N Y
- ixon - N Y
- ixoff - N Y
- ixany - N Y
- rs485_enable - N Y
- rs485_rts_on_send - N Y
- rs485_rts_after_send - N Y
- rs485_delay_rts_before_send - msec_delay
- rs485_delay_rts_after_send - msec_delay
-

- On some systems (e.g. Windows, Darwin) the driver accepts any numeric value for - the baud rate, which must, of course be supported by the system hardware. On Linux - the choices are limited to the values like B300, B9600, etc. which are defined in - /usr/include/bits/termios.h.

-

- The clocal and crtscts parameter names are taken from the POSIX termios serial interface - definition. The clocal parameter controls whether the modem control lines (Data - Terminal Ready, Carrier Detect/Received Line Signal Detect) are used (clocal=N) - or ignored (clocal=Y). The crtscts parameter controls whether the hardware handshaking - lines (Request To Send, Clear To Send) are used (crtscts=Y) or ignored (crtscts=N).

-

- The vxWorks sioLib serial support does not provide support for modem control lines. - It also uses clocal for what is actually crtscts. For vxWorks the standard serial - support accepts both clocal and crtscts for getOption and setOption. clocal=Y implies - crtscts=N and clocal=N implies crtscts=Y.

-

- ixon controls XON/OFF flow control on output. If the IOC receives an XOFF character, - it suspends output until an XON character is received. This option is also supported - on ports communicating via the RFC 2217 Telnet protocol. In this case, as noted - in the standard, ixon implies both outbound and inbound flow control.

-

- ixoff controls XON/OFF flow control on input. The IOC sends XOFF and XON characters - as necessary to prevent input from coming in faster than programs are reading it. - The external device sending the input data must respond to an XOFF character by - suspending transmission, and to an XON character by resuming transmission.

-

- The ixany flag allows any input character to restart output when output has been - suspended with the XOFF character. Otherwise, only the XON character restarts output. - This flag is not available on all systems, including WIN32.

-

- The rs485 options are only supported on Linux, only kernels ≥ 2.6.35, and only - on hardware ports that support RS-485. The delay option units are integer milliseconds.

-

- vxWorks IOC serial ports may need to be set up using hardware-specific commands. - Once this is done, the standard drvAsynSerialPortConfigure and asynSetOption commands - can be issued. For example, the following example shows the configuration procedure - for a port on a GreenSprings octal UART Industry-Pack module on a GreenSprings VIP616-01 - carrier.

-
-ipacAddVIPC616_01("0x6000,B0000000")
-tyGSOctalDrv(1)
-tyGSOctalModuleInit("Mod0","232", 0x80, 0, 0)
-tyGSOctalDevCreate("/tyGS/0/0","Mod0",0,0,1000,1000)
-drvAsynSerialPortConfigure("/tyGS/0/0","/tyGS/0/0",0,0,0)
-asynSetOption("/tyGS/0/0",0,"baud","9600")
-
-For the IP520:
-
-IP520Drv(1)
-IP520ModuleInit("UART_0", "232", 0xC2, 0, 0)
-IP520DevCreate("A1", "UART_0", 0, 0, 1000, 1000)
-drvAsynSerialPortConfigure("A1","A1",0,0,0)
-asynSetOption("A1",0,"baud",9600)
-asynOctetSetInputEos( "A1",0,"\r")
-asynOctetSetOutputEos("A1",0,"\r")
-
-

- TCP/IP or UDP/IP Port

-

- The drvAsynIPPort driver supports devices which communicate over a TCP/IP or UDP/IP - connection. A typical example is a device connected through an Ethernet/Serial converter - box.

-

- TCP/IP or UDP/IP connections are configured with the drvAsynIPPortConfigure - command:

-
   drvAsynIPPortConfigure("portName","hostInfo",priority,noAutoConnect,
-        noProcessEos)
-

- where the arguments are:

-
    -
  • portName - The portName that is registered with asynManager.
  • -
  • hostInfo - The Internet host name, port number, optional local port number, and - optional IP protocol of the device. The format is:
    - <host>:<port>[:localPort] [protocol]
    - (e.g. "164.54.9.90:4002", "164.54.9.90:4001:10101", "serials8n3:4002", "serials8n3:4002 - TCP" or "164.54.17.43:5186 udp"). If no protocol is specified, TCP will be used. - Possible protocols are -
      -
    • TCP
    • -
    • UDP
    • -
    • UDP* -- Send UDP broadcasts. The address portion of the argument must be the network - broadcast address (e.g. "192.168.1.255:1234 UDP*", or "255.255.255.255:1234 UDP*", - etc.).
    • -
    • HTTP -- Like TCP but for servers which close the connection after each transaction.
    • -
    • COM -- For Ethernet/Serial adapters which use the TELNET RFC 2217 protocol. This - allows port parameters (speed, parity, etc.) to be set with subsequent asynSetOption - commands just as for local serial ports. The default parameters are 9600-8-N-1 with - no flow control.
    • -
    - If the hostInfo argument begins wih the characters - unix:// the remainder of the argument is taken to be the name of a UNIX-domain - stream socket. -
    - To receive UDP broadcasts the localPort is the port to listen on, for example: drvAsynIPPortConfigure("BD","255.255.255.255:1234:3956 - UDP*",0,0,0). If the port is only to be used to receive broadcast messages then - the UDP protocol should be specified. If it is also to be used to send UDP broadcasts - then the UDP* protocol must be specified. In this case the broadcasts will be send - on port "port" and it will listen for broadcast messages on port "localPort".
    - Note that the localPort should almost never be used for TCP ports because normally - the local host choses an unused random local port that it binds to and passes to - the server. However, there are some unusual servers that only accept a specific - local port or range of local ports, in which case localPort must be specified.
  • -
  • priority - Priority at which the asyn I/O thread will run. If this is zero or - missing, then epicsThreadPriorityMedium is used.
  • -
  • noAutoConnect - Zero or missing indicates that portThread should automatically - connect. Non-zero if explicit connect command must be issued.
  • -
  • noProcessEos If 0 then asynInterposeEosConfig is called specifying both processEosIn - and processEosOut.
  • -
-

- Only asynOctet methods write, read, and flush are implemented. Calling the other - methods will result in an error unless asynInterposeEos is used for the other asynOctet - methods. read blocks until at least one character has been received or until a timeout - occurs. read transfers as many characters as possible, limited by the specified - count.

-

- The following table summarizes the drvAsynIPPort driver asynSetOption keys and values.

- - - - - - - - - - - - - - - - - - -
- Key - - Value - - Description -
- disconnectOnReadTimeout - N Y - Default=N. If Y then if a read operation times out the driver automatically disconnect - the IP port.
- hostInfo - <host>:<port>[:localPort] [protocol] - The IP port hostInfo specification using the same syntax as drvAsynIPPortConfigure. - This option 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.
-

- In addition to these key/value pairs if the COM protocol is used then the drvAsynIPPort - driver uses the same key/value pairs as the drvAsynSerialPort driver for specifying - the serial parameters, i.e. "baud", "bits", etc.

-

- asynInterposeEos and asynInterposeFlush can be used to provide additional functionality.

-

- TCP/IP Server

-

- The drvAsynIPServerPort driver supports asyn socket servers by listening for TCP/IP - or UDP connections from remote clients. The creates maxClients drvAsynIPPort port - drivers by calling drvAsynIPPortConfigure at initialization. These ports are named - portName:0, portName:1, etc. where portName is the name passed to drvAsynIPServerPortConfigure.

-

- IP server listeners are configured with the drvAsynIPServerPortConfigure - command:

-
 drvAsynIPServerPortConfigure("portName", "serverInfo", maxClients, priority, 
-      noAutoConnect, noProcessEos);
-

- where the arguments are:

-
    -
  • portName - The portName that is registered with asynManager.
  • -
  • serverInfo - The Internet host name and port number to listen for connections - on (e.g. "localhost:4002" for TCP, "localhost:4002 UDP" for UDP).
  • -
  • maxClients - the maximum number of IP clients that can be simultaneously connected - on this port. Additional connect requests will fail.
  • -
  • priority - Priority at which the listener thread and any asyn I/O ports it creates - will run. If this is zero or missing, then epicsThreadPriorityMedium is used.
  • -
  • noAutoConnect - Zero or missing indicates that the listener port should automatically - connect. Non-zero if explicit connect command must be issued. Note that all asyn - I/O ports that the listener thread creates will be created with noAutoConnect=1, - but this is transparent to socket server applications, because the listener thread - does the explicit connection for them.
  • -
  • noProcessEos is passed to drvAsynIPPortConfigure when new asyn I/O ports are created. - If 0 then asynInterposeEosConfig is called specifying both processEosIn and processEosOut.
  • -
-

- This driver implements the asynOctet interface. For TCP connections the only methods - it supports are registerInterruptUser and cancelInterruptUser. Calling the other - asynOctet methods will result in an error. For UDP it implements asynOctet->read(). - The following happens when a new connection is received on the port specified in - drvAsynIPServerPortConfigure:

-
    -
  • The list of drvAsynIPPort ports that this listener thread has created is searched - to see if there is a drvAsynIPPort that is currently disconnected because there - is no remote IP client connected.
  • -
  • If there is a disconnected port, then it is connected with the file descriptor - from the new IP connection.
  • -
  • If there are no disconnected ports then the incoming connection will be immediately - closed.
  • -
  • The asynTraceMask and asynTraceIOMask of the newly connected port are set to the - current values of the listener thread port. This makes it possible to trace the - early stages of execution of the callbacks to the registered clients, before one - could enable tracing at iocsh.
  • -
  • All registered asyn clients (who have called registerInterruptUser on the asynOctet - interface of the listener port) are called back with the name of the newly connected - port.
  • -
-

- VXI-11

-

- VXI-11 is a TCP/IP protocol for communicating with IEEE 488.2 devices. It is an - RPC based protocol. In addition to the VXI-11 standard, three additional standards - are defined.

-
    -
  • VXI-11.1 - A standard for communicating with VXIbus devices. These controllers - have a vxiName that starts with "vxi" and can control multiple devices, i.e. the - port driver will be a multiaddress driver.
  • -
  • VXI-11.2 - A standard for communicating with a IEEE 488.1 device. This means that - the TCP/IP connection is talking to a GPIB controller that is talking to a GPIB - bus. These devices have an vxiName that starts with "gpib". Note that the Agilent - E2050A does not follow the standard. For it the vxiName must be "hpib"
  • -
  • VXI-11.3 - A standard for communicating with IEEE 488.2 devices. This means that - the TCP/IP connection is talking directly with an device. These devices have an - vxiName that starts with "inst". These controllers can control only a single device, - i.e. the port driver will be a single address driver
  • -
-

- NOTES

-
    -
  • No VXI-11.1 controller has been tested.
  • -
  • The following VXI-11.2 controllers have been tested: Agilent E2050 and E5810
  • -
  • The following VXI-11.3 instruments have been tested: -
      -
    • Tektronic TDS3054B scope. -

      - SRQs do not work. Do not know why

      -
    • -
    • Tektronic TDS5054B scope. -

      - SRQs do work. The asynUser MUST specify addr = 0. Also do NOT set bit 0x40 of Service - Request Enable register, i.e. cause SRQ when device has output available. This did - not work and can cause infinite set of SRQs

      -
    • -
    -
  • -
-

- Consult the following documents (available on-line) for details.

-
VMEbus Extensions for Instrumentation
-    VXI-11   TCP/IP Instrument Protocol Specification
-    VXI-11.1 TCP/IP-VXIbus Interface Specification
-    VXI-11.2 TCP/IP-IEEE 488.1 Interface Specification
-    VXI-11.3 TCP/IP-IEEE 488.2 Instrument Interface Specification
-

- The following commands may be specified in the st.cmd file

-
    E2050Reboot("inet_addr")
-    E5810Reboot("inet_addr","password")
-    vxi11Configure("portName","inet_addr",flags,"timeout",
-        "vxiName",priority,noAutoConnect)
-

- where

-
    -
  • inet_addr - Internet Address
  • -
  • password - password. If given as 0 the default E5810 is used.
  • -
  • portName - The portName that is registered with asynGib.
  • -
  • flags - Bitmap -
      -
    • Bit 0 (0x1) recoverWithIFC - (0,1) => (don't, do) issue IFC when error occurs.
    • -
    • Bit 1 (0x2) lockDevices - (0,1 ) => (don't, do) lock devices when creating - the link.
    • -
    • Bit 2 (0x4) noSRQ - (0,1 ) => (do, don't) set up a VXI-11 SRQ channel.
    • -
    -
  • -
  • timeout - I/O operation timeout in seconds as a string. Prior to release R4-16 - this was a double, but was changed to a string because it is not safe to pass doubles - on the vxWorks shell. If "0.0", then a default is assigned.
  • -
  • vxiName - Must be chosen as specified above. NOTE: For the Agilent E2050 vxiName - must be "hpib". For the Agilent E5810 use the name "gpib0". For an instrument that - supports VXI11 try "inst0".
  • -
  • priority - Priority at which the asyn I/O thread will run. If this is zero or - missing, then epicsThreadPriorityMedium is used.
  • -
  • noAutoConnect - Zero or missing indicates that portThread should automatically - connect. Non-zero if explicit connect command must be issued.
  • -
-

- The vxi11 driver implements two timeouts: ioTimeout and rpcTimeout (Remote Procedure - Call timeout). The ioTimeout is taken from asynUser:timeout. The rpcTimeout is handled - internally for each port. It has a default of 4 seconds but can be changed by calling - setOptions. For example:

-
asynSetOption L0 -1 rpctimeout .1
-

- Will change the rpcTimeout for port L0 to .1 seconds.

-

- Linux-Gpib

-

- The linux-gpib port driver was written to support - The Linux GPIB Package library.

-

- In order to build this support the Linux GPIB Package must be installed. Also in - configure/RELEASE the statement:

-
    LINUX_GPIB=NO
-

- must be changed to

-
    LINUX_GPIB=YES
-

- Configuration command is:

-
    GpibBoardDriverConfig(portName,autoConnect,BoardIndex,timeout,priority)
-

- where

-
    -
  • portName - An ascii string specifying the port name that will be registered with - asynDriver.
  • -
  • noAutoConnect - Non-zero indicates that portThread should automatically connect. - Zero means explicit connect command must be issued.
  • -
  • boardIndex -Integer containing index of board (0 means /dev/gpib0). Normally it - is 0. This must be the same as in gpib.conf file (minor number - board index) of - driver configuration.
  • -
  • timeout - Time in seconds in which an i/o operation must complete. Zero means - disabled. This is "general" timeout for every call to low level drivers. For actual - read/write operations timeout must be defined in device support. Both timeouts are - converted into integers 0-17 which represents disabled to 1000 seconds.
  • -
  • priority - An integer specifying the priority of the port thread. A value of 0 - will result in a default value being assigned.
  • -
-

- An example is:

-
GpibBoardDriverConfig("L0",1,0,3,0)
-

- NOTES:

-
    -
  • AsynOption Interface is supported. Key (hexadecimal) and val (integer) arguments - to setPortOptions function must be appropriate values represented as character arrays. - See GPIB library documentation for details.
  • -
  • pgpibCmd type GPIBREADW and GPIBEFASTIW were not tested.
  • -
  • The linux-port driver was tested with PC104-GPIB board from Measurement Computing.
  • -
-

- Green Springs IP488

-

- This is support for the Green Springs Industry Pack GPIB carrier. The configuration - command is:

-
    gsIP488Configure(portName,carrier,module,intVec,priority,noAutoConnect)
-

- where

-
    -
  • portName - An ascii string specifying the port name that will be registered with - asynDriver.
  • -
  • carrier - An integer identifying the Industry Pack Carrier
  • -
  • module - An integer identifying the module on the carrier
  • -
  • intVec - An integer specifying the interrupt vector
  • -
  • priority - An integer specifying the priority of the portThread. A value of 0 - will result in a defalt value being assigned
  • -
  • noAutoConnect - Zero or missing indicates that portThread should automatically - connect. Non-zero if explicit connect command must be issued.
  • -
-

- An example is:

-
#The following is for the Greensprings IP488 on an MV162 
-ipacAddMVME162("A:l=3,3 m=0xe0000000,64")
-gsIP488Configure("L0",0,0,0x61,0,0)
-

- WARNING:

-

- This module includes code that implement a 6 microsecond delay because the gpib - interface chip requires it. The first time gsIP488Configure is executed code is - run to determine a variable used by the delay routine. It assumes that there is - no higher priority thread running that consumes lots of cpu cycles.

-

- National Instruments GPIB-1014D

-

- This is support for a National Instruments VME GPIB interface. The configuration - command is:

-
    ni1014Config(portNameA,portNameB,base,vector,level,priority,noAutoConnect)
-

- where

-
    -
  • portNameA - An ascii string specifying the port name that will be registered with - asynDriver for portA.
  • -
  • portNameB - An ascii string specifying the port name that will be registered with - asynDriver for portB. If only one port should be registered, then leave this as - a null string. The support should also work for a single port NI1014 but has not - been tested.
  • -
  • base - VME A16 base address.
  • -
  • vector - VME interrupt vector.
  • -
  • level - An integer specifying the interrupt level.
  • -
  • priority - In integer specifying the priority of the portThread. A value of 0 - will result in a defalt value being assigned
  • -
  • noAutoConnect - Zero or missing indicates that portThread should automatically - connect. Non-zero if explicit connect command must be issued.
  • -
-

- An example is:

-
ni1014Config("L0","L1",0x5000,0x64,5,0,0)
-

- NOTES:

-
    -
  • Ports A and B are almost but not quite the same. Thus the code for connecting - to port A is slightly different than the code for portB.
  • -
  • In order to disconnect and reconnect either port, BOTH ports must be disconnected - and reconnected.
  • -
  • When the ports are connected, portA MUST be connected before port B.
  • -
  • Programmed I/O, via interrupts, rather than DMA is implemented. Thus no A24 address - space is required.
  • -
-

- WARNING:

-

- This module includes code that implement a 6 microsecond delay because the gpib - interface chip requires it. The first time ni1014Config is executed code is run - to determine a variable used by the delay routine. It assumes that there is no higher - priority thread running that consumes lots of cpu cycles.

-

- USB TMC (Test and Measurement Class) driver

-

- Configure each instance of the driver in the application startup script:

-
usbtmcConfigure("asynPort", vendorId, productId, "serialNumber", priority, flags)
-

- The asynPort and serialNumber arguments are strings and the other - arguments are integers. A missing or 0 vendorId or productId matches - any value and a missing or empty serialNumber string matches any value. - Thus the command:

-
usbtmcConfigure("usbtmc1")
-

- will associate ASYN port usbtmc1 with the first USB TMC device discovered. A missing - or 0 priority will set the worker thread priority to its default value of 50 (epicsThreadPriorityMedium).

-

- A missing flags argument is taken to be 0. As of now only one bit is used: Bit 0 - (0x1) Disable/enable (1/0) automatic port connection.

-

- Non-octet records

-

- In addition to the asynOctet stream this support module provides some values for - records with DTYP=asynInt32. Since the port is a single-address device the subaddress - field of the INP or OUT '@asyn()' descriptor can not be used. Instead the 'drvUser' - string at the end of the INP or OUT field is used to distinguish the parameter to - be read or written. -

-
- Service Request (SRQ) handling
-

- The presence of one or more records with INP="@asyn(port, 0, 0) SRQ") will cause - the driver to create an extra thread to read from the device Interrupt-In endpoint. - The SCAN field must be "I/O Intr". Record processing will occur when the device - sends a service request message on the Interrupt-In endpoint and the value will - be the device status byte sent as part of the service request message. Typically - the record type will be longin or mbbiDirect.

-
- Device Status Byte (STB)
-

- The USBTMC/USB488 device status byte is read by a record with

-
INP="@asyn(port, 0, 0) STB").
-

- Typically the record type will be longin or mbbiDirect.

-
- Remote Enable (REN)
-

- The device remote enable is written by a record with

-
OUT="@asyn(port, 0, 0) REN") 
-

- Typically the record type will be bo.

-

- Linux udev configuration

-

- If attempts to communicate with a device result in error messages of the form "Access - denied (insufficient permissions)" you must add udev entries to allow access. In - the /etc/udev/rules.d directory create a file, 55-usbtmc.rules for example, with - a line for each device of interest.

-

- To allow everyone in the "usbtmc" group access to a device with vendor code 1BFA - (hexadecimal) and product code 0498 (hexadecimal) the line would look like:

-
-SUBSYSTEM=="usb", ATTRS{idVendor}=="1BFA", ATTRS{idProduct}=="0498", GROUP="usbtmc", MODE="0660"
-

- To allow everyone access the line would look like:

-
-SUBSYSTEM=="usb", ATTRS{idVendor}=="1BFA", ATTRS{idProduct}=="0498", MODE="0666"
-

- The {idVendor} and {idProduct} values must match those of the - device with which you wish to communicate.

-

- StreamDevice Exception Handlers

-

- The USBTMC driver attempts to take correct action when it detects that the device - has been unplugged or become unresponsive. The effectiveness of this depends somewhat - on the level of support provided by the underlying operating system so it is good - practice to also specify the following StreamDevice global exception handlers:

-
-    @mismatch { disconnect; }
-    @writetimeout { disconnect; }
-    @readtimeout { disconnect; }
-    @replyTimeout { disconnect; }
-
-

- Additional Drivers

-

- The drivers noted above are included as part of the ASYN distribution.  Additional - drivers are available, including:
-

- -
-

- asynPortDriver C++ base class

-

- A C++ base class called asynPortDriver is available. This is a base class from which - real asyn port drivers can be derived. It greatly simplifies the job of writing - an asyn port driver, because it takes care of all of the tasks like registering - the port, registering the interfaces, and calling interrupt clients. It is documented - separately in asynPortDriver.html.

-
-

- asynPortClient C++ classes

-

- asynPortClient is a set of C++ classes that are designed to simplify the task of - writing a client that directly communicates with an asyn port driver, without running - an EPICS IOC. They handle the details of connecting to the driver, finding the required - interfaces, etc. They only uses the synchronous interfaces, so all calls are blocking. - If clients need asynchronous operation then they can use the normal C interface - with pasynManager->queueRequest. It is documented separately in - asynPortClient.html.

-
-

- Diagnostic Aids

-

- iocsh Commands

-
    asynReport(level,portName)
-    asynInterposeFlushConfig(portName,addr,timeout)
-    asynInterposeEosConfig(portName,addr,processIn,processOut)
-    asynSetTraceMask(portName,addr,mask)
-    asynSetTraceIOMask(portName,addr,mask)
-    asynSetTraceInfoMask(portName,addr,mask)
-    asynSetTraceFile(portName,addr,filename)
-    asynSetTraceIOTruncateSize(portName,addr,size)
-    asynSetOption(portName,addr,key,val)
-    asynShowOption(portName,addr,key)
-    asynAutoConnect(portName,addr,yesNo)
-    asynSetAutoConnectTimeout(timeout)
-    asynWaitConnect(portName, timeout)
-    asynEnable(portName,addr,yesNo)
-    asynOctetConnect(entry,portName,addr,timeout,buffer_len,drvInfo)
-    asynOctetRead(entry,nread)
-    asynOctetWrite(entry,output)
-    asynOctetWriteRead(entry,output,nread)
-    asynOctetFlush(entry)
-    asynOctetSetInputEos(portName,addr,eos,drvInfo)
-    asynOctetGetInputEos(portName,addr,drvInfo)
-    asynOctetSetOutputEos(portName,addr,eos,drvInfo)
-    asynOctetGetOutputEos(portName,addr,drvInfo)
-    asynRegisterTimeStampSource(portName,functionName);
-    asynUnregisterTimeStampSource(portName)    
-    
-

- asynReport calls asynCommon:report for a specific port - if portName is specified, or for all registered drivers and interposeInterface if - portName is not specified.

-

- asynInterposeFlushConfig is a generic interposeInterface that implements - flush for low level drivers that don't implement flush. It just issues read requests - until no bytes are left to read. The timeout is used for the read requests.

-

- asynInterposeEosConfig is a generic interposeInterface that implements - End of String processing for low level drivers that don't.

-

- asynSetTraceMask calls asynTrace:setTraceMask for the - specified port and address. If portName is zero length then the global trace mask - is set. The mask bit definitions are documented in the traceMask - definitions.

-

- asynSetTraceIOMask calls asynTrace:setTraceIOMask for - the specified port and address. If portName is zero length then the global traceIO - mask is set. The mask bit definitions are documented in the - traceIO mask definitions.

-

- asynSetTraceInfoMask calls asynTrace:setTraceInfoMask - for the specified port and address. If portName is zero length then the global traceInfo - mask is set. The mask bit definitions are documented in the - traceInfo mask definitions.

-

- Beginning with asyn R4-35 the mask argument of asynSetTraceMask, asynSetTraceIOMask, - and asynSetTraceInfoMask can be specified either 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 are not case sensitive - and the prefixes ASYN_, TRACE_, TRACEIO_, and TRACEINFO_ are optional. Examples:

-
-          asynSetTraceMask port,0,ASYN_TRACE_ERROR 
-         asynSetTraceIOMask port,0,ascii+escape
-         asynSetTraceInfoMask port,0,1+port+TRACEINFO_SOURCE|ASYN_TRACEINFO_THREAD
-  
-

- asynSetTraceFile calls asynTrace:setTraceFile. The filename - is handled as follows:

-
    -
  • Not specified - A NULL pointer is passed to setTraceFile. Subsequent messages - are sent to errlog.
  • -
  • An empty string ("") or "stderr" - stderr is passed to setTraceFile.
  • -
  • "stdout" - stdout is passed to setTraceFile.
  • -
  • Any other string - The specified file is opened with an option of "w" and the - file pointer is passed to setTraceFile.
  • -
-

- asynSetTraceIOTruncateSize calls asynTrace:setTraceIOTruncateSize

-

- asynSetOption calls asynCommon:setOption. asynShowOption - calls asynCommon:getOption.

-

- Thw asynOctetXXX commands provide shell access to asynOctetSyncIO methods. The entry - is a character string constant that identifies the port,addr.

-

- where

-
    -
  • filename - An ascii string naming a file. If null or a null string, then the output - is sent to stdout.
  • -
  • level - The report level.
  • -
  • portName - An ascii string specifying the portName of the driver.
  • -
  • addr - In integer specifying the address of the device. For multiDevice ports - a value of -1 means the port itself. For ports that support a single device, addr - is ignored.
  • -
  • mask - The mask value to set. See the mask bit definitions in asynDriver.h
  • -
  • key - The key for the option desired.
  • -
  • val - The value for the option.
  • -
  • yesNo - The value (0,1) means (no,yes).
  • -
  • entry - A character string that identifies the asynOctetConnect request.
  • -
  • timeout - timeout as an integer in milliseconds. The default is 1.
  • -
  • buffer_len - length of buffer for I/O. Default=160. NOTE: output strings passed - to asynOctetWrite can have escape characters. The buffer_len must be large enough - to handle escape characters. For example if \x02 appears in an output string it - counts as four characters.
  • -
  • drvInfo - A string to pass to the driver via interface asynDrvUser.
  • -
  • nread - max number of bytes to read. Default=buffer_len.
  • -
  • flush - (0,1) means (don't, do) flush before reading. Default=0.
  • -
  • output - output string.
  • -
-

- The commands asynOctetConnect, asynOctetDisconnect, asynOctetRead, asynOctetWrite, - asynOctetWriteRead, asynOctetFlush allow I/O to a device from the ioc shell. Examples - are:

-
asynOctetConnect("myid","A",0,1,20)
-asynOctetWrite("myid","testnew")
-asynOctetRead("myid")
-testnew\n
-asynOctetWriteRead("myid","this is test")
-this is test\n
-asynOctetDisconnect("myid")
-

- asynRegisterTimeStampSource calls pasynManager->registerTimeStampSource - for the specified port. The time stamp source function must be defined as a "function" - in the application dbd file.

-

- asynUnregisterTimeStampSource calls pasynManager->runegisterTimeStampSource - for the specified port. This reverts to the default timestamp source function in - asynManager.

-
-

- Example Client

-

- The following is an example of an asyn client that reads from an asyn driver via - octet messages:

-
#include <asynDriver.h>
-...
-#define BUFFER_SIZE 80
-typedef struct myData {
-    epicsEventId done;
-    asynOctet    *pasynOctet;
-    void         *drvPvt;
-    char         buffer[BUFFER_SIZE];
-}myData;
-
-static void queueCallback(asynUser *pasynUser) {
-    myData     *pmydata = (myData *)pasynUser->userPvt;
-    asynOctet  *pasynOctet = pmydata->pasynOctet;
-    void       *drvPvt = pmydata->drvPvt;
-    asynStatus status;
-    int        writeBytes,readBytes;
-    int        eomReason;
-
-    asynPrint(pasynUser,ASYN_TRACE_FLOW,"queueCallback entered\n");
-    status = pasynOctet->write(drvPvt,pasynUser,pmydata->buffer,
-              strlen(pmydata->buffer),&writeBytes);
-    if(status!=asynSuccess) {
-        asynPrint(pasynUser,ASYN_TRACE_ERROR,
-            "queueCallback write failed %s\n",pasynUser->errorMessage);
-    } else {
-        asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE,
-            pmydata->buffer,strlen(pmydata->buffer),
-            "queueCallback write sent %d bytes\n",writeBytes);
-    }
-    status = pasynOctet->read(drvPvt,pasynUser,pmydata->buffer,
-         BUFFER_SIZE,&readBytes,&eomReason);
-    if(status!=asynSuccess) {
-        asynPrint(pasynUser,ASYN_TRACE_ERROR,
-            "queueCallback read failed %s\n",pasynUser->errorMessage);
-    } else {
-        asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE,
-            pmydata->buffer,BUFFER_SIZE,
-            "queueCallback read returned: retlen %d eomReason 0x%x data %s\n",
-            readBytes,eomReason,pmydata->buffer);
-    }
-    epicsEventSignal(pmydata->done);
-}
-
-static void asynExample(const char *port,int addr,const char *message)
-{
-    myData        *pmyData;
-    asynUser      *pasynUser;
-    asynStatus    status;
-    asynInterface *pasynInterface;
-
-    pmyData = (myData *)pasynManager->memMalloc(sizeof(myData));
-    memset(pmyData,0,sizeof(myData));
-    strcpy(pmyData->buffer,message);
-    pasynUser = pasynManager->createAsynUser(queueCallback,0);
-    pasynUser->userPvt = pmyData;
-    status = pasynManager->connectDevice(pasynUser,port,addr);
-    if(status!=asynSuccess) {
-        printf("can't connect to serialPort1 %s\n",pasynUser->errorMessage);
-        exit(1);
-    }
-    pasynInterface = pasynManager->findInterface(
-        pasynUser,asynOctetType,1);
-    if(!pasynInterface) {
-        printf("%s driver not supported\n",asynOctetType);
-        exit(-1);
-    }
-    pmyData->pasynOctet = (asynOctet *)pasynInterface->pinterface;
-    pmyData->drvPvt = pasynInterface->drvPvt;
-    pmyData->done = epicsEventCreate(epicsEventEmpty);
-    status = pasynManager->queueRequest(pasynUser,asynQueuePriorityLow, 0.0);
-    if(status) {
-        asynPrint(pasynUser,ASYN_TRACE_ERROR,
-            "queueRequest failed %s\n",pasynUser->errorMessage);
-    }
-    epicsEventWait(pmyData->done);
-    status = pasynManager->freeAsynUser(pasynUser);
-    if(status) {
-        asynPrint(pasynUser,ASYN_TRACE_ERROR,
-            "freeAsynUser failed %s\n",pasynUser->errorMessage);
-    }
-    epicsEventDestroy(pmyData->done);
-    pasynManager->memFree(pasynUser->userPvt,sizeof(myData));
-}
-

- The flow of control is as follows:

-
    -
  1. A port driver calls registerPort. This step is not shown in the above example.
  2. -
  3. asynExample allocates myData and an asynUser.
  4. -
  5. asynExample connects to a device and to the asynOctet interface for the port driver.
  6. -
  7. When it is ready to communicate with the driver it calls queueRequest.
  8. -
  9. queueCallback is called. It calls the port driver's write and read methods.
  10. -
-
-

- Test Applications

-

- The asynDriver distribution includes several test applications to test asynDriver - and device support.

-

- testApp

-

- This is an example of how to interface to asynManager. The example resides in <top>/testApp - and contains the following components:

-
Db/
-   test.db
-   testBlock.db
-adl/
-   test.adl
-src/
-   devTestBlock.dbd
-   echoDriver.c
-   addrChangeDriver.c
-   devTestBlock.c
-   interposeInterface.c
-

- echoDriver is a port driver that echos messages it receives. It implements asynCommon - and asynOctet. When asynOctet:write is called it saves the message. When asynOctet:read - is called, the saved message is returned and the message is flushed. echoDriverInit - has an argument that determines if it acts like a multiDevice or a single device - port driver.

-

- An instance of echoDriver is started via the iocsh command:

-
echoDriverInit(portName,delay,noAutoConnect,multiDevice)
-

- where

-
    -
  • portName - the port name for this instance.
  • -
  • delay - The time to delay after a read or write. If delay is 0 then echoDriver - registers as a synchronous port driver, i.e. bit ASYN_CANBLOCK of attributes is - not set. If delay>0 then ASYN_CANBLOCK is set.
  • -
  • noAutoConnect - Determines initial setting for port.
  • -
  • multiDevice - If true then it supports two devices with addresses 0 and 1. If - false it does not set ASYN_MULTIDEVICE, i.e. it only supports a single device.
  • -
-

- addrChangeDriver is a multidevice driver that is an asynUser of another port driver. - In the example application it connects to echoDriver. An example where this technique - might be used is a port driver for mult-drop serial that connects to a standard - serial port.

-

- An instance of addrChangeDriver is started via the iocsh commandL:

-
addrChangeDriverInit(portName,lowerPort,addr)
-

- where

-
    -
  • portName - the port name for this instance.
  • -
  • lowerPort - the port to which addrChangeDriver connects
  • -
  • addr - The address to which addrChangeDriver connects
  • -
-

- devTestBlock is device support that tests blockProcessCallback. It has device support - for stringin records. The INP field has the syntax:

-
    field(INP,"@asyn(port,addr,timeout) pvname)
-

- where:

-
    -
  • asyn(port,addr,timeout) is same as for devEpics support.
  • -
  • pvname - The name of a record in the same ioc.
  • -
-

- When the stringin record is processed the following occurs.

-
    -
  • When process is called and PACT is : -
      -
    • TRUE - then it just returns to record support.
    • -
    • FALSE - It does what follows.
    • -
    -
  • -
  • When processing starts the state is stateIdle.
  • -
  • blockProcessCallback is called.
  • -
  • callbackRequestDelayed is called (.1 second delay). The callback calls queueRequest.
  • -
  • When processCallback is called it does the following: -
      -
    • calls unblockProcessCallback
    • -
    • If state is stateIdle -
        -
      • Calls dbGet to get a string value from pvname
      • -
      • calls pasynOctet->write to send the string
      • -
      • sets state to stateWrite
      • -
      • Calls blockProcessCallback
      • -
      • callbackRequestDelayed is called The callback calls queueRequest.
      • -
      • completes. processCallback will be called again
      • -
      -
    • -
    • If state is stateWrite -
        -
      • calls pasynOctet->read and puts the value in VAL.
      • -
      • Sets state = stateIdle
      • -
      • requests the the record be processed. This time PACT will be TRUE
      • -
      -
    • -
    -
  • -
-

- test.db is a template containing three records: a calc record, which forward links - to a stringout record which forward links to a stringin record. The stringOut record - attaches to the device support supplied by asynOctetWriteRead.c. When the calcRecord - is processed the following happens:

-
    -
  • The calcRecord acts as a counter that overflows when the count reaches 10. After - counting to forward links ti the stringIn record.
  • -
  • The string in record gets the current value of the counter converted to s character - string and forward links to the stringOut record.
  • -
  • The stringOut record gets the value from the stringIn record an calls queueRequest. - The record is left with PACT true.
  • -
  • The processCallback calls pasynOctet->write passing the value obtained from - the stringIn record. The then does does a pasynOctet->read. When this completes - it asks for the record to complete processing.
  • -
  • The stringOut record completes processing. -

    -

    -
  • -
-

- testBlock.db is a template similar to test.db except that it attached to device - support testBlock instead of asynOctetWriteRead.

-

- Executing "medm -x test.adl" produces the display:

-
-

- asynTest.png

-
-

- It assumes that an ioc has been started via:

-
cd <top>/iocBoot/ioctest
-../../bin/linux-x86_64/test st.cmd
-

- This starts two versions of echoDriver as port "A" and "B". port A acts as single - device port. port B acts as a multiDevice port that has two devices. For each of - the three possible devices, the st.cmd file starts up two sets of records from test.db - The st.cmd file also loads a set of records from asynTest.db for port A and for - port B and for each of the two devices attached to port B. It also loads a set of - records from asynRecord.db. It starts one version of addrChangeDriver which connects - to port A.

-

- It loads six versions of test.db and four versions of testBlock.db The test.adl - file attaches to these database records.

-

- testArrayRingBufferApp

-

- This tests ring buffers for callbacks with arrays. The example resides in <top>/testArrayRingBufferApp. -

-

- Executing "medm -x testArrayRingBufferTop.adl" produces a top-level display from - which this display can be opened:

-
-

- asynTestArrayRingBuffer.png

-
-

- It assumes that an ioc has been started via:

-
cd <top>/iocBoot/ioctestArrayRingBuffer
-../../bin/linux-x86_64/testArrayRingBuffer st.cmd
-

- testAsynPortClientApp

-

- This is a test program that demonstrates how to write C++ program that instantiates - both an asyn port driver and an asynPortClient object. It uses the asynPortClient - object to communicate with the asyn port driver directly over the asyn interfaces - without running an EPICS IOC. It creates an asynIPPort driver and an asynPortClient, - 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 provided that - show how to use testAsynIPPortClient to communicate with a Web server, a Newport - XPS motor controller, and a telnet host respectively.

-

- Usage: testAsynIPPortClient hostInfo outputString [outputEos] [inputEos]

-

- Example: testAsynIPPortClient cars.uchicago.edu:80 "GET / HTTP/1.0" "\n\n"

-

- The example resides in <top>/testAsynPortClientApp.

-

- testAsynPortDriverApp

-

- This test demonstrates how to write a driver using the asynPortDriver C++ class. - It consists of a simple digital oscilloscope simulator. When the vertical gain changes - the driver does callbacks on the enum choices for the vertical volts/division. This - requires closing and re-opening the display in medm, because Channel Access does - not do monitors on enum value changes.

-

- The example resides in <top>/testAsynPortDriverApp. -

-

- Executing "medm -x testAsynPortDriverTop.adl" produces a top-level display from - which this display can be opened:

-
-

- testAsynPortDriver.png

-
-

- It assumes that an ioc has been started via:

-
cd <top>/iocBoot/ioctestAsynPortDriver
-../../bin/linux-x86_64/testAsynPortDriver st.cmd
-

- testBroadcastApp

-

- This application contains 3 test programs that use UDP IP broadcast messages.

-

- testBroadcastAsyn.c
- This program uses drvAsynIPPort to send UDP broadcast messages on port 37747. The - message is "i\n". It then listens for any responses. If there are NSLS electrometers - on the network they should respond.

-

- testBroadcastNoAsyn.c
- This program does the same as testBroadcastAsyn.c but uses native socket calls rather - than drvAsynIPort.

-

- testBroadcastBurst.c
- This program is used to test the behavior of devices in the presence of large amounts - of broadcast traffic. It should be used with caution, since it can send a large - number of broadcast messages very quickly. It sends numBroadcast messages with no - delay. The messages is "test\r". It does this in a loop of numLoops with a delay - of delayTime seconds at the end of each loop. delayTime is floating point value, - so can be less than 1 second.
- Usage: testBroadcastBurst broadcastAddress broadcastPort numBroadcast numLoops delayTime

-

- The code resides in <top>/testBroadcastApp.

-

- testConnectApp

-

- This application can be used to test connection management. It connects to a device - with drvAsynIPPort and periodically writes to it in a background thread. Depending - on whether the device is connected error messages will be printed. The device can - be connected and disconnected by power-cycling or removing the network cable to - test the behavior.

-

- The example resides in <top>/testConnectApp. -

-

- The test ioc can be started via:

-
cd <top>/iocBoot/ioctestConnect
-../../bin/linux-x86_64/testConnect st.cmd
-

- The st.cmd file can be edited to select devices which will or will not ever connect. - There is no medm screen for this test.

-

- testEpicsApp

-

- This test includes example asyn port drivers for the asynInt32 and asynUInt32Digital - interfaces. Both drivers also implement the asynFloat64 interface for controlling - the update rate. The testEpicsApp application also uses the asynOctet echoDriver - from testApp. -

-

- The example resides in <top>/testEpicsApp. -

-

- Executing "medm -x *.adl" from the <top>/testEpicsApp/adl directory opens - the followings displays.

-
-

- testInt32.png

-

- testDigital.png

-

- testOctet.png

-
-

- From the testInt32.adl screen the following time-series screen can be opened.

-
-

- asynTimeSeries.png

-
-

- It assumes that an ioc has been started via:

-
cd <top>/iocBoot/ioctestEpics
-../../bin/linux-x86_64/testEpics st.cmd
-

- testErrorsApp

-

- This tests error handling in standard asyn device support. The user can control - the status and severity for write operations, read operations, and interrupt callbacks. - It tests all of the interfaces (asynInt32, asynUInt32Digital, asynFloat64, asynOctet, - asynEnum, asynXXXArray (XXX=Int8, Int16, Int32, Float32, Float64). It tests output - records both with an without the info tag asyn:READBACK. By editing options in the - st.cmd file it also tests:

-
    -
  • Synchronous and asynchronous driver operation (ASYN_CANBLOCK unset or set)
  • -
  • String and waveform records with or without ring buffer support(asyn:FIFO=0 or - 5)
  • -
  • Record .TSE field 0 (default timestamp support) or -2 (records get their timestamps - from the driver)
  • -
  • Periodic or I/O Intr scanning of input records.
  • -
-

- The example resides in <top>/testEpicsApp. -

-

- Executing "medm -x testErrorsTop.adl" from the <top>/testEerrorsApp/adl directory - produces a top-level display from which this display can be opened:

-
-

- testErrors.png

-
-

- It assumes that an ioc has been started via:

-
cd <top>/iocBoot/ioctestErrors
-../../bin/linux-x86_64/testErrors st.cmd
-

- Install and Build

-

- Install and Build asynDriver

-

- After obtaining a copy of the distribution, it must be installed and built for use - at your site. These steps only need to be performed once for the site (unless versions - of the module running under different releases of EPICS and/or the other required - modules are needed).

-
    -
  1. Create an installation directory for the module, usually this will end with -
    .../support/asyn/
    -
  2. -
  3. Place the distribution file in this directory. Then issue the commands (Unix style) -
    gunzip <file>.tar.gz
    -tar xvf <file>.tar
    -
  4. -
  5. This creates a support <top>. -
    .../support/asyn/X-Y
    - where X-Y is the release number. For example: -
    .../support/asyn/3-1
    -
  6. -
  7. Edit the config/RELEASE file and set the paths to your installation of - EPICS_BASE and IPAC. IPAC is only needed if you are building for vxWorks.
  8. -
  9. Run make in the top level directory and check for any compilation errors.
  10. -
-

- Using asynDriver Components with an EPICS iocCore Application

-

- Since asynDriver does NOT provide support for specific devices an application must - obtain device specific support elsewhere. This section only explains how to include - asynDriver components.

-

- In the configure/RELEASE file add definitions for IPAC, - ASYN, and EPICS_BASE.

-

- In the src directory where the application is built:

-
    -
  • Add the following to Makefile -
            <app>_LIBS += asyn
    -    
    -
  • -
  • The application database definition file must include the database definition - files for the stream package and for any needed ASYN drivers. There are two ways - that this can be done:
    -
      -
    • If you are building your application database definition file from the application - Makefile you specify the aditional database definitions there (uncomment the lines - appropriate to your application): -
                include "asyn.dbd"
      -          #include "drvAsynSerialPort.dbd"
      -          #include "drvAsynIPPort.dbd"
      -          #include "drvVxi11.dbd"
      -          #include "drvGsIP488.dbd"
      -          #include "drvIpac.dbd"
      -          #include "drvUSBTMC.dbd"
      -          
      -
    • -
    • If you are building your application database definition file from the application - Makefile you specify the aditional database definitions there (again, uncomment - the lines appropriate to your application): -
                xxx_DBD += asyn.dbd
      -          #xxx_DBD += drvAsynSerialPort.dbd
      -          #xxx_DBD += drvAsynIPPort.dbd
      -          #xxx_DBD += drvVxi11.dbd
      -          #xxx_DBD += drvGsIP488.dbd
      -          #xxx_DBD += drvIpac.dbd
      -          #xxx_DBD += drvUSBTMC.dbd
      -          
      -
    • -
    -
  • -
-

- In the st.cmd file add:

-

- dbLoadRecords("db/asynRecord.db", "P=<ioc>, R=<record>, PORT=<port>, - ADDR=<addr>, OMAX=<omax>, IMAX=<imax>")

-

- You must provide values for <ioc>, <record>, <port>, <addr>, - <omax>, and <imax>.

-

- Once the application is running, medm displays for an ioc can be started by: medm - -x -macro "P=<ioc>,R=<record>" <asyntop>/medm/asynRecord.adl &

-

- You must provide correct values for <ioc> and <record>. Once asynRecord - is started, it can be connected to different devices.

-
-

- License Agreement

-
Copyright (c) 2002 University of Chicago All rights reserved.
-asynDriver is distributed subject to the following license conditions:
-
-SOFTWARE LICENSE AGREEMENT
-Software: asynDriver
-
- 1. The "Software", below, refers to asynDriver (in either source code, or
-    binary form and accompanying documentation). Each licensee is
-    addressed as "you" or "Licensee."
-
- 2. The copyright holders shown above and their third-party licensors
-    hereby grant Licensee a royalty-free nonexclusive license, subject to
-    the limitations stated herein and U.S. Government license rights.
-
- 3. You may modify and make a copy or copies of the Software for use
-    within your organization, if you meet the following conditions:
-      a. Copies in source code must include the copyright notice and this
-         Software License Agreement.
-      b. Copies in binary form must include the copyright notice and this
-         Software License Agreement in the documentation and/or other
-         materials provided with the copy.
-
- 4. You may modify a copy or copies of the Software or any portion of it,
-    thus forming a work based on the Software, and distribute copies of
-    such work outside your organization, if you meet all of the following
-    conditions:
-      a. Copies in source code must include the copyright notice and this
-         Software License Agreement;
-      b. Copies in binary form must include the copyright notice and this
-         Software License Agreement in the documentation and/or other
-         materials provided with the copy;
-      c. Modified copies and works based on the Software must carry
-         prominent notices stating that you changed specified portions of
-         the Software.
-
- 5. Portions of the Software resulted from work developed under a U.S.
-    Government contract and are subject to the following license: the
-    Government is granted for itself and others acting on its behalf a
-    paid-up, nonexclusive, irrevocable worldwide license in this computer
-    software to reproduce, prepare derivative works, and perform publicly
-    and display publicly.
-
- 6. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY
-    OF ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY LICENSORS, THE
-    UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND THEIR
-    EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
-    BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-    FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME
-    ANY LEGAL LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS,
-    OR USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE
-    SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT
-    THAT THE SOFTWARE WILL FUNCTION UNINTERRUPTED, THAT IT IS ERROR-FREE
-    OR THAT ANY ERRORS WILL BE CORRECTED.
-
- 7. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, THEIR
-    THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT
-    OF ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
-    CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF ANY KIND OR NATURE,
-    INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS OR LOSS OF DATA, FOR ANY
-    REASON WHATSOEVER, WHETHER SUCH LIABILITY IS ASSERTED ON THE BASIS OF
-    CONTRACT, TORT (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR
-    OTHERWISE, EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE
-    POSSIBILITY OF SUCH LOSS OR DAMAGES.
- - diff --git a/documentation/asynPortClient.html b/documentation/asynPortClient.html deleted file mode 100755 index a82fb94..0000000 --- a/documentation/asynPortClient.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - asynPortClient - - - -
-

- asynPortClient

-

- C++ Base Class for Asyn Port Clients

-

- January 26, 2019

-

- Mark Rivers

-

- University of Chicago

-
-

- asynPortClient is a set of C++ classes that are designed to simplify the task of - writing a client that directly communicates with an asyn port driver, without running - an EPICS IOC. They handle the details of connecting to the driver, finding the required - interfaces, etc. They only use the synchronous interfaces, so all calls are blocking. - If clients need asynchronous operation then they can use the normal C interface - with pasynManager->queueRequest.

-

- asynPortClient provides a base class, asynParamClient, from which interface-specific - class are derived. It also provides a class for each of the standard asyn interfaces, - (asynInt32Client, asynFloat64Client, asynCommonClient, asynEnumClient, etc.).

-

- The asynPortClient class connects to a specific asynPortDriver object. It creates - an asynParamClient derived class 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 generic 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.

-

- The detailed documentation for asynPortClient is in these files (generated by doxygen):

- -

- The example driver in asyn (testAsynPortClient) is a simple example of how to use - this class.

-

- Another example can be found in ADSimDetector/iocs/simDetectorNoIOC found in the - areaDetector module. -

-

- Example client - testAsynPortClient

-

- An example client using the asynPortClientclass is provided in the testAsynPortClientApp - application in asyn. 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.

- - diff --git a/documentation/asynPortDriver.html b/documentation/asynPortDriver.html deleted file mode 100644 index dbd50e7..0000000 --- a/documentation/asynPortDriver.html +++ /dev/null @@ -1,469 +0,0 @@ - - - - asynPortDriver - - - -
-

- asynPortDriver

-

- C++ Base Class for Asyn Port Drivers

-

- September 15, 2017

-

- Mark Rivers

-

- University of Chicago

-
-

- asynPortDriver is a base C++ class that is designed to greatly simplify the task - of writing an asyn port driver. It handles all of the details of registering the - port driver, registering the supported interfaces, and registering the required - interrupt sources. -

-

- Drivers typically need to support a number of parameters that control their operation - and provide status information. Most of these can be treated as 32-bit integers, - 64-bit floats, or strings. When the new value of a parameter is sent to a driver, - (e.g. new D/A output value) from an asyn client (e.g. an EPICS record), then the - driver will need to take some action. It may change some other parameters in response - to this new value. The sequence of operations in the driver can be summarized as -

-
    -
  1. New parameter value arrives, or new data arrives from a device.
  2. -
  3. Change values of one or more parameters.
  4. -
  5. For each parameter whose value changes set a flag noting that it changed.
  6. -
  7. When operation is complete, call the registered callbacks for each changed parameter.
  8. -
-

- asynPortDriver provides methods to simplify the above sequence, which must be implemented - for each of the often many parameters that the driver supports. Each parameter is - assigned a number, which is the value in the pasynUser->reason field that asyn - clients pass to the driver when reading or writing that parameter. asynPortDriver - maintains a table of parameter values, associating each parameter number with a - data type (integer, UInt32Digital, double, or string), caching the current value, - and maintaining a flag indicating if a value has changed. Drivers use asynPortDriver - methods to read the current value from the table, and to set new values in the table. - There is a method to call all registered callbacks for values that have changed - since callbacks were last done. -

-

- The detailed documentation for asynPortDriver is in these files (generated by doxygen):

- -

- The example driver in asyn (testAsynPortDriver) is a simple example of how to use - this class

-

- The synApps measComp - module contains a detailed example of writing an asynPortDriver driver. The - driver is for the Measurement Computing USB-1608GX-2AO USB device. The example starts - with a very simple driver that only uses a few of the features of the device, and - is fewer than 150 lines of code. There are 5 versions of the driver that each add - additional features. There is a document describing the code for each driver in - detail, which was the basis of a talk at an EPICS short course on asyn. The following - are links to this example:

- -

- More complex examples can be found in the drivers and plugins provided with the - areaDetector - module. -

-

- Example driver - testAsynPortDriver

-

- An example driver using the asynPortDriver class is provided in the testAsynPortDriverApp - application in asyn. This example is a simple digital oscilloscope emulator. In - this example all of output control and input data is done in a calculated simulation. - But it is easy to see how to use the driver as a basis for real device control. - The code doing the simulation would simply be changed to talk to an actual device. - This could be done using the asyn serial or IP drivers via the asynOctetSyncIO interface - (because at this driver level blocking is permitted), or via VME register access, - or any other I/O mechanism.

-

- This is the medm screen for controlling this example application. It is started - in the testAsynPortDriverApp/adl directory with the command:

-
 medm -x -macro "P=testAPD:, R=scope1:" testAsynPortDriver.adl &
- 
-
-

- testAsynPortDriver.adl

-

- testAsynPortDriver.png

-
-

- The simulated scope input is a noisy 1kHz sin wave with an amplitude of +-1V. The - amplitude of the noise is an adjustable parameter. The scope parameters that can - be adjusted are the vertical volts/division, vertical volt offset, horizontal time/division, - trigger delay (relative to time=0 for the sin wave). The minimum, maximum and mean - values of the waveform are calculated. The run/stop control turns the simulation - of the waveform on and off. The update time in seconds controls the rate at which - the waveform and statistics are calculated. By default all of the EPICS input records - are I/O Intr scanned. There is a control on the medm screen to change the scan rate - of the waveform record itself. By default it is also I/O Intr scanned, so the plot - updates on every simulation. One can change this to, for example, 1 second, and - then the simulation can be running faster (for example 50 Hz, Update time=.02) so - the statistics will update quickly but the waveform at only 1Hz to save CPU time - and network bandwidth.

-

- This driver supports about 20 EPICS records, including ao, ai, bo, bi, and waveform. - It does callbacks to device support when any of the input records changes, so the - records can use I/O Intr scanning rather than polling. It uses only the standard - asyn EPICS record device support provided as part of asyn. Yet the driver is only - about 340 lines of well-commented C++ code, because so much of the infrastructure - is handled by the asynPortDriver base class.

-

- Here are the important lines from the startup script to start this IOC:

-
testAsynPortDriverConfigure("testAPD", 1000)
-dbLoadRecords("../../db/testAsynPortDriver.db","P=testAPD:,R=scope1:,PORT=testAPD,ADDR=0,TIMEOUT=1,NPOINTS=1000")
-
-

- The first line starts the asyn port driver with a 1000 point waveform. The second - line loads the database. The PORT parameter is the name of the asyn port created - in the first line. The ADDR parameter is 0 because this driver is not ASYN_MULTIDEVICE, - it only supports a single address. The TIMEOUT parameter is not really significant - because this is a synchronous asyn port driver, i.e. ASYN_CANBLOCK=0. NPOINTS is - the value for NELM in the waveform record in the database. It would normally match - the value provided in the configure command above.

-

- This is an example of 2 of the record definitions in the database file, testAsynPortDriver.db.

-
###################################################################
-#  These records are the time per division                        #
-###################################################################
-record(ao, "$(P)$(R)TimePerDiv")
-{
-   field(PINI, "1")
-   field(DTYP, "asynFloat64")
-   field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))SCOPE_TIME_PER_DIV")
-   field(PREC, "5")
-}
-
-record(ai, "$(P)$(R)TimePerDiv_RBV")
-{
-   field(PINI, "1")
-   field(DTYP, "asynFloat64")
-   field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))SCOPE_TIME_PER_DIV")
-   field(PREC, "5")
-   field(SCAN, "I/O Intr")
-}
-
-

- Note that there is both an output record and an input record for this parameter, - the time per horizontal division. This is done so that if the driver is forced to - modify a parameter (for example because the device cannot support the output value - it received) there is feedback to the user on the actual value being used. In this - case the ai record will always be the same as the ao record. But in the case of - the update time parameter the driver enforces a minimum time of 0.02 seconds, so - that if a value less than this is requested the ao and ai records will not agree. - In that particular case DRVL could be used to enforce that limit at the ao record - level, but this is not always the case, because device limits can vary with the - value of other parameters.

-

- The DTYP field of these records is asynFloat64, which uses the standard asyn device - support for ao and ai records, provided in asyn/devEpics/devAsynFloat64.c.

-

- The OUT and INP fields use the PORT, ADDR and TIMEOUT values described above. The - final parameter, SCOPE_TIME_PER_DIV in these fields is used by the driver to identify - which driver parameter these records are connected to. This is the asyn drvInfo - parameter, and is discussed below.

-

- Finally, note that the ai record has SCAN=I/O Intr. This means that this record - does not have to be periodically scanned (which is inefficient), but rather it will - be processed whenever its value is changed by the driver. For the ai statistics - records (min, max, mean) in this example,,. record callbacks occur every time the - simulation runs if the noise is non-zero.

-

- This is the definition of the testAsynPortDriver class:

-
class testAsynPortDriver : public asynPortDriver {
-public:
-    testAsynPortDriver(const char *portName, int maxArraySize);
-
-    /* These are the methods that we override from asynPortDriver */
-    virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
-    virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
-    virtual asynStatus readFloat64Array(asynUser *pasynUser, epicsFloat64 *value,
-                                        size_t nElements, size_t *nIn);
-    virtual asynStatus readEnum(asynUser *pasynUser, char *strings[], int values[], int severities[],
-                                size_t nElements, size_t *nIn);
-
-    /* These are the methods that are new to this class */
-    void simTask(void);
-
-protected:
-    /** Values used for pasynUser->reason, and indexes into the parameter library. */
-    int P_Run;
-    int P_MaxPoints;
-    int P_TimePerDiv;
-    int P_TimePerDivSelect;
-    int P_VertGain;
-    int P_VertGainSelect;
-    int P_VoltsPerDiv;
-    int P_VoltsPerDivSelect;
-    int P_VoltOffset;
-    int P_TriggerDelay;
-    int P_NoiseAmplitude;
-    int P_UpdateTime;
-    int P_Waveform;
-    int P_TimeBase;
-    int P_MinValue;
-    int P_MaxValue;
-    int P_MeanValue;
-
-private:
-    /* Our data */
-    epicsEventId eventId_;
-    epicsFloat64 *pData_;
-    epicsFloat64 *pTimeBase_;
-    // Actual volts per division are these values divided by vertical gain
-    char *voltsPerDivStrings_[NUM_VERT_SELECTIONS];
-    int voltsPerDivValues_[NUM_VERT_SELECTIONS];
-    int voltsPerDivSeverities_[NUM_VERT_SELECTIONS];
-    void setVertGain();
-    void setVoltsPerDiv();
-    void setTimePerDiv();
-};
-
-

- testAsynPortDriver is derived from asynPortDriver. It overrides the methods writeInt32, - writeFloat64, readFloat64Array, and drvUserCreate. It adds a new method, simTask, - which runs a separate thread to compute the waveform at the specified update time.

-

- This is the how the parameters are defined in the driver, testAsynPortDriver.cpp

-
/* These are the drvInfo strings that are used to identify the parameters.
- * They are used by asyn clients, including standard asyn device support */
-#define P_RunString                "SCOPE_RUN"             /* asynInt32,    r/w */
-#define P_MaxPointsString          "SCOPE_MAX_POINTS"      /* asynInt32,    r/o */
-#define P_TimePerDivisionString    "SCOPE_TIME_PER_DIV"    /* asynFloat64,  r/w */
-#define P_VoltsPerDivisionString   "SCOPE_VOLTS_PER_DIV"   /* asynFloat64,  r/w */
-#define P_VoltOffsetString         "SCOPE_VOLT_OFFSET"     /* asynFloat64,  r/w */
-#define P_TriggerDelayString       "SCOPE_TRIGGER_DELAY"   /* asynFloat64,  r/w */
-#define P_NoiseAmplitudeString     "SCOPE_NOISE_AMPLITUDE" /* asynFloat64,  r/w */
-#define P_UpdateTimeString         "SCOPE_UPDATE_TIME"     /* asynFloat64,  r/w */
-#define P_WaveformString           "SCOPE_WAVEFORM"        /* asynFloat64Array,  r/o */
-#define P_TimeBaseString           "SCOPE_TIME_BASE"       /* asynFloat64Array,  r/o */
-#define P_MinValueString           "SCOPE_MIN_VALUE"       /* asynFloat64,  r/o */
-#define P_MaxValueString           "SCOPE_MAX_VALUE"       /* asynFloat64,  r/o */
-#define P_MeanValueString          "SCOPE_MEAN_VALUE"      /* asynFloat64,  r/o */
-
-

- Note that each parameter has an integer value that identifies it. It is also associated - with a string that is used in the drvInfo field of the record INP or OUT fields - to associate a record with a parameter.

-

- This is the beginning of the constructor for the testAsynPortDriver C++ class.

-
testAsynPortDriver::testAsynPortDriver(const char *portName, int maxPoints)
-   : asynPortDriver(portName,
-                    1, /* maxAddr */
-                    asynInt32Mask | asynFloat64Mask | asynFloat64ArrayMask | asynEnumMask | asynDrvUserMask, /* Interface mask */
-                    asynInt32Mask | asynFloat64Mask | asynFloat64ArrayMask | asynEnumMask,  /* Interrupt mask */
-                    0, /* asynFlags.  This driver does not block and it is not multi-device, so flag is 0 */
-                    1, /* Autoconnect */
-                    0, /* Default priority */
-                    0) /* Default stack size*/
-...
-
-

- It invokes the constructor for the asynPortDriver base class. It passes:

-
    -
  • The portName, which is the name of the asyn port to be created. In the st.cmd - file above this is "testAPD".
  • -
  • The maximum number of asyn addresses that this driver supports, which is 1.
  • -
  • A mask which defines which asyn interfaces this driver supports, in this case - asynInt32, asynFloat64, asynFloat64Array, and asynDrvUser. All drivers must support - asynCommon, so that bit is added in the base class.
  • -
  • A mask which defines which asyn interfaces can generate interrupts (callbacks). - In this case that is asynInt32, asynFloat64, and asynFloat64Array.
  • -
  • A mask which defines the asyn attributes for this driver. asyn currently defines - two attribute bits, ASYN_CANBLOCK and ASYN_MULTIDEVICE. ASYN_CANBLOCK must be set - for drivers that perform "slow" operations on their interfaces, requiring asynManager - to create a separate port thread for them and to use asynchronous device support. - ASYN_MULTIDEVICE must be set for drivers that support more than one asyn address, - for example a driver used to support a 16-channel A/D converter.
  • -
  • A flag to tell asynManager that it should automatically attempt to connect to - this device when a call is made on its interfaces. This results in a call to asynCommon->connect().
  • -
  • A priority flag for the port thread that asynManager will create if ASYN_CANBLOCK - is 1. If this is 0 then asyn will use a default medium thread priority.
  • -
  • The stack size for the port thread that asynManager will create if ASYN_CANBLOCK - is 1. If this is 0 then asyn will use a default medium thread stack size.
  • -
-

- The constructor also allocates spaces for the waveform arrays (X and Y axes), and - creates the simTask thread.

-

- This is the implementation of the writeFloat64 function:

-
asynStatus testAsynPortDriver::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
-{
-    int function = pasynUser->reason;
-    asynStatus status = asynSuccess;
-    epicsInt32 run;
-    const char *paramName;
-    const char* functionName = "writeFloat64";
-
-    /* Set the parameter in the parameter library. */
-    status = (asynStatus) setDoubleParam(function, value);
-
-    /* Fetch the parameter string name for possible use in debugging */
-    getParamName(function, &paramName);
-
-    if (function == P_UpdateTime) {
-        /* Make sure the update time is valid. If not change it and put back in parameter library */
-        if (value < MIN_UPDATE_TIME) {
-            asynPrint(pasynUser, ASYN_TRACE_WARNING,
-                "%s:%s: warning, update time too small, changed from %f to %f\n",
-                driverName, functionName, value, MIN_UPDATE_TIME);
-            value = MIN_UPDATE_TIME;
-            setDoubleParam(P_UpdateTime, value);
-        }
-        /* If the update time has changed and we are running then wake up the simulation task */
-        getIntegerParam(P_Run, &run);
-        if (run) epicsEventSignal(eventId_);
-    } else {
-        /* All other parameters just get set in parameter list, no need to
-         * act on them here */
-    }
-
-    /* Do callbacks so higher layers see any changes */
-    status = (asynStatus) callParamCallbacks();
-
-    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",
-              driverName, functionName, function, paramName, value);
-    return status;
-}
-
-

- This is what is being performed in this function:

-
    -
  • The pasynUser->reason field is used to get the value of function. - This is one of the parameter indices (e.g. P_TimePerDivision). It was placed in - the pasynUser->reason field by this driver's drvUserCreate method that was called - at iocInit, and was passed the drvUser field from the record link, e.g. "SCOPE_TIME_PER_DIV".
  • -
  • The value passed is set in the parameter list with setDoubleParam.
  • -
  • A series of if statements that processes each of the parameters differently. In - this case only one float64 parameter, P_UpdateTime, needs to actually have any action - taken in this function. All other parameters just have their values set in the parameter - list for later use.
  • -
  • For P_UpdateTime the value is checked for validity to make sure it is greater - than MIN_UPDATE_TIME. If not then the value is changed, and the new value is written - to the parameter list. This new value will be passed in callbacks to any callback - clients, for example an ai record that is monitoring this parameter. The function - then retrieves the value of the P_Run parameter from the parameter list, and if - it is 1 it sends an EPICS event signal to wake up the simTask. This is done so that - if the update time is changed from a very long value to a shorter one then it does - not wait for the long timer to expire.
  • -
  • callParamCallbacks() is called, which results in callbacks to all - registered clients for any parameters that have changed as a result of this function - call. In this case the only parameter that will have changed is whatever parameter - was passed in pasynUser->reason, but in general other parameters could have changed - as a side-effect of changing this parameter.
  • -
  • Diagnostic information is optionally printed for both error and success status.
  • -
-

- The writeInt32 function is very similar.

-

- Finally here is the simTask function, which actually does the simulation. - It runs in a separate thread created in the constructor:

-
void testAsynPortDriver::simTask(void)
-{
-    /* This thread computes the waveform and does callbacks with it */
-
-    double timePerDiv, voltsPerDiv, voltOffset, triggerDelay, noiseAmplitude;
-    double updateTime, minValue, maxValue, meanValue;
-    double time, timeStep;
-    double noise, yScale;
-    epicsInt32 run, i, maxPoints;
-    double pi=4.0*atan(1.0);
-
-    lock();
-    /* Loop forever */
-    while (1) {
-        getDoubleParam(P_UpdateTime, &updateTime);
-        getIntegerParam(P_Run, &run);
-        // Release the lock while we wait for a command to start or wait for updateTime
-        unlock();
-        if (run) epicsEventWaitWithTimeout(eventId_, updateTime);
-        else     (void) epicsEventWait(eventId_);
-        // Take the lock again
-        lock();
-        /* run could have changed while we were waiting */
-        getIntegerParam(P_Run, &run);
-        if (!run) continue;
-        getIntegerParam(P_MaxPoints,        &maxPoints);
-        getDoubleParam (P_TimePerDiv,       &timePerDiv);
-        getDoubleParam (P_VoltsPerDiv,      &voltsPerDiv);
-        getDoubleParam (P_VoltOffset,       &voltOffset);
-        getDoubleParam (P_TriggerDelay,     &triggerDelay);
-        getDoubleParam (P_NoiseAmplitude,   &noiseAmplitude);
-        time = triggerDelay;
-        timeStep = timePerDiv * NUM_DIVISIONS / maxPoints;
-        minValue = 1e6;
-        maxValue = -1e6;
-        meanValue = 0.;
-
-        yScale = 1.0 / voltsPerDiv;
-        for (i=0; i<maxPoints; i++) {
-            noise = noiseAmplitude * (rand()/(double)RAND_MAX - 0.5);
-            pData_[i] = AMPLITUDE * (sin(time*FREQUENCY*2*pi)) + noise;
-            /* Compute statistics before doing the yOffset and yScale */
-            if (pData_[i] < minValue) minValue = pData_[i];
-            if (pData_[i] > maxValue) maxValue = pData_[i];
-            meanValue += pData_[i];
-            pData_[i] = NUM_DIVISIONS/2 + yScale * (voltOffset + pData_[i]);
-            time += timeStep;
-        }
-        updateTimeStamp();
-        meanValue = meanValue/maxPoints;
-        setDoubleParam(P_MinValue, minValue);
-        setDoubleParam(P_MaxValue, maxValue);
-        setDoubleParam(P_MeanValue, meanValue);
-        callParamCallbacks();
-        doCallbacksFloat64Array(pData_, maxPoints, P_Waveform, 0);
-    }
-}
-
-

- Here are the important aspects of this function:

-
    -
  • The value of P_Run determines whether the simulation is running or - stopped. If stopped it simply waits for a signal (from the writeInt32() - function) to start running. If running it waits for the update time, or until it - receives a signal, which will occur if the update time is changed in the writeFloat64() - function.
  • -
  • It reads the values of the simulation parameters (P_TimePerDivision, - etc.) from the parameter list.
  • -
  • It computes each point in the waveform inside the for loop, using - the current values of the simulation parameters. It also updates the statistics - parameters (min, max, mean) inside this loop.
  • -
  • After the loop is done the new values of the statistics parameters are written - to the parameter list with setDoubleParam().
  • -
  • New values of all scalar parameters (int32, float64, string) in the parameter - list are sent to registered clients (e.g. asyn device support for input records) - with the call to callParamCallbacks().
  • -
  • The new value of the waveform is sent to registered clients (e.g. device support - for the waveform input record) with the call to doCallbacksFloat64Array().
  • -
-

- Real drivers may or may not need such a separate thread. Drivers that need to periodically - poll status information will probably use one. Most drivers will probably implement - one or more of the writeInt32(), writeFloat64(), or - writeOctet() functions, in addition to drvUserCreate().

- - diff --git a/documentation/asynRecord.html b/documentation/asynRecord.html deleted file mode 100644 index 9ec97ef..0000000 --- a/documentation/asynRecord.html +++ /dev/null @@ -1,2042 +0,0 @@ - - - - asyn - asyn Record - - - -
-

- asyn Record

-
- Mark Rivers and Marty Kraimer -
-
-
-

- Contents

- -

- Overview

-

- The asyn record is designed to provide access to nearly all of the features of the - asyn facility. It includes the ability to:

-
    -
  • Perform I/O to any asyn device that supports the asynOctet, asynInt32, asynUInt32Digital, - and/or asynFloat64 interfaces.
  • -
  • Allow EPICS to communicate with a new device without rebooting the IOC, i.e. without - writing any C code or changing the database. This allows Channel Access clients - to communicate with devices for which no EPICS device support exists.
  • -
  • In combination with the scalcout record to format output strings and to parse - response strings, eliminate the need for C device support code in many applications.
  • -
  • Dynamically change the asyn device "port" and "address", so a single asyn record - can be switched from talking to one device to another at run time.
  • -
  • Dynamically change the asyn interface being used for I/O.
  • -
  • Manage the connection state of a device, i.e. connect/disconnect, enable/disable, - autoConnect/noAutoConnect..
  • -
  • Provide access to asynTrace, controlling debugging output for any asyn device.
  • -
  • Control the the baud rate, parity, etc. for serial ports whose drivers support - the asynOption interface.
  • -
  • Control the GPIB address and execute global and addressed commands for GPIB devices.
  • -
-

- For the asynOctet interface there are two output fields, AOUT (ASCII Output) and - BOUT (Byte Output). The OFMT (Output Format) field is used to select one of these - fields or the other as the output source to the device. Similarly, there are two - input fields, AINP (ASCII Input) and BINP (Byte Input). The IFMT (Input Format) - field is used to select one or the other as the destination of data sent from the - device. The ASCII fields are type DBF_STRING, and are very convenient for typical - communication with many devices. They permit, for example, medm screens - where the user can type a string and observe the response from the instrument. The - ASCII fields, however are limited to 40 characters in length, and cannot be used - to read or write binary data. The byte input and output fields are DBF_CHAR arrays, - and can be used to transfer large blocks of arbitrary data, either ASCII or binary.

-

-

-

- In the "Access" columns in the field description tables: -

- - - - - - - - - - - - - - - - - - - - - - - -
- R - Read only -
- R/W - Read and write are allowed -
- R/W* - Read and write are allowed; write triggers record processing if the record's SCAN - field is set to "Passive". -
- N - No access allowed -
-

-

-
-

- Device Address Control Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Name - Access - Prompt - Data type - Description
- PORT - R/W - "asyn port" - DBF_STRING - The asyn "port" name. This field can be changed at any time to connect the record - to another asyn device.
- ADDR - R/W - "asyn address" - DBF_LONG - The asyn address. This field can be changed at any time to connect the record to - another asyn device.
- PCNCT - R/W - "Port Connect/Disconnect" - DBF_MENU - Disconnects or connects the port. Choices are "Disconnect" and "Connect". The value - read reflects whether there is currently a valid connection to a port.
- DRVINFO - R/W - "Driver information" - DBF_STRING - A string that is passed to the driver with asynDrvUser->create(), assuming that - the asynDrvUser interface exists. The driver will update pasynUser->reason and/or - pasynUser->drvUser as a result. If pasynUser->reason is changed then the asynRecord - REASON field will be updated.
- REASON - R/W - "Reason or command" - DBF_LONG - A integer "reason" or "command" that is typically used to tell the driver what item - to read or write. This value is updated when connecting to the driver, using the - DRVINFO field. It can be changed later without reconnecting to the driver. If REASON - is changed then the DRVINFO field will be set to an empty string.
-

- The asyn record does not have traditional INP or OUT fields for input and output - links. Rather it provides the PORT and ADDR fields to allow dynamically changing - what asyn device the record is connected to. -

-

- Writing to the PORT, ADDR or DRVINFO fields causes the asyn record to disconnect - from the current device and connect to the specified asyn port and address. This - permits a single asyn record to be used to control any asyn device. Writing to these - fields does not cause any I/O to be done.

-

- Note that since writing to the PORT, ADDR, or DRVINFO fields cause the record to - automatically attempt to connect to the port, it is usually not necessary to write - to the PCNCT field to connect to the port. The PCNCT field is useful for determining - if the port is connected, and for forcing a disconnect if desired.

-

-

-
-

- Input/Output Control Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Name - Access - Prompt - Data type - Description
- VAL - R/W - "Value field (unused)" - DBF_STRING - This field is unused. The functions normally assigned to the VAL field in many records - are performed by the AOUT, BOUT, AINP, BINP, I32OUT, I32INP, UI32OUT, UI32INP, F64OUT, - and F64INP fields in the asyn record.
- TMOD - R/W - "Transaction mode" - DBF_MENU - The type of I/O transaction to perform when the record is processed. The choices - are: - - - - - - - - - - - - - - - - - - -
- "Write/Read" (default)
- "Write"
- "Read"
- "Flush"
- "NoI/O"
-
- IFACE - R/W - "Interface" - DBF_MENU - The interface to use for the I/O transfer when the record processes. The choices - are: - - - - - - - - - - - - - - - -
- "asynOctet" (default)
- "asynInt32"
- "asynUInt32Digital"
- "asynFloat64"
-
- OCTETIV - R - "Octet Is Valid" - DBF_LONG - This field is (1,0) if the driver (does,does not) support the asynOctet interface. -
- I32IV - R - "Int32 Is Valid" - DBF_LONG - This field is (1,0) if the driver (does,does not) support the asynInt32 interface. -
- UI32IV - R - "UInt32Digital Is Valid" - DBF_LONG - This field is (1,0) if the driver (does,does not) support the asynUInt32Digital - interface.
- F64IV - R - "Float64 Is Valid" - DBF_LONG - This field is (1,0) if the driver (does,does not) support the asynFloat64 interface. -
- OPTIONIV - R - "Option Is Valid" - DBF_LONG - This field is (1,0) if the driver (does,does not) support the asynOption interface. -
- GPIBIV - R - "GPIB Is Valid" - DBF_LONG - This field is (1,0) if the driver (does,does not) support the asynGPIB interface. -
- TMOT - R/W - "Timeout (sec)" - DBF_DOUBLE - The timeout value for read and write operations in seconds. If a response is not - received from the device within this time then the record sets a major alarm. -1.0 - means wait forever, no timeout. Default=1.0
-

- The TMOD field controls what type of I/O is performed when the record processes.

- - - - - - - - - - - - - - - - - - - - - - - -
- "Write/Read" (default) - The output data is sent from the selected output field to the device. A response - is then read back into the selected input field. The response must be received within - the time specified by TMOT. For asynOctet the input buffer is flushed before the - write operation, so that any characters received prior to the write operation are - discarded. The Write/Read operation is "atomic", meaning that it is guaranteed that - no other asyn I/O to the device will occur between the write and read operations. -
- "Write" - The output source is sent to the device. No response is read back.
- "Read" - Data is read from the device into the input field. The response must be received - within the time specified by TMOT. No output is sent to the device prior to the - read operation.
- "Flush" - The input buffer is flushed. Nothing is sent to the device or read from the device. - Applies only to asynOctet.
- "NoI/O" - The record processes but no I/O is actually performed. This mode can be used as - a safety feature when using an asyn record to just control the trace fields of asyn - ports. If the record is in this mode and is accidentally processed, then no I/O - will occur.
-

-

-
-

- Output Control Fields for asynOctet

-

- These fields control output I/O when using the asynOctet interface (i.e. when IFACE="asynOctet").

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Name - Access - Prompt - Data type - Description
- AOUT - R/W* - "Output string" - DBF_STRING - The output string which is sent to the device if OFMT="ASCII". The number of bytes - sent to the device will be strlen(AOUT) plus strlen(OEOS). -
- BOUT - R/W* - "Output byte data" - DBF_CHAR (array) - The output data which is sent to the device if OFMT="Binary" or "Hybrid". The maximum - length of this field is controlled by OMAX. The actual number of bytes to be sent - to the device when OFMT="Hybrid" will be strlen(BOUT) plus strlen(OEOS). - The actual number of bytes to be sent to the device when OFMP="Binary" will - be NOWT.
- OEOS - R/W - "Output terminator" - DBF_STRING - A character string that is appended to the output before transmission to the device. - This field is ignored if OFMT="Binary". Set this field to "" to suppress transmission - of a terminator. Commonly used values are "\r" (the default), "\n", and "\r\n". -
- OMAX - R - "Max. size of output array" - DBF_LONG - The allocated length of the BOUT array. This value cannot be changed after IOC initialization. - Default=80.
- NOWT - R/W - "Number of bytes to write" - DBF_LONG - The number of bytes to send from the BOUT array to the device if OFMT="Binary". - This value must be less than or equal to OMAX. Default=80.
- NAWT - R/W - "Number of bytes actually written" - DBF_LONG - The actual number of bytes written in the last write operation. This field is valid - for all OFMT modes. This number does not include the output terminator, if any. -
- OFMT - R/W - "Output format" - DBF_MENU - The output format. The choices are: - - - - - - - - - - - - - - - -
- "ASCII "(default) - The data sent to the device will be taken from the AOUT field.
- "Hybrid" - The data sent to the device will be taken from the BOUT field.
- "Binary" - The data sent to the device will be taken from the BOUT field.
-
-

- There are two output fields, AOUT (ASCII Output) and BOUT (Byte Output). The OFMT - (Output Format) field is used to select one of these fields or the other as the - output source to the device. -

-

- If OFMT="ASCII" then the AOUT field is processed with dbTranslateEscape() to convert - control characters (e.g. "\r", "\021") to bytes, the length of the output is determined - with strlen(), and the string is sent to the device using asynOctet->write. This - will append the output EOS if one has been set.

-

- If OFMT="Hybrid" then the BOUT field is processed with dbTranslateEscape() to convert - control characters (e.g. "\r", "\021") to bytes, the length of the output is determined - with strlen(), and the string is sent to the device using asynOctet->write. This - will append the output EOS if one has been set.

-

- If OFMT="Binary" then NOWT bytes from the BOUT field are sent to the device using - asynOctet->write. This will not append an output EOS.

-

- OEOS is set to the current value for the port when the record connects to the port. - If OEOS is modified after the record connects to the port, then the output EOS will - be changed using asynOctet->setOutputEos. IMPORTANT: The value of OEOS in the - database file is never used, because it is modified when the record connects to - the port.

-

-

-
-

- Input Control Fields for asynOctet

-

- These fields control input I/O when using the asynOctet interface (i.e. when IFACE="asynOctet").

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Name - Access - Prompt - Data type - Description
- AINP - R - "Input string" - DBF_STRING - The input string that is read from the device if IFMT="ASCII". The string will be - null terminated. Note that due to the maximum size of a string in EPICS, the input - string must be less than 40 characters. If longer strings are required then set - IFMT="Hybrid" and read into the BINP field.
- BINP - R - "Input byte data" - DBF_CHAR (array) - The input data that is read from the device if IFMT="Hybrid" or IFMT="Binary". The - maximum length of this field is controlled by IMAX. The actual number of bytes read - from the device is given by NORD.
- IEOS - R/W - "Input terminator" - DBF_STRING - A string that indicates the end of a message on input. Set this field to """ if - no input terminator should be used. This field is ignored if IFMT="Binary". Commonly - used values are "\r" (the default), "\n", and "\r\n". The input terminator is removed - from the input buffer after the read.
- IMAX - R - "Max. size of input array" - DBF_LONG - The allocated length of the BINP array. This value cannot be changed after IOC initialization. - Default=80.
- NRRD - R/W - "Number of bytes to read" - DBF_LONG - The requested number of bytes to read. This field is valid for all IFMT modes. If - this field is <= 0, then the requested number of bytes to read will be the EPICS - defined MAX_STRING_SIZE=40 (if IFMT="ASCII") or IMAX (if IFMT="Hybrid" or "Binary"). - Default=0.
- NORD - R - "Number of bytes read" - DBF_LONG - The actual number of bytes read in the last read operation. This field is valid - for all IFMT modes. This number includes the input terminator, if any.
- IFMT - R/W - "Input format" - DBF_MENU - The input format. The choices are: - - - - - - - - - - - - - - - -
- "ASCII" (default) - The data read from the device will be placed in the AINP field.
- "Hybrid" - The data read from the device will be placed in the BINP field.
- "Binary" - The data read from the device will be placed in the BINP field.
-
- TINP - R - "Translated input" - DBF_CHAR (array) - This field will contain up to the first 40 characters of the AINP or BINP fields - (depending on IFMT), after translation with epicsStrSnPrintEscaped, to convert non-printable - characters to a printable form (e.g. \r, \n, etc.)
-

- There are two input fields, AINP (ASCII Input) and BINP (Byte Input). The IFMT (Input - Format) field is used to select one or the other as the destination of data sent - from the device.

-

- A read operation terminates when any 1 of the following 4 conditions is met:

-
    -
  1. The input terminator (IEOS) is found (if IFMT="ASCII" or "Hybrid")
  2. -
  3. EOI asserted (GPIB only)
  4. -
  5. The desired number of input characters (NRRD) are received
  6. -
  7. The timeout (TMOT) expires
  8. -
-

- If IFMT="ASCII" then input is read into the AINP field with asynOctet->read. - This will remove the input EOS string, if any, and AINP will be NULL terminated - if possible.

-

- If IFMT="Hybrid" then the input is read into the BINP field with asynOctet->read. - This will remove the input EOS string, if any, and BINP will be NULL terminated - if possible.

-

- If IFMT="Binary" then the input is read into the BINP field using asynOctet->read. - This will ignore the input EOS. BINP will be null terminated. -

-

- The TINP field is intended for operator display. It will contain up to the first - 40 characters of the input read into AINP (if IFMT="ASCII") or BINP (if IFMT="Hybrid" - or "Binary"). Non-printable characters are first converted to a printable form using - epicsStrSnPrintEscaped. This field should not normally be using for parsing the - response from the device. This is the field that is shown as the ASCII input field - in the medm display asynRecord.adl. It is useful for displaying the device response, - even in "Hybrid" and "Binary" input modes.

-

- The IEOS terminator field is 40 characters long. However, the serial drivers permit - 2 character end-of-message strings at most. The GPIB drivers only permit 1 character - end-of-message strings.

-

- IEOS is set to the current value for the port when the record connects to the port. - If IEOS is modified after the record connects to the port, then the input EOS will - be changed using asynOctet->setInputEos. IMPORTANT: The value of IEOS in the - database file is never used, because it is modified when the record connects to - the port.

-
-

- Input/Output Control Fields for Register Interfaces

-

- These fields control I/O when using the register interfaces (i.e. when IFACE="asynInt32", - "asynUInt32Digital", or "asynFloat64").

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Name - Access - Prompt - Data type - Description
- I32INP - R - "asynInt32 input" - DBF_LONG - The input data that is read from the device if IFACE="asynInt32" and TMOD="Read" - or "Write/Read".
- I32OUT - R/W* - "asynInt32 output" - DBF_LONG - The data that is sent to the device if IFACE="asynInt32" and TMOD="Write" or "Write/Read". -
- UI32INP - R - "asynUInt32Digital input" - DBF_ULONG - The input data that is read from the device if IFACE="asynUInt32Digital" and TMOD="Read" - or "Write/Read".
- UI32OUT - R/W* - "asynUInt32Digital output" - DBF_ULONG - The data that is sent to the device if IFACE="asynUInt32Digital" and TMOD="Write" - or "Write/Read".
- UI32MASK - R/W - "asynUInt32Digital mask" - DBF_ULONG - The mask that is used if IFACE="asynUInt32Digital". The mask is used for both write - and read operations. Only bits that are set in mask will be modified on writes, - and any bits that are clear in mask will be zero on read.
- F64INP - R - "asynFloat64 input" - DBF_DOUBLE - The input data that is read from the device if IFACE="asynFloat64" and TMOD="Read" - or "Write/Read".
- F64OUT - R/W* - "asynFloat64 output" - DBF_DOUBLE - The data that is sent to the device if IFACE="asynFloat64" and TMOD="Write" or "Write/Read". -
-

-

-
-

- Serial Control Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Name - Access - Prompt - Data type - Description
- BAUD - R/W - "Baud rate" - DBF_MENU - The baud rate for the port. Choices are "Unknown", "300", "600", "1200", "2400", - "4800", "9600", "19200", "38400", "57600", "115200", "230400", 460800, 576000, 921600, - and 1152000. Default="Unknown". Note that BAUD field is limited to 16 choices because - it is of type DBF_MENU. The LBAUD field can be used to select baud rates that are - not available in the BAUD menu.
- LBAUD - R/W - "Baud rate (long)" - DBF_LONG - The baud rate for the port as an integer. This field allows selecting any baud rate, - including those not available in the BAUD menu field. Changing the BAUD field will - change the LBAUD field accordingly. Changing the LBAUD field will change the BAUD - field to the appropriate menu choice if possible, or to "Unknown" if that baud rate - is not in the menu.
- PRTY - R/W - "Parity" - DBF_MENU - The device parity. Choices are "Unknown", "None", "Even", and "Odd". Default="Unknown". -
- DBIT - R/W - "Data bits" - DBF_MENU - The number of data bits. Choices are "Unknown", "5", "6", "7", and "8". Default="Unknown". -
- SBIT - R/W - "Stop bits" - DBF_MENU - The number of stop bits. Choices are "Unknown", "1" and "2". Default="Unknown". -
- MCTL - R/W - "Modem Control" - DBF_MENU - Modem control. Choices are "Unknown", "CLOCAL" and "YES". Default="Unknown".
- FCTL - R/W - "Flow control (cts rts)" - DBF_MENU - Flow control. Choices are "Unknown", "None" and "Hardware". Default="Unknown". Hardware - means to use the cts (clear to send) and rts (request to send) signals
- IXON - R/W - "Output XOFF/XON" - DBF_MENU - XOFF/XON control on output. Choices are "Unknown", "No" and "Yes". Default="Unknown". - If the IOC receives an XOFF character, it suspends output until an XON character - is received.
- IXOFF - R/W - "Input XOFF/XON" - DBF_MENU - XOFF/XON control on input. Choices are "Unknown", "No" and "Yes". Default="Unknown". - The IOC sends XOFF and XON characters as necessary to prevent input from coming - in faster than programs are reading it. The external device sending the input data - must respond to an XOFF character by suspending transmission, and to an XON character - by resuming transmission.
- IXANY - R/W - "XON=any character" - DBF_MENU - Choices are "Unknown", "No" and "Yes". Default="Unknown". Allows any input character - to restart output when output has been suspended with the XOFF character. Otherwise, - only the XON character restarts output. This flag is not available on all systems, - including WIN32.
-

- The above fields are used to set the serial port parameters. A write to any of these - fields causes the port parameters to be changed immediately, but does not cause - any I/O to be performed. The port parameters can currently be set only for local - serial ports, including IP-Octal on vxWorks. They cannot currently be set for Ethernet/serial - adapters like the Moxa units.

-

- The "Unknown" choice for each option is used on readback if the driver does not - support that option. "Unknown" should not be written into the field.

-

- The baud rates actually available are device dependent. For the SBS IP-Octal module - the maximum baud rate is 38400. -

-

- These record fields are set to the values currently in effect for the port when - the connection to the port is made. IMPORTANT: The value of these fields in the - database file is never used, because it is modified when the record connects to - the port.

-

- vxWorks and MCTL,FCTL. The sioLib serial support for vxWorks uses CLOCAL for what - POSIX calls CTSRTS (Clear to send and request to send). It does not appear that - sioLib has any concept of modem control, which is what POSIX calls CLOCAL. For vxWorks - the standard serial support for asynDriver supplied in drvAsynSerialPort.c, accepts - both MCTL and FCTL. MCTL=(CLOCAL,YES) is the same as FCTL=(None,Hardware).

-

-

-
-

- IP Control Fields

- - - - - - - - - - - - - - - - - - - - - - - - -
- Name - Access - Prompt - Data type - Description
- DRTO - R/W - "Disconnect on Read Timeout" - DBF_MENU - Choices are "Unknown", "No" and "Yes". Default="No". If Yes then the IP port will - be disconnected on a read timeout.
- HOSTINFO - R/W - "IP port hostInfo" - DBF_STRING - The IP port hostInfo string with the same syntax as the drvAsynIPPortConfigure command - i.e. host:port[:localport] [protocol].
-

- Writing to the HOSTINFO field will cause the drvAsynIPPort driver to disconnect - from the current host (if any) and then attempt to connect to the new host.

-

- If the drvAsynIPPort was created with the COM (RFC 2217) protocol then the serial - control fields listed above can be used to control those settings on ther Ethernet/serial - adapter.

-
-

- GPIB Control Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Name - Access - Prompt - Data type - Description
- SPR - R - "Serial Poll Response" - DBF_UCHAR - The device status byte, which is read during a Serial Poll operation.
- UCMD - R/W* - "Universal command" - DBF_MENU - A GPIB Universal Command to be executed. . The choices are: - - - - - - - - - - - - - - - - - - - - - - - - -
- "None"
- "Device Clear (DCL)"
- "Local Lockout (LL0)"
- "Serial Poll Disable (SPD)"
- "Serial Poll Enable (SPE)"
- "Unlisten (UNL)"
- "Untalk (UNT)"
-
- ACMD - R/W* - "Addressed command" - DBF_MENU - A GPIB Addressed Command to be executed. The choices are: - - - - - - - - - - - - - - - - - - - - - -
- "None"
- "Group Execute Trig. (GET)"
- "Go To Local (GTL)"
- "Selected Dev. Clear (SDC)"
- "Take Control (TCT)"
- "Serial Poll"
-
-

- GPIB Universal Commands are commands which are directed to all devices on the GPIB - bus, not just addressed devices. If the UCMD field is set to any value except "None" - then the appropriate Universal Command is executed, and UCMD is set back to "None". - The record processing only performs the Universal Command, i.e. it does not also - perform the GPIB operation indicated by TMOD.

-

- GPIB Addressed Commands are commands which are directed to only the addressed devices - on the GPIB bus. If the ACMD field is set to any value except "None" then the appropriate - Addressed Command is executed, and ACMD is set back to "None". The record processing - only performs the Addressed Command, i.e. it does not also perform the GPIB operation - indicated by TMOD.

-

-

-
-

- Trace Control Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Name - Access - Prompt - Data type - Description
- TMSK - R/W - "Trace mask" - DBF_LONG - The asynTraceMask.
- TB0 - R/W - "Trace error" - DBF_MENU - The ASYN_TRACE_ERROR bit. Choices are "Off" and "On".
- TB1 - R/W - "Trace IO device" - DBF_MENU - The ASYN_TRACEIO_DEVICE bit. Choices are "Off" and "On".
- TB2 - R/W - "Trace IO filter" - DBF_MENU - The ASYN_TRACEIO_FILTER bit. Choices are "Off" and "On".
- TB3 - R/W - "Trace IO driver" - DBF_MENU - The ASYN_TRACEIO_DRIVER bit. Choices are "Off" and "On".
- TB4 - R/W - "Trace flow" - DBF_MENU - The ASYN_TRACE_FLOW bit. Choices are "Off" and "On".
- TB5 - R/W - "Trace warning" - DBF_MENU - The ASYN_TRACE_WARNING bit. Choices are "Off" and "On".
- TIOM - R/W - "Trace I/O mask" - DBF_LONG - The asynTraceIOMask.
- TIB0 - R/W - "Trace IO ASCII" - DBF_MENU - The ASYN_TRACEIO_ASCII bit. Choices are "Off" and "On".
- TIB1 - R/W - "Trace IO escape" - DBF_MENU - The ASYN_TRACEIO_ESCAPE bit. Choices are "Off" and "On".
- TIB2 - R/W - "Trace IO hex" - DBF_MENU - The ASYN_TRACEIO_HEX bit. Choices are "Off" and "On".
- TINM - R/W - "Trace Info mask" - DBF_LONG - The asynTraceInfoMask.
- TINB0 - R/W - "Trace Info Time" - DBF_MENU - The ASYN_TRACEINFO_TIME bit. Choices are "Off" and "On".
- TINB1 - R/W - "Trace Info Port" - DBF_MENU - The ASYN_TRACEINFO_PORT bit. Choices are "Off" and "On".
- TINB2 - R/W - "Trace Info Source" - DBF_MENU - The ASYN_TRACEINFO_SOURCE bit. Choices are "Off" and "On".
- TINB3 - R/W - "Trace Info Thread" - DBF_MENU - The ASYN_TRACEINFO_THREAD bit. Choices are "Off" and "On".
- TSIZ - R/W - "TraceIO truncate size" - DBF_LONG - The parameter passed to asynTraceSetTraceIOTruncateSize(). This value is used to - limit the number of I/O bytes printed by traceIO.
- TFIL - R/W - "Trace IO file" - DBF_STRING - The name of the file to which trace information is printed.
-

- The above fields are used to control the asynTrace facility. They allow one to turn - on and off debugging output printed at the shell or written to the trace file.

-

- The TMSK field allows one to read/write the entire asynTraceMask word. The TB0-TB5 - fields allow one to read/write the individual bits in asynTraceMask. The TIOM field - allows one to read/write the entire asynTraceIOMask word, and the TIB0-TIB2 fields - allow one to read/write the individual bits in asynTraceIOMask. The TINM field allows - one to read/write the entire asynTraceInfoMask word, and the TINB0-TINB3 fields - allow one to read/write the individual bits in asynTraceInfoMask.

-

- When the asyn record is connected to a new device with the PORT and ADDR fields - the above trace fields are automatically updated to reflect the current asynTrace, - asynTraceIO, and asynTraceInfo masks for that device.

-

- The TFIL field is used to set the name of the trace file. It is not possible for - the asyn record to determine the current file name if the record did not set it. - In this case the file name is displayed as "Unknown". Set this field to a string - file name (including possibly a valid path from the IOC's current default directory) - to have the output written to that file. The following values are handled as special - cases: -

-
    -
  • <stdout> - Write to standard out.
  • -
  • <stderr> - Write to standard error.
  • -
  • <errlog> - Use the errlog facility.
  • -
-

-

-
-

- Connection Management Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Name - Access - Prompt - Data type - Description
- AUCT - R/W - "Autoconnect" - DBF_MENU - Sets the autoconnect option. Choices are "noAutoConnect" and "autoConnect". The - value read reflects current state of the autoconnect flag, i.e. the value returned - from isAutoConnect().
- ENBL - R/W - "Disable/Enable" - DBF_MENU - Disables or enables the port. Choices are "Disable" and "Enable". The value read - reflects current state of the enabled flag, i.e. the value returned from isEnabled(). -
- CNCT - R/W - "Connect/Disconnect" - DBF_MENU - Disconnects or connects the device. Choices are "Disconnect" and "Connect". The - value read reflects current state of the connected flag, i.e. the value returned - from isConnected().
-

-

-
-

- Error Status Fields

- - - - - - - - - - - - - - - - - - - - - - - - -
- Name - Access - Prompt - Data type - Description
- ERRS - R - "Error status" - DBF_STRING - Error status string for the most recent operation. This string is set to "" (null - string) at the start of each connection and I/O operation.
- AQR - W - "About queueRequest" - DBF_CHAR - Abort queueRequest. If a process request has been queued but not delivered it is - canceled, the record is put into alarm and record completion occurs.
-

- The ERRS field is set to "" (null string) at the start of every operation, including - trace and connection management operations. It contains the first 100 characters - of any error message the record writes with asynPrint(...ASYN_TRACE_ERROR...). -

-

- The standard EPICS record fields STAT (status) and SEVR (severity) are used to report - the I/O error status. For example status field may be set to NO_ALARM, WRITE, READ, - or COMM, and the SEVR field may be set to NO_ALARM, MINOR, or MAJOR. These alarm - fields are only used to report I/O errors or errors when connecting to a new PORT - or ADDR. They are not affected by trace or connection management operations.

-

-

-
-

- Private Fields

-

-

- - - - - - - - - - - - - - - - - - - - - - - - -
- Name - Access - Prompt - Data type - Description
- IPTR - N - "Input buffer pointer" - DBF_NOACCESS - The pointer to the buffer for the BINP field.
- OPTR - N - "Output buffer pointer" - DBF_NOACCESS - The pointer to the buffer for the BOUT field.
-

-

-
-

- Record Processing

-

- The asyn record processes, i.e. performs the I/O operation given by TMOD, according - to the normal rules for EPICS records. The AOUT, BOUT, I32OUT, UI32OUT, and F64OUT - fields are Process Passive, so the record will process if these fields are written - to and the SCAN field of the record is Passive. The scan field of the record can - be set to any of the periodic scan rates (e.g. "1 second") for periodic processing, - to "Event" for event processing, or to "I/O Intr" for I/O interrupt processing.

-

- "I/O Intr" scanning is fully supported for drivers that provide callbacks.

-

- If the SCAN field is "I/O Intr" it will be changed to "Passive" when any of the - following fields are modified: PORT, ADDR, DRVINFO, REASON, IFACE, or UINT32MASK. - This is necessary because changes to these fields require re-registering with the - interrupt source.

-

-

-
-

- Obsolete serial and GPIB records

-

- The asyn record is designed to be a complete replacement for the older generic serial - ("serial") and generic GPIB ("gpib") records. These records are no longer needed, - and will not be supported in the future. The following is a list of the differences - between the old serial and GPIB records and the new asyn record which may require - changes to databases or applications.

-
    -
  • The ODEL field has been replaced by OEOS. It has changed from a DBF_LONG to DBF_STRING - in order to support multi-character terminators.
  • -
  • The IDEL (serial) and EOS (gpib) fields have been replaced by IEOS. They have - changed from a DBF_LONG to DBF_STRING in order to support multi-character terminators.
  • -
  • The INP field has been replaced by the PORT and ADDR fields in order to support - run-time connection to different devices.
  • -
  • The AOUT and OEOS fields are processed by dbTranslateEscape before being sent - to the device. In rare cases this may require changing the output strings if these - contained the "\" character.
  • -
  • The asyn record always posts monitors on the input field (AINP or BINP) when the - record processes. The older records did not post monitors on the AINP field if the - value was the same as the previous read. This caused problems for some SNL programs - and data acquisition applications.
  • -
  • The ODEL and IDEL fields were used even when OFMT or IFMT were in "Binary" mode. - OEOS and IEOS are now ignored when OFMT or IFMT respectively are in "Binary" mode.
  • -
  • The ODEL and IDEL fields were always used to set the input and output end of string. - The IEOS and OEOS fields now are now initialized to the current EOS settings for - the port when the record connects. IEOS and OEOS only change the EOS settings if - these fields are modified after the record connects to the port. Thus, it is now - important to initialize the EOS strings for the port correctly in the startup script.
  • -
  • The TMOT field has changed from DBF_LONG to DBF_DOUBLE, and the units have changed - from milliseconds to seconds. TMOT=-1.0 now means wait forever.
  • -
-

-

-
-

- medm screens

-

- The following are screen shots of the medm screens provided for the asyn record.

-
-

- Main control screen, asynRecord.adl

-

- asynRecord.png

-

-

-

- asynOctet I/O screen, asynOctet.adl

-

- asynOctet.png

-

- asyn register device I/O screen, asynRegister.adl

-

- asynRegister.png

-

- Serial port setup screen, asynSerialPortSetup.adl

-

- asynSerialPortSetup.png

-

-

-

- IP port setup screen, asynIPPortSetup.adl

-

- asynIPPortSetup.png

-

-

-

- GPIB setup screen, asynGPIBSetup.adl

-

- asynGPIBSetup.png

-

-

-
-
-

- Example #1

-

- The following is an IDL program that demonstrates the use of the asyn record. It - transfers data in both ASCII and binary formats. Hopefully the IDL syntax is clear - enough to be understood by non-IDL users, and can be translated into your favorite - scripting language.

-
; This IDL program demonstrates the use of the EPICS asyn record.
-; The program uses 2 asyn records.  The ports corresponding to these
-; 2 records are connected with a null-modem cable
-; Record 1 sends a message to record 2 in ASCII.
-; Record 2 sends a message back to record 1 in binary.
-
-; Record names
-rec1 = '13LAB:serial2'
-rec2 = '13LAB:serial3'
-recs = [rec1, rec2] ; Array with both record names
-; Set up port parameters for both records:
-;   19,200 baud, 8 data bits, 1 stop bit, no parity, no flow control
-;   Timeout=1 second
-for i=0, 1 do begin
-    rec = recs[i]
-    t = caput(rec+'.BAUD', '19200')
-    t = caput(rec+'.DBIT', '8')
-    t = caput(rec+'.SBIT', '1')
-    t = caput(rec+'.PRTY', 'None')
-    t = caput(rec+'.FCTL', 'None')
-    t = caput(rec+'.TMOT', 1.0)
-endfor
-
-; Put record 1 in ASCII output mode, <CR> output delimiter,
-;   binary input mode, no input delimiter
-t = caput(rec1+'.OFMT', 'ASCII')
-t = caput(rec1+'.OEOS', '\r')
-t = caput(rec1+'.IFMT', 'Binary')
-t = caput(rec1+'.IEOS', '')
-; Put a monitor on record 1 Binary input field
-t = casetmonitor(rec1+'.BINP')
-; Clear the monitor by reading the value
-t = caget(rec1+'.BINP', junk)
-
-; Put record 2 in Binary output mode, no output delimiter
-;   ASCII input mode, <CR> input delimiter
-t = caput(rec2+'.OFMT', 'Binary')
-t = caput(rec2+'.OEOS', '')
-t = caput(rec2+'.IFMT', 'ASCII')
-t = caput(rec2+'.IEOS', '\r')
-
-; Put record 2 in read transfer mode
-t = caput(rec2+'.TMOD', 'Read')
-; Put a monitor on record2 ASCII input field
-t = casetmonitor(rec2+'.AINP')
-; Clear the monitor by reading the value
-t = caget(rec2+'.AINP', junk)
-
-; Process record 2; this will cause it to wait for data
-t = caput(rec2+'.PROC', 1)
-; Put record 1 in Write transfer mode
-t = caput(rec1+'.TMOD', 'Write')
-; Send a message to port 2
-message = 'Request data: '+string(systime())
-print, 'Record 1 sent message: ' + message
-t = caput(rec1+'.AOUT', message)
-
-; Wait for monitor on record2 ASCII input field
-while (not cacheckmonitor(rec2+'.AINP')) do wait, .1
-; Read data from record 2
-t = caget(rec2+'.AINP', input)
-print, 'Got a message from record 1: ', input
-
-size=256
-; Put record 1 in read mode, expect "size" byte input
-t = caput(rec1+'.TMOD', 'Read')
-t = caput(rec1+'.NRRD', size)
-; Process record 1; this will cause it to wait for data
-t = caput(rec1+'.PROC', '1')
-
-; Put record 2 in write mode
-t = caput(rec2+'.TMOD', 'Write')
-; Send an 8 bit binary sin wave, "size" points long from
-; port 2 to port 1
-send_data = byte(sin(findgen(size)/5)*126 + 127)
-t = caput(rec2+'.NOWT', size)
-t = caput(rec2+'.BOUT', send_data)
-
-; Wait for monitor on channel 1 binary input
-while (not cacheckmonitor(rec1+'.BINP')) do wait, .1
-
-; Record 1 should have received "size" bytes. Make sure NORD=size
-t = caget(rec1+'.NORD', nord)
-if (nord eq size) then $
-    print, 'Read array data OK' $
-else $
-    print, 'Error reading array data!'
-
-; Read data from record 1
-t = caget(rec1+'.BINP', rec_data, max=nord)
-
-; Plot it
-plot, rec_data
-
-end
-
-

- Example #2

-

- The following is an IDL procedure that demonstrates the use of the asyn record to - communicate with a Tektronix TDS200 Digital Oscilloscope. It transfers data in both - ASCII and binary formats. It will work with either an RS-232 or GPIB connection - to the scope. The record must be loaded with IMAX at least large enough to read - the waveform. The entire waveform readout is 2500 channels on the TDS220. The buffer - size required is 1 byte per channel + 7 bytes header/checksum. The start and stop - parameters to the procedure can be used to read a subset of the waveform.

-

- Hopefully the IDL syntax is clear enough to be understood by non-IDL users, and - can be translated into your favorite scripting language.

-
pro read_tds200, record, data, start=start, stop=stop, chan=chan
-
-; This procedure reads waveforms from the Tektronix TDS200 series scopes
-; Mark Rivers
-; Modifications: 
-;     March 7,  2001 Correctly put record in Write and Write/Read modes.
-;     Dec. 7,   2001 Set timeout to 2 seconds before read.
-;     March 30, 2004 Change IFMT from Binary to Hybrid, other fixes.
-
-if (n_elements(start) eq 0) then start=1
-if (n_elements(stop) eq 0) then stop=2500
-if (n_elements(chan) eq 0) then chan=1
-chan = 'CH'+strtrim(chan,2)
-
-aout = record + '.AOUT'
-binp = record + '.BINP'
-tmod = record + '.TMOD'
-ifmt = record + '.IFMT'
-binp = record + '.BINP'
-nord = record + '.NORD'
-tmot = record + '.TMOT'
-oeos = record + '.OEOS'
-ieos = record + '.IEOS'
-
-; Set the terminators to newline (assumes scope is set up this way)
-t = caput(oeos, '\n', /wait)
-t = caput(ieos, '\n', /wait)
-
-; Set the transfer mode to write
-t = caput(tmod, 'Write', /wait)
-
-; Set the encoding to positive binary, start and stop readout channels
-; Set the readout range.  Can't do as one command, exceed 40 characters
-command = 'DATA:ENC RPB; DATA:START ' + strtrim(start,2)
-t = caput(aout, command, /wait)
-command = 'DATA:STOP ' + strtrim(stop,2)
-t = caput(aout, command, /wait)
-
-;Set DATa:WIDth to 2
-;command = 'DATA:WIDTH 2'
-;t = caput(aout, command, /wait)
-
-;Set channel number
-command = 'DATA:SOURCE '+ strtrim(chan,2)
-t = caput(aout, command, /wait)
-
-; Set the input mode to hybrid. Large buffer but line-feed terminator
-t = caput(ifmt, 'Hybrid', /wait)
-
-
-; Set the transfer mode to write/read
-t = caput(tmod, 'Write/Read', /wait)
-
-; Empirically the timeout needs to be about 5 seconds for
-; 1024 channels with RS-232
-t = caput(tmot, 5.0)
-
-; Read the scope
-t = caput(aout, 'Curve?', /wait)
-
-; Get the data
-t = caget(binp, data)
-
-; Check the number of bytes read.  See if it's what's expected
-n_data = stop-start+1
-n_header = 2 + strlen(strtrim(n_data, 2))
-n_checksum = 1
-n_expected = n_header + n_data + n_checksum
-t = caget(nord, n)
-if (n ne n_expected) then $
-   print, 'Scope returned:', n, $' bytes, expected: ', n_expected
-
-; The first n_header bytes are header, the last byte is checksum.
-; Data are offset by 127, convert to long
-data = data[n_header:n-2] - 127L
-
-return
-end
- - diff --git a/documentation/devGpib.html b/documentation/devGpib.html deleted file mode 100644 index 62097d3..0000000 --- a/documentation/devGpib.html +++ /dev/null @@ -1,1569 +0,0 @@ - - - - asynDriver devGpib - - - -
-

- EPICS: asynDriver devGpib
- Instrument Device Support

-

- Marty Kraimer and Eric Norum

-

- October 19, 2007

-
-

- NOTE: devGpib is obsolete and should not be used for new applications. - StreamDevice should be used instead.

-
-

- Contents

-
-

- Introduction -
- Acknowledgments -
- Install and Build -
- Using Instrument Support -
- Creating Instrument Device Support -
- devCommonGpib
- devSupportGpib
- Changes to Previous EPICS GPIB Support
- General GPIB Problems
- License Agreement
-

-
-

- License Agreement

-

- This product is available via the open source license described at the end of this - document.

-
-

- Introduction

-

- devGpib is the successor to the GPIB support that came with EPICS base 3.13. The - 3.13 code was unbundled by Benjamin Franksen, and ultimately became gpibCore which - is the 3.14 version of Benjamin's support. devGpib is the successor to the device - support portion of gpibCore. The driver part of gpibCore is replaced by asynDriver - and asynGpib.

-

- This manual assumes that the reader is familiar with EPICS IOC record and device - support and also with asynDriver.

-

- devGpib is one method for implementing EPICS IOC device support for instruments. - Other methods are available. If support for an instrument does not exist, consider - using STREAMS instead of devGpib.

-

- The 3.13 GPIB support only worked with real GPIB instruments. Since devGpib uses - low level asyn drivers, it can also work with other instruments, e.g. serial devices. - Thus, this manual uses the terminology instrument rather than GPIB device.

-

- devGpib requires that a device support module be created for each supported instrument. - Facilities are provided to make it relatively easy to write new support.

-

- The following features are provided:

-
    -
  • I/O is performed via database records.
  • -
  • Instrument device support is written by calling devCommonGpib/devSupportGpib routines.
  • -
  • devCommonGpib provides support for individual record types.
  • -
  • devSupportGpib provides record independent support.
  • -
  • devCommonGpib/devSupportGpib use asynCommon, asynOctet, and asynGpib. Thus, the - support will work with any driver that implements these interfaces. If instrument - support does not use GPIB specific features, then the support will work with any - driver that implements asynCommon and asynOctet. In particular, communication via - serial ports is possible.
  • -
  • devCommonGpib should satisfy most requirements but it is also possible to provide - custom support that uses devSupportGpib.
  • -
-
-

- Acknowledgments

-
-
John Winans
-
- John provided the original EPICS GPIB support. Most databases using John's support - can be used without modification. With some modification, device support modules - written for John's support can be used.
-
Benjamin Franksen
-
- John's support only worked on vxWorks. In addition, the driver support was implemented - as a single source file. Benjamin defined an interface between drvCommon and low - level controllers. The low level drivers became separate source modules that implemented - the interface. He also created the original support for VXI-11.
-
Eric Norum
-
- Eric started with Benjamin's code and converted it to use the Operating System Independent - features of EPICS 3.14.
-
Marty Kraimer
-
- Marty started with Eric's version and made changes to support secondary addressing - and to replace ioctl with code to support general bus management, universal commands, - and addressed commands. He also made the conversion to using asyn drivers.
-
-
-

- InstallAndBuild

-

- devGpib is bundled with the asynDriver. The code is in library asyn. Thus, once - asyn is included as part of an application, devGpib will also be available. It is - only necessary to include devGpib.dbd in your <app>Include.dbd - file. In addition, device support for your specific instruments must be installed.

-
-

- Using Instrument Support

-

- devGpib does not provide support for specific GPIB devices but for implementing - such support. Within the EPICS community, support exists for many GPIB devices. - The EPICS supported hardware list shows some of the support. If your device is not - listed and a message to tech-talk does not provide any help, then you will have - to write your own device support. This section assumes that an instrument support - is available.

-

- An EPICS record is connected to GPIB by the fields DTYP and INP or OUT.

-

- The DTYP field has the format:

-
    field(DTYP,"<device support name>")
-

- where

-

- <device support name> - Is the name from a device database definition, - i.e. a definition of the form:

-
    device(<record type>,GPIB_IO,<dsetName>,"<device support name>")
-

- The INP or OUT field has the format:

-
    field(INP,"#L<link> A<addr> @<number>")
-    or
-    field(OUT,"#L<link> A<addr> @<number>")
-

- where

-
-
<link>
-
- Link number. Low level drivers use portName to provide access to a specific communication - interface. In order to keep compatibility with link numbers, the portName MUST be - Lxxx where xxx is the value that appears in the #Lxxx portion of the INP or OUT - fields of record instances.
-
<addr>
-
- GPIB address of your device, which can be a primary address or an extended address. - A primary address has a value <=30. An extended address is of the form PSS, where - P represents the primary address and SS is the secondary address. It is not possible - to express an extended address if the primary address is 0. Some examples are: -
A9    primary address 9
-A900  extended address: primary address is 9, secondary address is 0
-A906  extended address: primary address is 9, secondary address is 6. 
-
-
<number>
-
- An integer that identifies a gpibCmd definition in a GPIB device support module. - If the implementer is nice, documentation like the following is provided: -
   recordType  @<number>   Description
- If such documentation is not available, look at the device support itself for statements - like: -
  /* Param 12 */
-  {&DSET_LI, GPIBREAD, IB_Q_LOW, "*ESR?",  "%ld", 0, 20, 0, 0, 0, 0, 0, 0},
- The above states that @12 is a GPIB read command via a longin record. Thus the record - definition would be: -
    record(longin,"<name>") {
-        field(DTYP,"<device support name>")
-        ...
-        field(OUT,"#L<link> A<addr> @12")
-        ...
-    }
-
-
-

- Reports and Timeouts

-

- In order to have these commands available, devGpib.dbd must be included - as part of the applications xxxInclude.dbd file.

-

- A report of all devGpib devices can be generated via the command:

-
    dbior("devGpib",level)
-

- Three timeouts are defined:

-
    -
  • timeout - This is the timeout for individual I/O operations. It is - determined by the instrument support.
  • -
  • queueTimeout - Maximum time to wait in a the queue for access to - a device instance. The default is 60 seconds and can be changed with the iocsh - command: -
    devGpibQueueTimeout(interfaceName,gpibAddr,timeout)
    -    
    -
  • -
  • srqWaitTimeout - Maximum time to wait for an SRQ after a GPIBREADW - or GPIBEFASTIW has sent a command to the device. The default is 5 seconds and can - be changed with the iocsh command: -
    devGpibSrqWaitTimeout(interfaceName,gpibAddr,timeout)
    -    
    -
  • -
-
-

- Creating Instrument Device Support

-

- This section describes how to write device support for an instrument. It is assumed - that the reader is already familiar with the dialogue required to operate the instrument - and EPICS record and device support.

-

- Purpose

-

- An instrument support module provides access to the operating parameters of the - instrument.

-

- Overview

-

- Instruments typically have many operating parameters, each of which may be thought - of in terms of an EPICS database record type. It is the job of the instrument support - designer to map operating parameters to record types. Once this mapping is complete, - an instrument support module can be written. For each operating parameter, a gpibCmd - must be created.

-

- Device DBD Definition

-

- For each instrument support module, device definitions must be defined:

-
device(<record type>,<link type>,<DSET name>,"<DTYP name>")
-

- where

-
-
<record type>
-
- The record type, e.g. ai, ao, ...
-
<link type>
-
- Link type. Must be GPIB_IO.
-
<DSET name>
-
- Device Support Entry Table name. This is the external name defined in the device - support code.
-
<DTYP name>
-
- Device Type name. This is what appears in the DTYP field of record instances.
-
-

- For example, the definitions for the test supplied with devGpib are:

-
device(ai,GPIB_IO,devAiTestGpib,"GPIB Test")
-device(ao,GPIB_IO,devAoTestGpib,"GPIB Test")
-device(bi,GPIB_IO,devBiTestGpib,"GPIB Test")
-device(bo,GPIB_IO,devBoTestGpib,"GPIB Test")
-device(longin,GPIB_IO,devLiTestGpib,"GPIB Test")
-device(longout,GPIB_IO,devLoTestGpib,"GPIB Test")
-device(mbbi,GPIB_IO,devMbbiTestGpib,"GPIB Test")
-device(mbbo,GPIB_IO,devMbboTestGpib,"GPIB Test")
-device(stringin,GPIB_IO,devSiTestGpib,"GPIB Test")
-device(stringout,GPIB_IO,devSoTestGpib,"GPIB Test")
-

- For more information about device support, and also how to define INP or OUT links - of records, see the EPICS Application Developers Guide.

-

- Instrument Device Support Module

-

- If you are writing a new instrument support module just:

-
    -
  • Create a source directory and 'cd' to it.
  • -
  • Create a set of instrument support files by running the makeSupport.pl script: -

    - <asynTop>/bin/<EpicsHostArch>/makeSupport.pl -t devGpib - <InstName>

    -
  • -
  • Modify the src/<InstName>.c, src/<InstName>.dbd - and src/<InstName>.db files to provide the functionality needed by - your device.
  • -
-

- An instrument device support module consists of DSET entries, an array of gpibCmds, - efast tables (optional), name tables (optional), a devGpibParmBlock, a debugging - flag, an init_ai routine, and custom conversion functions (optional.).

-

- A simplified version of the skeleton file is:

-
/* devSkeletonGpib.c */
-...
-#include <devCommonGpib.h>
-...
-/* define all desired DSETs */
-...
-#define DSET_BO    devBiSkeletonGpib
-...
-#include <devGpib.h>    /* must be included after DSET defines */
-#define TIMEOUT     1.0
-#define TIMEWINDOW  2.0
-...
-/* Strings used by the init routines to fill in the znam,onam,... in BI and BO*/
-static  char    *offOnList[] = { "Off", "On" };
-static  struct  devGpibNames   offOn = { 2, offOnList, 0, 1 };
-
-static char  *initNamesList[] = { "Init","Init" };
-static struct devGpibNames initNames = { 2,initNamesList,0,1 };
-/* example EFAST table */
-static char *userOffOn[] = {"USER OFF;", "USER ON;", 0};
-
-/* Array of structures that define all GPIB messages */
-static struct gpibCmd gpibCmds[] =
-{
-  /* Param 0 */
-  {&DSET_BO,GPIBCMD,IB_Q_HIGH,"init",0,0,32,NULL,0,0,NULL,&initNames,0},
-  /* Param 1 */
-  {&DSET_BO, GPIBEFASTO, IB_Q_HIGH,0,0, 0, 32,0, 0, 0, userOffOn, &offOn, 0},
-  /* definitions for other parameters follow*/
-};
-/* The following is the number of elements in the command array above.  */
-#define NUMPARAMS sizeof(gpibCmds)/sizeof(struct gpibCmd)
-/* User MUST define init_ai */
-static long init_ai(int parm)
-{
-    if(parm==0)  {
-        devSupParms.name = "devSkeletonGpib";
-        devSupParms.gpibCmds = gpibCmds;
-        devSupParms.numparams = NUMPARAMS;
-        devSupParms.timeout = TIMEOUT;
-        devSupParms.timeWindow = TIMEWINDOW;
-        devSupParms.respond2Writes = -1;
-    }
-}
-

- The meaning of each portion of the code should become clear as you read the following - sections:

-

- DSET - Device Support Entry Tables

-

- The following statements create the Device Support Entry Tables

-
#define DSET_AI    devAiSkeletonGpib
-#define DSET_BI    devBiSkeletonGpib
-#define DSET_MBBI   devMbbiSkeletonGpib
-...
-#include <devGpib.h>    /* must be included after DSET defines */
-

- The actual DSETs are created by devGpib.h based on which DSET_xx definitions are - defined. A #define must appear for each record type required. DSET_AI must be defined - because an init_ai routine must be implemented as described below. If you also define - DSET_AIRAW the associated .dbd file must specify different DTYP strings for the - DSET_AI and DSET_AIRAW device declarations.

-

- Likewise, if you define both DSET_AO and DSET_AORAW the associated .dbd file must - specify different DTYP strings for the DSET_AO and DSET_AORAW device declarations.

-

- devCommonGpib provides device support for many standard record types. It is also - possible to create custom support, but this is more difficult.

-

- gpibCmd Definitions

-

- This is where the translation to and from the language of the instrument is defined. - The actual table contains one element for each parameter that is made available - to the user via the @<number> portion of an INP or OUT field.

-

- In the example above the definitions for the gpibCmds are:

-
static struct gpibCmd gpibCmds[] =
-{
-  /* Param 0 */
-  {&DSET_BO, GPIBEFASTO, IB_Q_HIGH, 0, 0, 0, 32,0, 0, 0, userOffOn, &offOn, 0},
-  /* definitions for other parameters follow*/
-};
-

- This example defines a single command. A database record using this definition must - define field OUT as

-
field(OUT,,"#L<link> A<addr> @0")
-

- gpibCmd is

-
typedef struct gpibCmd {
-    gDset *dset; /* used to indicate record type supported */
-    int type;    /* enum - GPIBREAD...GPIBSRQHANDLER */
-    short pri;   /* request priority IB_Q_LOW, IB_G_MEDIUM, or IB_Q_HIGH */
-    char *cmd;   /* CONSTANT STRING to send to instrument */
-    char *format;/* string used to generate or interpret msg */
-    int rspLen;  /* room for response error message */
-    int msgLen;  /* room for return data message length */
-    /*convert is optional custom routine for conversions */
-    int (*convert) (gpibDpvt *pgpibDpvt,int P1, int P2, char **P3);
-    int P1;      /* P1 plays a dual role: */
-                 /*      For EFAST it is set internally to the
-                 /*      number of entries in the EFAST table */
-                 /*      For convert it is passed to convert() */
-    int P2;      /* user defined parameter passed to convert() */
-    char **P3;   /* P3 plays a dual role: */
-                 /*      For EFAST it holds the address of the EFAST table */
-                 /*      For convert it is passed to convert() */
-    devGpibNames *pdevGpibNames; /* pointer to name strings */
-    char * eos; /* input end-of-string */
-} gpibCmd;
-

- where

-
-
dset
-
- Address of the Device Support Entry Table (DSET) that describes the record type - supported by the table entry.
-
type
-
- Type of GPIB I/O operation that is to be performed. The type field - must be set to one of the enumerated values declared in devSupportGpib.h, i.e. GPIBREAD,...,GPIBSRQHANDLER. - See next section for the definitions.
-
pri
-
- Processing priority of the I/O operation. Must be IB_Q_HIGH, IB_Q_MEDIUM, - or IB_Q_LOW.
-
cmd
-
- Constant string that is used differently depending on the value of type. - See the discussion of type below. Set this field to 0 if not used.
-
format
-
- Printf/scanf format string that is used differently depending on the value of - type. See the discussion of type. Set this field to 0 if not - used.
-
rspLen
-
- Size needed to read back from a device when performing a respond2Writes read operation. - If a gpibCmd is a read operation or a write operation that does not respond, then - set this field to zero. When devGpib initializes, it finds the maximum rspLen of - all commands associated with a port instance and allocates storage of that size.
-
msgLen
-
- Size needed to read or write from a device. If not needed, set it to zero. When - devGpib initializes it finds the maximum msgLen of all commands associated with - a port instance and allocates storage of that size.
-
convert
-
- A conversion function that has the prototype: -
 int (*convert) (gpibDpvt *pgpibDpvt,int P1, int P2, char **P3);
- The use depends on the pgpibCmd->type. See below for details. Set to 0 when no - conversion function is present. -

- Conversion routines should return 0 to signify a successful conversion. If a convert - routine finds an error, it should do the following:

-
    -
  • Generate an error message as follows: -
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
    -                                                    "<format>",...);
    -
  • -
  • return -1 to signify failure
  • -
-
-
P1
-
- This plays a dual role. -

- For EFAST operations it is set equal to the number of entries in the efast table - by devSupportGpib:init_record.

-

- For other operations, it is an integer passed to the conversion function specified - in convert.

-
-
P2
-
- Integer passed to the conversion function specified in convert.
-
P3
-
- This field plays a dual role. -

- When type is one of the EFAST operations, this field points to the - EFAST table. See the EFAST operation descriptions under the type field - definitions and the section "Efast Tables" for more on the use of this field. Set - this field to 0 when it is not used.

-

- For other operations, it is passed to the conversion function specified in convert. - It has a char** value.

-
-
pdevGpibNames
-
- Pointer to a Name Table. Name tables are described in the section "Name Tables". - Set this to 0 when no Name Table is used.
-
eos
-
- Input message termination string. It can be: -
-
0
-
- A NULL pointer means that this read operation will be terminated by the current - asynOctetSetInputEos value, if any.
-
""
-
- An empty string signifies that a single null character ('\0') is the terminator - for this operation.
-
non-empty string (e.g. "\n")
-
- The termination characters (not including the null character terminating the string) - for this operation. For example, "\n" sets the message terminator to - a single ASCII newline ('\n') character. Some drivers, e.g. the VXI-11, - allow only a single termination character.
-
-
-
-

- Definitions for pgpibCmd->type

-

- The following describes the semantics for the device support provided by the devGpib - support provided with asynDriver. If an application extends this support, it must - document its changes.

-
-
GPIBREAD
-
-

- Supports record types: ai, bi, event, longin, mbbi, mbbiDirect, stringin, and waveform. - For all of these types the following is done.

-
    -
  • Send pgpibCmd->cmd to the instrument.
  • -
  • Read from the instrument into pgpibDpvt->msg. -
    - pgpibCmd->msgLen must specify a size large enough for the message.
  • -
-

- If convert is defined then:

-
    -
  • convert is called. It is expected to give a value to the appropriate - field (RVAL for bi, mbbi, mbbiDirect and VAL for all others) of the record or return - -1. Note that it is the responsiblity of the custom conversion routine to set or - clear the record .UDF field.
  • -
  • The field pgpibDpvt->msgInputLen contains the number of bytes - in the last read msg. This allows messages with null characters to be processed.
  • -
  • Record completion occurs.
  • -
-

- If convert is not defined then what is done depends on the record type.

-
    -
  • bi, event, longin, mbbi, and mbbiDirect. -

    - pgpibDpvt->msg is converted and the result put into field RVAL (bi, - mbbi, mbbiDirect) or VAL (event, longin). If pgpibCmd->format is defined it is - used for the conversion, otherwise a format appropriate to the data type of RVAL/VAL - is used.

    -
  • -
  • ai -

    - pgpibDpvt->msg is converted and the result put into field VAL or - RVAL. VAL is used if the DSET does NOT define special_linconv and RVAL is used if - special_linconv is defined. If pgpibCmd->format is defined, it is used for the - conversion. Otherwise, a format appropriate to the field is used. The DSET generated - by devGpib.h does not define special_linconv.

    -
  • -
  • stringin -

    - pgpibDpvt->msg is converted and the result put into field VAL. If - pgpibCmd->format is defined it is used for the conversion, otherwise "%39c" is - used.

    -
  • -
  • waveform -

    - Unless FTVL is menuFtypeCHAR, an error is generated and the record is put into alarm. - If FTVL is menuFtypeCHAR,then epicsSnprintf is used to convert pgpibDpvt->msg - into BPTR. If format is defined it is used, otherwise "%s" is used.

    -

    -

    -
  • -
-
-
GPIBWRITE
-
-

- Supports record types: ao, bo, longout, mbbo, mbboDirect, stringout, and waveform.

-
    -
  • If convert is defined, it is called. It must put a command string - into pgpibDpvt->msg. It can return: -
      -
    • -1 -

      - Signifies error. The operation is aborted and the record put into alarm.

      -
    • -
    • 0 -

      - Success and call strlen to determine the length of msg.

      -
    • -
    • >0 -

      - Success and the return value is the number of bytes in msg.

      -
    • -
    -
  • -
  • If convert is not defined, then what happens is determined by the - record type. -
      -
    • ao -

      - If special_linconv is NOT defined in DSET, the RVAL field is converted as a long - into msg. If special_linconv is defined, OVAL is converted as a double into msg.

      -
    • -
    • bo, mbbo, and mbboDirect -

      - VAL is converted as an unsigned long into msg.

      -
    • -
    • longout -

      - VAL is converted as a long into msg.

      -
    • -
    • stringout -

      - VAL is converted into msg via epicsSnprintf. If pgpibCmd->format is defined it - is used, otherwise "%s" is used.

      -
    • -
    • waveform -

      - BPTR is converted into msg via epicsSnprintf. If pgpibCmd->format is defined - it is used, otherwise "%s" is used.

      -
    • -
    -
  • -
  • pgpibDpvt->msg is sent to the instrument. -

    -

    -
  • -
-
-
GPIBCVTIO
-
-

- Supports record types:

-

- ai, ao, bi, bo, event, longin.longout, mbbi, mbbo, mbbiDirect, mmboDirect, stringin, - stringout, waveform.

-

- All I/O is done by the convert routine, which must be defined. - convert is called by a callback routine and thus can make an arbitrary - number of calls to low level drivers. It is passed the address of gpibDpvt - which contains the information needed to call the low level drivers: asynCommon, - asynOctet, and asynGpib. Note that asynGpib may not be present, - i.e. pasynGpib is null. gpibDpvt also contains a field - pupvt which can be used by the convert routine. Is is initialized to - null. The macro gpibCmdGet can be used to get the address of gpibCmd - which contains other usefull information.

-

- If the End of String terminator needs to be changed, it must be changed by calling - pdevSupportGpib->setEos rather than calling pgpibDpvt->pasynOctet->setEos - Also when the convert routine has finished with read operations it - must call pdevSupportGpib->restoreEos

-

- Subsection "gpibCmd convert example" below provides an example.

-
-
-
GPIBCMD
-
-

- Supports record types: ao, bo, longout, mbbo, mbboDirect, stringout, and waveform.

-

- Send the command string specified in pgpibCmd->cmd to the instrument - exactly as specified.

-

-

-
-
GPIBACMD
-
- This is like GPIBCMD except that ATN is held active. This should rarely be necessary. -

-

-
-
GPIBSOFT
-
- No I/O is done. It calls pgpibCmd->convert. pgpibCmd->convert - must be defined If GPIBSOFT fails, it calls asynPrint with mask - ASYN_TRACE_ERROR and also puts the record into alarm. -

-

-
-
GPIBREADW
-
- Like GPIBREAD except for that it waits for the device to issue an SRQ before it - issues the read request. -

-

-
-
GPIBRAWREAD
-
- Like GPIBREAD except that no command is sent to the instrument. -

-

-
-
GPIBEFASTO
-
-

- This operation type is only valid on BO and MBBO record types. pgpibCmd->P3 - must contain the address of an efast table. At init time some checks are made to - see that an efast table is defined, but if it is defined incorrectly problems may - arise.

-

- The following is done:

-
    -
  • Device support sets pibDpvt.efastVal equal to the VAL field.
  • -
  • If pgpibCmd->cmd is not null, then msgLen must also - be specified. msg is set equal to the concatenation of cmd - and the efast value specified by pgpibCmd->P3. The resulting - msg is sent.
  • -
  • If pgpibCmd->cmd is null, then the string pointed to by - pgpibCmd->P3[efastVal] is sent. -

    -

    -
  • -
-
-
GPIBEFASTI
-
-

- This operation type is only valid on BI and MBBI record types.

-

- The following is done:

-
    -
  • Send the command string specified in cmd to the instrument exactly - as specified.
  • -
  • Read the data from the instrument and place it into pgpibDpvt->msg.
  • -
  • Compare msg with each element of the EFAST table referenced by - pgpibCmd->P3.
  • -
  • devSupportGpib sets pgpibDpvt->efastVal to the index of the EFAST - table that matched.
  • -
  • Device support sets RVAL equal to pgpibDpvt->efastVal. -

    -

    -
  • -
-
-
GPIBEFASTIW
-
- This operation type is like GPIBEFASTI except that it waits for the device to raise - SRQ before the data is read. -

-

-
-
GPIBIFC
-
-

- Valid only for BO records. If rval = (0,1) then (do nothing, pulse IFC). IFC is - one of the GPIB Bus Management Lines.

-

- Only define dset, type, and pri. A default - pdevGpibNames is provided. For example

-
{&DSET_BO, GPIBIFC, IB_Q_LOW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
-      
-
-
GPIBREN
-
-

- Valid only for BO records. If rval = (0,1) then (drop,assert) REN. REN is one of - the GPIB Bus Management Lines.

-

- If devices are in the LLO state they can be removed from this state by toggling - the REN line, i.e. turn it off and then turn it back on.

-

- Only define dset, type, and pri. A default - pdevGpibNames is provided.

-

-

-
-
GPIBDCL
-
-

- Valid only for BO records. If rval = (0,1) then (do nothing, send DCL). DCL is a - Universal GPIB command, i.e. it applys to all devices on the link

-

- Only define dset, type, and pri. A default - pdevGpibNames is provided.

-

-

-
-
GPIBLLO
-
-

- If rval = (0,1) then (do nothing, send LLO). LLO is a Universal GPIB command, i.e. - it applys to all devices on the link

-

- After a LLO, the first time a device is addressed it will disable local control, - i.e. the front pannel controls will not respond. To remove devices from this state - toggle the REN line. A single device can temporarily be removed from LLO by sending - the GPIBCTL command but it will go back to LLO state as soon as it is again addressed.

-

- Only define dset, type, and pri. A default - pdevGpibNames is provided.

-

-

-
-
GPIBSDC
-
-

- If rval = (0,1) then (do nothing, send SDC). SDC is an addressed GPIB command, i.e. - it applys only to the addressed device.

-

- Only define dset, type, and pri. A default - pdevGpibNames is provided.

-

-

-
-
GPIBGTL
-
-

- If rval = (0,1) then (do nothing, send GTL). GTL is an addressed GPIB command, i.e. - it applys only to the addressed device.

-

- If a device has local control locked out, local control can be temporarily granted - by issuing this command. However the next time the device is addressed it will again - disable local control.

-

- Only define dset, type, and pri. A default - pdevGpibNames is provided.

-

-

-
-
GPIBSRQHANDLER
-
- This is used to handle an unsolicited SRQ from gpibAddr, i.e. a device raises SRQ - when a read wait, e.g. GPIBREADW or GPIBEFASTIW, is not active. This request is - implemented only for longin records. When the device issues an SRQ, the status byte - is put into the val field and the record is processed. It is expected that the record - will forward link to records that issue GPIB commands to read the information that - caused the SRQ.
-
-

- Efast (Enumerated Fast I/O) Tables

-

- A device's command set often has things like "OFF" or "ON" in the command string. - It is convenient to issue such commands via binary and multibit binary records. - Efast tables specify such strings. Simply specify the string value for each of the - possible states of the VAL field of the record.

-

- The format of an efast table is:

-
    static char  *tableName[] = {
-        "OFF",    /* when VAL = 0 */
-        "ON",    /* when VAL = 1 */
-        0        /* list terminator */
-  }; 
-

- And is referenced in an output parameter table entry like this:

-
    {&DSET_BO, GPIBEFASTO, IB_Q_HIGH, 0, 0, 0, 0,0, 0, 0, tableName, 0, 0},
-

- For an input entry, it would look like this:

-
    {&DSET_BI, GPIBEFASTI, IB_Q_HIGH, "<command>", 0, 0, 50, 0, 0, 0, 
-
     tableName, 0, 0},
-

- The efast table MUST be 0 terminated.

-

- For outputs the VAL field is used to index into the efast table and select a string - to send to the instrument. If cmd is 0, the string is sent to the instrument - exactly as as it appears in the efast table. If cmd is defined, then - that string is prepended to the string obtained from the efast table.

-

- For input operations, the cmd string is sent to the instrument, and - msg is read from the instrument. msg is compared against - each of the entries in the efast table starting at the zeroth entry. The slot number - of the first table entry that matches the response string is used as the setting - for the RVAL field of the record. When strings are compared, they are compared from - left to right until the number of characters in the efast table are checked. When - ALL of the characters up to but NOT including the 0 of the string in the - efast table match the corresponding characters of the response string, it is considered - a valid match. This allows the user to check response strings fairly fast. For example, - if a device returns something like "ON;XOFF;9600" or "OFF;XOFF;9600" in response - to a status check, and you wish to know if the first field is either "OFF" or "ON", - your efast table could look like this:

-
    static char *statCheck[] = {
-        "OFF",      /* set RVAL to 0 */
-        "ON",      /* set RVAL to 1 */
-        0};     /* list terminator */
-

- The 0 field is extremely important. If it is omitted and the instrument - gets confused and responds with something that does not start with an "OFF" or "ON", - the GPIB support library code will end up running off the end of the table.

-

- In the case when none of the choices in an efast table match for an input operation, - the record is placed into a INVALID alarm state.

-

- devGpibNames - Name Table

-

- For binary and multibit binary records, the choice fields of a record can be assigned - values at record initialization. If pdevGpibNames has a value, then when a record - is initialized, the instrument support uses the associated name table to assign - values to choice fields that have not been assigned values. These name tables have - nothing to do with I/O operations.

-

- devGpibNames is:

-
struct devGpibNames {
-    int count;            /* CURRENTLY only used for MBBI and MBBO */
-    char **item;
-    unsigned long *value; /* CURRENTLY only used for MBBI and MBBO */
-    short nobt;           /* CURRENTLY only used for MBBI and MBBO */
-};
-

- To use a name table, the address of the table must be put into pdevGpibNames - of the parameter table. The table format for a multibit record type looks like this:

-
    static char *tABCDList[] = {
-        "T",                 /* zrst*/
-        "A",                 /* onst */
-        "B",                 /* twst */
-        "C",                 /* thst */
-        "D"};                /* frst */
-
-    static unsigned long tABCDVal[] = {
-        1,                  /* zrvl */
-        2,                  /* onvl */
-        3,                  /* twvl */
-        5,                  /* thvl */
-        6 };                /* frvl */
-
-    static devGpibNames tABCD = {
-        5,                  /* number of elements in string table */
-        tABCDList,          /* pointer to string table */
-        tABCDVal,           /* pointer to value table */
-        3 };                /* value for the nobt field */
-

- The table format for a binary record type looks like this:

-
    static char *disableEnableList[] = { 
-        "Disable",          /* znam */
-        "Enable" };         /* onam */
-
-    static devGpibNames disableEnable = {
-        2,                  /* number of elements */
-        disableEnableList,  /* pointer to strings */
-        0,               /* pointer to value list */
-        1};                 /* number of valid bits */
-

- devGpibNames is defined in devSupportGpib.h. For binary - records, the strings are placed into the name fields in order from lowest to highest - as shown above. For multibit binary records, up to sixteen strings can be defined. - A devGpibNames structure referencing these strings is then defined.

-

- value and nobt are not used for binary record types, but - should be specified anyway as if the binary record was a multibit binary record - with only 2 values.

-

- For multibit record types, the name strings, values, and NOBT fields are filled - in from the devGpibNames information. For binary record types, only - the znam and onam fields are filled in.

-

- Name strings (and their associated values in the multibit cases) are not filled - in if the database designer has assigned them values.

-

- Defining the devGpibParmBlock

-

- Each DSET of the instrument support contains the address of a devGpibParmBlock. - init_ai MUST initialize this structure. For example:

-
static long init_ai(int parm)
-{
-    if(parm==0) {
-        devSupParms.name = "devSkeletonGpib";
-        devSupParms.gpibCmds = gpibCmds;
-        devSupParms.numparams = NUMPARAMS;
-        devSupParms.timeout = TIMEOUT;
-        devSupParms.timeWindow = TIMEWINDOW;
-        devSupParms.respond2Writes = -1;
-    }
-    return(0);
-}
-

- devGpibParmBlock is:

-
struct devGpibParmBlock {
-    char *name;         /* Name of this device support*/
-    gpibCmd *gpibCmds;  /* pointer to gpib command list */
-    int numparams;  /* number of elements in the command list */
-    double timeout; /* seconds to wait for I/O */
-    double timeWindow;  /* seconds to stop I/O after a timeout*/
-    double respond2Writes; /* set >= 0 if device responds to writes */
-    /*The following are set by devSupportGpib*/
-    int  msgLenMax;     /*max msgLen all commands*/
-    int  rspLenMax;     /*max rspLen all commands*/
-};
-
-
gpibCmds
-
-
name
-
- The device support module type name. Used only to generate diagnostic messages.
-
- Address of an array of gpibCmd definitions.
-
numparams
-
- The number of gpibCmds defined. A macro should be used to set its value.
-
timeout
-
- timeout in seconds for an individual I/O operation.
-
timeWindow
-
- The number of seconds after a timeout before a new I/O operation will be issued - to the device. During this time window, any I/O operations directed to the timed - out device will result in an error, and the appropriate alarm status will be raised - for the record (either READ_ALARM or WRITE_ALARM depending on the record type and - VALID_ALARM in all cases.)
-
respond2Writes
-
- This field is for devices that echo writes. If respond2Writes >=0 then after - an output command the following is done: -
    -
  • If pgpibCmd->rspLen is <=0 no action is taken. This is a way to override - respond2Writes for specific commands.
  • -
  • If respond2Writes is >0 then a wait of respond2Writes milliseconds occurs.
  • -
  • A read of up to pgpibCmd->rspLen bytes (terminated earlier by GPIB EOI or by - the terminator string, if any) is read into pgpibDpvt->rsp.
  • -
-
-
msgLenMax
-
- This is set by devGpibSupport. The value is that of the maximum size input message, - i.e. the largest msgLen defined in gpibCmds.
-
rspLenMax
-
- This is set by devGpibSupport. The value is that of the maximum size response message, - i.e. the largest rspLen defined in gpibCmds.
-
-

- SRQ Processing

-

- If the low level device driver implements interface asynGpib, then - devSupportGpib registers itself to handle SRQs. It defines two types of SRQs: solicited - and unsollicited. Solicited SRQs are for GPIBREADW and GPIBEFASTIW commands. If - an SRQ is raised for a gpibAddr that does not have an outstanding GPIBREADW or GPIBEFASTIW - command, the SRQ is considered unsolicited.

-

- When the devSupportGpib receives an unsolicited SRQ and it has a registered handler - for the gpibAddr, it calls the handler. Otherwise it issues a message that it received - an unsolicited SRQ.

-

- The device support for the longinRecord supports gpibCmd type GPIBSRQHANDLER. It - calls the devSupportGpib registerSrqHandler method. When its interruptCallbackInt32 - gets called, it puts the SRQ status byte into the VAL field and then makes a request - to process the record. By forward linking this record to other records, the user - can handle SRQs from specific devices. Note that the callback is an interruptCallbackInt32 - since asynGpib handles SRQ callbacks via the asynInt32 interface and using asynUser.reason - = ASYN_REASON_SIGNAL.

-

- To save time during SRQ polling operations it is possible to exclude a device which - has become disconnected from the bus for some reason and then to restore the device - to the polling list when the device is reattached. A binary output record with the - following command table entry is used for this purpose:

-

- /* Add/remove address from SRQ polling list */

-

- { &DSET_BO,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,0,boSRQonOff,0,0,NULL,NULL,NULL - }

-

- If the binary-output record rval is (0, 1) then (remove, add) device (from, to) - the SRQ polling liist. No commands are sent to the bus. Before exluding a device - from being polled stop any communications to it, i.e. set SCAN-field(s) to PASSIVE - and turn off the device.

-

- gpibCmd convert example

-

- The asyn distribution includes an example of how to implement the convert parameter - for a gpibCmd. The example is in asyn/devGpib/devGpibConvertExample.c. It defines - three gpibCmds for stringin and three for stringout records. All three input commands - have the same result and all three output commands have the same result. The difference - is how much is done by devGpib support and how much is done by the instrument support.

-

- The example show how a convert routine can access fields from the devGpibsupport.

-

- The command tables are:

-
static struct gpibCmd gpibCmds[] =
-{
-  /* Param 0 */
-  {&DSET_SI,GPIBREAD,IB_Q_LOW,"*IDN?", 0,0,200,0,0,0,0,0,0},
-  /* Param 1 simple convert   */
-  {&DSET_SI,GPIBREAD,IB_Q_LOW,"*IDN?",0,0,200,readString,0,0,0,0,0},
-  /* Param 2,example of GPIBCVTIO */
-  {&DSET_SI,GPIBCVTIO,IB_Q_LOW,"*IDN?",0,0,200,readCvtio,0,0,0,0,0},
-  /* Param 3 */
-  {&DSET_SO,GPIBWRITE,IB_Q_LOW,0,0,0,200,0,0,0,0,0,0},
-  /* Param 4 simple convert   */
-  {&DSET_SO,GPIBWRITE,IB_Q_LOW,0,0,0,200,writeString,0,0,0,0,0},
-  /* Param 5,example of GPIBCVTIO */
-  {&DSET_SO,GPIBCVTIO,IB_Q_LOW,0,0,0,200,writeCvtio,0,0,0,0,0}
-};
-

- The command for Param 0 lets the devGpib support do everything as follows:

-
    -
  • The command "*IDN?" is sent to the instrument.
  • -
  • A responds is read back from the instrument.
  • -
  • device suipport for the stringin record copies the response to the VAL field of - the record.
  • -
-

- The command for Param 1 is similar except that, after the response is read from - the instrument, readString is called. It copies the response to VAL.

-

- The command for Param 2 causes the devGpib support to call readCvtio without doing - any I/O. The convert routine is responsible for all I/O.

-

-

-

- The command for Param 3 lets the devGpib support do everything as follows:

-
    -
  • Device support for the stringout record copies the current value of the VAL field - to a message buffer.
  • -
  • The message buffer is sent to the instrument.
  • -
-

- The command for Param 4 is similar except that writeString is called to move the - value of the VAL field to the message buffer.

-

- The command for Param 5 causes the devGpib support to call writeCvtio without doing - any I/O. The convert routine is responsible for all I/O.

-

-

-

- The actual code for the convert routines is:

-
static int readString(gpibDpvt *pgpibDpvt,int P1, int P2, char **P3)
-{
-    stringinRecord *precord = (stringinRecord*)pgpibDpvt->precord;
-    strncpy(precord->val,pgpibDpvt->msg,sizeof(precord->val));
-    precord->val[sizeof(precord->val) - 1] = 0;
-    return(0);
-}
-static int readCvtio(gpibDpvt *pgpibDpvt,int P1, int P2, char **P3)
-{
-    stringinRecord *precord = (stringinRecord*)pgpibDpvt->precord;
-    asynUser *pasynUser = pgpibDpvt->pasynUser;
-    gpibCmd *pgpibCmd = gpibCmdGet(pgpibDpvt);
-    asynOctet *pasynOctet = pgpibDpvt->pasynOctet;
-    void *asynOctetPvt = pgpibDpvt->asynOctetPvt;
-    asynStatus status;
-    size_t nchars = 0, lenmsg = 0;
-    pgpibDpvt->msgInputLen = 0;
-
-    assert(pgpibCmd->cmd);
-    lenmsg = strlen(pgpibCmd->cmd);
-    status  = pasynOctet->write(asynOctetPvt,pasynUser,
-        pgpibCmd->cmd,lenmsg,&nchars);
-    if(nchars==lenmsg) {
-        asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE,pgpibCmd->cmd,nchars,
-                                            "%s readCvtio\n",precord->name);
-    } else {
-        asynPrint(pasynUser,ASYN_TRACE_ERROR,
-            "%s write status \"%s\" requested %d but sent %d bytes\n",
-                precord->name,pasynUser->errorMessage,lenmsg,nchars);
-            return -1;
-    }
-    if(!pgpibDpvt->msg) {
-        asynPrint(pasynUser,ASYN_TRACE_ERROR,
-            "%s pgpibDpvt->msg is null\n",precord->name);
-        nchars = 0; return -1;
-    } else {
-        status = pasynOctet->read(asynOctetPvt,pasynUser,
-            pgpibDpvt->msg,pgpibCmd->msgLen,&nchars,0);
-    }
-    asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s readCvtio nchars %d\n",
-        precord->name,nchars);
-    if(nchars > 0) {
-        asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE,pgpibDpvt->msg,nchars,
-            "%s readCvtio\n",precord->name);
-    } else {
-        asynPrint(pasynUser,ASYN_TRACE_ERROR,
-            "%s read status \"%s\" nin %d\n",
-            precord->name, pasynUser->errorMessage,nchars);
-        pgpibDpvt->msgInputLen = 0;
-        return -1;
-    }
-    pgpibDpvt->msgInputLen = nchars;
-    if(nchars<pgpibcmd->pgpibcmd->msgLen) pgpibDpvt->msg[nchars] = 0;
-    readString(pgpibDpvt,P1,P2,P3);
-    return 0;
-}
-
-static int writeString(gpibDpvt *pgpibDpvt,int P1, int P2, char **P3)
-{
-    asynUser *pasynUser = pgpibDpvt->pasynUser;
-    stringoutRecord *precord = (stringoutRecord*)pgpibDpvt->precord;
-    int            nchars;
-    gpibCmd *pgpibCmd = gpibCmdGet(pgpibDpvt);
-    char *format = (pgpibCmd->format) ? pgpibCmd->format : "%s";
-
-    if(!pgpibDpvt->msg) {
-        asynPrint(pasynUser,ASYN_TRACE_ERROR,
-            "%s no msg buffer. Must define gpibCmd.msgLen > 0.\n",
-            precord->name);
-        recGblSetSevr(precord,WRITE_ALARM, INVALID_ALARM);
-        return -1;
-    }
-    nchars = epicsSnprintf(pgpibDpvt->msg,pgpibCmd->msgLen,format,precord->val);
-    if(nchars>pgpibCmd->msgLen) {
-        asynPrint(pasynUser,ASYN_TRACE_ERROR,
-            "%s msg buffer too small. msgLen %d message length %d\n",
-            precord->name,pgpibCmd->msgLen,nchars);
-        recGblSetSevr(precord,WRITE_ALARM, INVALID_ALARM);
-        return -1;
-    }
-    asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s writeMsgString\n",precord->name);
-    return nchars;
-}
-
-static int writeCvtio(gpibDpvt *pgpibDpvt,int P1, int P2, char **P3)
-{
-    stringoutRecord *precord = (stringoutRecord*)pgpibDpvt->precord;
-    asynUser *pasynUser = pgpibDpvt->pasynUser;
-    asynOctet *pasynOctet = pgpibDpvt->pasynOctet;
-    void *asynOctetPvt = pgpibDpvt->asynOctetPvt;
-    asynStatus status;
-    size_t nsent = 0, lenmsg = 0;
-    pgpibDpvt->msgInputLen = 0;
-
-    lenmsg = writeString(pgpibDpvt,P1,P2,P3);
-    if(lenmsg <= 0) return -1; status=pasynOctet->write(asynOctetPvt,pasynUser,
-        pgpibDpvt->msg,lenmsg,&nsent);
-    if(nsent==lenmsg) {
-        asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE,pgpibDpvt->msg,lenmsg,
-                                            "%s writeCvtio\n",precord->name);
-    } else {
-        asynPrint(pasynUser,ASYN_TRACE_ERROR,
-            "%s write status \"%s\" requested %d but sent %d bytes\n",
-                precord->name,pasynUser->errorMessage,lenmsg,nsent);
-            return -1;
-    }
-    return 0;
-}
-
-

- devCommonGpib

-

- The facilities described above should satisfy most gpib requirements. This section - and the next explain how to provide additional support. For example, support could - be written for additional record types. This section explains devCommonGpib, and - the next section explains devSupportGpib.

-

- devCommonGpib provides support for specific record types by making calls to devSupportGpib. - As explained above, an instrument support module must define some combination of - DSET_AI,...,DSET_WF and then include devGpib.h. devGpib.h defines DSETs (Device - Support Entry Tables) that refer to methods implemented in devCommonGpib.c

-

- If you want to write additional support code that can be used for writing instrument - specific device support, the easiest way is to start with code in devCommonGpib - and modify it.

-

- devGpib provides three header files:

-
    -
  • devCommonGpib.h - This defines the function prototypes for the methods implemented - in devCommonGpib.c
  • -
  • devGpib.h - Included in instrument specific device support. It generates DSETs - referring to the functions implemented in devCommonGpib.
  • -
  • devSupportGpib.h - Describes the structures gpibCmd, devGpibNames, and devGpibParmBlock - described above. It also describes additional structures described in the next section.
  • -
-
-

- devSupportGpib

-

- devSupportGpib.h describes all the public structures used by devGpib. The structures - gpibCmd, devGpibNames, and devGpibParmBlock were described above. They are needed - to create an instrument device support module. The remaining structures are used - by devCommonGpib, devSupportGpib, or other support. These structures are: gDset, - gpibDpvt, devGpibPvt, and devSupportGpib.

-

-

-

- gDset

-

- A gDset is an "overloaded" definition of a DSET. A gDset looks to iocCore like a - regular DSET, but it has an additional field that is the address of a devGpibParmBlock.

-
struct gDset
-{
-    long number;
-    DEVSUPFUN funPtr[6];
-    devGpibParmBlock *pdevGpibParmBlock;
-};
-

- where

-
-
number
-
- This is required for a DSET. It should always be initialized to 6.
-
funPtr
-
- Pointers to device support functions. Allowing for 6 is sufficient for all the standard - types in EPICS base.
-
pdevGpibParmBlock
-
- The address of the devGpibParmBlock for this instrument.
-
-

- gpibDpvt

-

- The dpvt field of a record with devGpib device support contains the address of a - gpibDpvt

-
struct gpibDpvt
-{
-    devGpibParmBlock *pdevGpibParmBlock;
-    CALLBACK callback;
-    dbCommon *precord;
-    asynUser *pasynUser;
-    asynCommon *pasynCommon;
-    void *pasynCommonPvt;
-    asynOctet *pasynOctet;
-    void *pasynOctetPvt;
-    asynGpib *pasynGpib;
-    void *pasynGpibPvt;
-    int parm;                 /* parameter index into gpib commands */
-    char *rsp;                /* for read/write message error responses */
-    char *msg;                /* for read/write messages */
-    int  msgInputLen;         /* number of characters in last READ*/
-    int efastVal;             /* For GPIBEFASTxxx */
-    void     *pupvt;          /*private pointer for custom code*/
-    devGpibPvt *pdevGpibPvt;  /*private for devGpibCommon*/
-};
-

- where

-
-
pdevGpibParmBlock
-
- Address of the devGpibParmBlock. It is the same value as pgDset->pdevGpibParmBlock
-
callback
-
- For use by completeProcess.
-
precord
-
- Address of the record.
-
pasynUser
-
- Address of an asynUser which is needed to call asynDriver support.
-
pasynCommon,pasynCommonPvt
-
- Used to call asynCommon methods. If initialization is successful these will have - a value.
-
pasynOctet,pasynOctetPvt
-
- Used to call asynOctet methods. If initialization is successful these will have - a value.
-
pasynGpib,pasynGpibPvt
-
- Used to call asynGpib methods. These may be 0 even if initialization is successful. - If a record that requires asynGpib is processed and pasynGpib is 0, then an error - message is generated and the record is put into alarm.
-
parm
-
- The value of the parm field of INP or OUT. It locates the gpibCmd for its record.
-
rsp
-
- If respond2Writes is >=0 and rspLen is >0, this is the buffer that holds the - read after each write.
-
msg
-
- A buffer of length msgLen. It is used by several GPIBXXX request types.
-
msgInputLen
-
- The length of the last input message.
-
efastVal
-
- Used for GPIBEFASTO, GPIBEFASTI, GPIBEFASTIW. For GPIBEFASTO the device support - sets efastVal from RVAL or VAL before queuing an I/O request. For GPIBEFASTI and - GPIBEFASTIW, the device support sets RVAL or VAL from efastVal after an I/O request - completes.
-
pupvt
-
- This is a private pointer for use by specialized instrument support.
-
pdevGpibPvt
-
- This is used by devSupportGpib. Note that the structure is described in devSupportGpib.c, - i.e. it is private.
-
-

- devSupportGpib

-

- describes methods implemented by devSupportGpib.c.

-
/* If a method returns int then (0,-1) => (OK, failure) */
-typedef void (*gpibWork)(gpibDpvt *pgpibDpvt,int failure);
-typedef int (*gpibStart)(gpibDpvt *pgpibDpvt,int failure);
-typedef void (*gpibFinish)(gpibDpvt *pgpibDpvt,int failure);
-
-typedef int (*gpibWork)(gpibDpvt *pgpibDpvt,int failure);
-struct devSupportGpib {
-    long (*initRecord)(dbCommon *precord, struct link * plink);
-    void (*processGPIBSOFT)(gpibDpvt *pgpibDpvt);
-    void (*queueReadRequest)(gpibDpvt *pgpibDpvt,gpibStart start,gpibFinish finish);
-    void (*queueWriteRequest)(gpibDpvt *pgpibDpvt,gpibStart start, gpibFinish finish);
-    /* queueRequest returns (0,1) for (failure,success) */
-    int (*queueRequest)(gpibDpvt *pgpibDpvt, gpibWork work);
-    void (*registerSrqHandler)(
-        gpibDpvt *pgpibDpvt,interruptCallbackInt32 handler,void *userPrivate);
-    int (*writeMsgLong)(gpibDpvt *pgpibDpvt,long val);
-    int (*writeMsgULong)(gpibDpvt *pgpibDpvt,unsigned long val);
-    int (*writeMsgDouble)(gpibDpvt *pgpibDpvt,double val);
-    int (*writeMsgString)(gpibDpvt *pgpibDpvt,const char *str);
-    int (*readArbitraryBlockProgramData)(gpibDpvt *pgpibDpvt);
-    int (*setEos)(gpibDpvt *pgpibDpvt,gpibCmd *pgpibCmd);
-    int (*restoreEos)(gpibDpvt *pgpibDpvt,gpibCmd *pgpibCmd);
-    void (*completeProcess)(gpibDpvt *pgpibDpvt);
-};
-epicsShareExtern devSupportGpib *pdevSupportGpib;
-
-
gpibWork
-
- Prototype of a function that is called when a request is dequeued by asynManager. - This can be either a function passed to queueRequest or an internal function that - devGpibSupport uses to implement queueReadRequest and queueWriteRequest.
-
gpibStart
-
- If queueReadRequest or queueWriteRequest is called, the internal gpibWork function - calls the start routine before it processes the request.
-
gpibFinish
-
- If queueReadRequest or queueWriteRequest is called, the internal gpibWork function - calls the finish routine when it is done processing.
-
initRecord
-
- This initializes all the devGpib structures attached to the record starting with - dbCommon.dpvt.
-
processGPIBSOFT
-
- If pgpibCmd->type is GPIBSOFT, just call this method.
-
queueReadRequest
-
- This handles GPIBREADW, GPIBEFASTIW, GPIBREAD, GPIBEFASTI, and GPIBRAWREAD. The - only thing device support needs to provide is work functions to do record specific - processing of the received message. The start function is called before - devGpibSupport issues write/reads and finish is called after the read. - start is optional and not usually required for read operations. The - msg buffer MUST not be accessed except via the start or finish work - functions.
-
queueWriteRequest
-
- This handles GPIBWRITE, GPIBCMD, GPIBACMD, and GPIBEFASTO. Device support provides - a start and finish work function. The start - function is called before devGpibSupport issues a write and finish - is called after the write. The msg buffer MUST not be accessed except via the - start or finish work functions. start must set - msg or efastVal depending on the pgpibCmd->type.
-
queueRequest
-
- The device support provides a work function that is called when the request is dequeued. - queueRequest returns (0,1) if the request (was not, was) queued.
-
report
-
- This generates a report or all devGpib devices.
-
registerSrqHandler
-
- Registers an SRQ handler for gpibAddr.
-
writeMsgLong,writeMsgULong,writeMsgDouble,writeMsgString
-
- pgpibDpvt->msg is written from pgpibCmd->format and the value passed by the - caller.
-
readArbitraryBlockProgramData
-
- Reads zero or more preamble (non-#) characters followed by IEEE-488.2 - definite-length arbitrary block program data followed by the end-of-string specified - by the active gpibCmd entry, and stores the entire response in pgpibDpvt->msg. - This routine is intended for use by custom input functions to read a block of arbitrary - data from a serial-line device.
-
setEos
-
- If the End of String terminator needs to be changed, it must be changed by calling - this rather than calling the low level driver.
-
restoreEos
-
- If code calls setEos it must call restoreEos after all reads are done.
-
completeProcess
-
- If the port can block, callbackRequestProcessCallback is called. If the port can - not block then PACT is set false. Thus before calling queueRequest, the caller should - set PACT true.
-
pdevSupportGpib
-
- An external variable which points to devSupportGpib.
-
-
-

- Changes to Previous EPICS GPIB Support

-

- conversionNotes.html describes - how to convert GPIB device support modules written for the devGpib support that - came with EPICS base 3.13 and earlier. The information also applys to support modules - written for Benjamin Franksen's GPIB support or the gpibCore support since both - of these evolved from the EPICS base GPIB support.

-

- General GPIB Problems

-

- NOTE: The following comments are from John Winan's original GPIB documentation.

-

- Every type of communication system has its problems. Some instrument vendors don't - properly test the GPIB interfaces on their products. Some devices miss messages - or commands that are too close together in time. There are handshaking lines that - are supposed to throttle the speed, but are apparently improperly implemented by - device vendors, or make the (wrong) assumption that the controller in charge is - slow in its ability to burst bytes down the bus. The only way that this problem - can be worked around is to add delays in the GPIB device device support modules. - The current device support library does not provide any means to do this.

-

- Very often, a device will slow down over 800% when a user presses a button on the - front panel of the device. This can cause the GPIB message transfer to time out, - alarms to be set, and so on. When devices of this type have to be used, operators - will have to be instructed to "look, but don't touch."

-

- Some devices like to go out to lunch once every hour, or day or so, and not respond - to a command for up to about 5 seconds (the DG 535 has done this on more than one - occasion.) This can be more frustrating that anything else. All that can be said - about these types of things is BEWARE of machines that don't work as advertised. - There is probably something wrong with it that won't surface until it is in use - and controlling something very important.

-

- Test, test, and test your devices after writing a new device support module. Many - devices can run fine if doing only three or five transactions per second, but crank - it up to 50 or more, and watch it go up in flames. Even if all the records in an - EPICS database are scanned slowly, they can still get processed in bursts. EPICS - can actually process over 20,000 records in one second if they are all ready to - go at the same time. And if there are enough records tied to the same device, there - is no telling how fast the device will be pushed.

-
-

- License Agreement

-
Copyright (c) 2002 University of Chicago, The Regents of the
-University of California, and Berliner Elektronenspeicherring
-Gesellschaft fuer Synchrotronstrahlung m.b.H. (BESSY) All rights
-reserved.
-
-asynDriver is distributed subject to the following license conditions:
-
- SOFTWARE LICENSE AGREEMENT
- Software: asynDriver
-
- 1. The "Software", below, refers to asynDriver (in either source code, or
-    binary form and accompanying documentation). Each licensee is
-    addressed as "you" or "Licensee."
-
- 2. The copyright holders shown above and their third-party licensors
-    hereby grant Licensee a royalty-free nonexclusive license, subject to
-    the limitations stated herein and U.S. Government license rights.
-
- 3. You may modify and make a copy or copies of the Software for use
-    within your organization, if you meet the following conditions:
-      a. Copies in source code must include the copyright notice and this
-         Software License Agreement.
-      b. Copies in binary form must include the copyright notice and this
-         Software License Agreement in the documentation and/or other
-         materials provided with the copy.
-
- 4. You may modify a copy or copies of the Software or any portion of it,
-    thus forming a work based on the Software, and distribute copies of
-    such work outside your organization, if you meet all of the following
-    conditions:
-      a. Copies in source code must include the copyright notice and this
-         Software License Agreement;
-      b. Copies in binary form must include the copyright notice and this
-         Software License Agreement in the documentation and/or other
-         materials provided with the copy;
-      c. Modified copies and works based on the Software must carry
-         prominent notices stating that you changed specified portions of
-         the Software.
-
- 5. Portions of the Software resulted from work developed under a U.S.
-    Government contract and are subject to the following license: the
-    Government is granted for itself and others acting on its behalf a
-    paid-up, nonexclusive, irrevocable worldwide license in this computer
-    software to reproduce, prepare derivative works, and perform publicly
-    and display publicly.
-
- 6. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY
-    OF ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY LICENSORS, THE
-    UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND THEIR
-    EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
-    BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-    FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME
-    ANY LEGAL LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS,
-    OR USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE
-    SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT
-    THAT THE SOFTWARE WILL FUNCTION UNINTERRUPTED, THAT IT IS ERROR-FREE
-    OR THAT ANY ERRORS WILL BE CORRECTED.
-
- 7. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, THEIR
-    THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT
-    OF ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
-    CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF ANY KIND OR NATURE,
-    INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS OR LOSS OF DATA, FOR ANY
-    REASON WHATSOEVER, WHETHER SUCH LIABILITY IS ASSERTED ON THE BASIS OF
-    CONTRACT, TORT (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR
-    OTHERWISE, EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE
-    POSSIBILITY OF SUCH LOSS OR DAMAGES.
- - diff --git a/documentation/gpibCoreConversion/Makefile b/documentation/gpibCoreConversion/Makefile deleted file mode 100644 index a6cb7a6..0000000 --- a/documentation/gpibCoreConversion/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -HTMLFLAGS = --book --duplex --format pdf14 --title --size letter - -all: conversionNotes.pdf - -%.pdf: %.html - -htmldoc $(HTMLFLAGS) --outfile $@ $< - -clean: - -realclean: clean - rm -f *.pdf diff --git a/documentation/gpibCoreConversion/cvsweb.css b/documentation/gpibCoreConversion/cvsweb.css deleted file mode 100644 index 847df9e..0000000 --- a/documentation/gpibCoreConversion/cvsweb.css +++ /dev/null @@ -1,180 +0,0 @@ -/* CSS for CVSweb pages */ - -body { - color: #000; - background-color: #fff; -} -th { - text-align: left; -} -hr { - height: 1px; - border: none; - background-color: #000; -} -h1 { - text-align: center; -} -fieldset { - background-color: #eee; - padding: 0.8em; -} -input[type="submit"] { - padding-left: 0.5em; - padding-right: 0.5em; -} - -/* Generic nowrap class */ -.nowrap { - white-space: nowrap; -} - -/* Source, diff and annotate views */ -.src { - color: #000; - background-color: #eee; - font-style: normal; - font-weight: normal; -} - -/* Navigation header for source views, diffs and annotations */ -.navigate-header { - background-color: #99e; - padding: 2px; - border: 2px outset; -} - -/* Directory table */ -table.dir { - border-right: 1px solid #ccc; -} -/* Cells */ -table.dir * td { - border-left: 1px solid #ccc; - border-bottom: 1px solid #ccc; - padding-left: 5px; - padding-right: 5px; -} -/* Column headers */ -table.dir * th { - background-color: #ffc; - border: thin outset; - padding-left: 5px; - padding-right: 5px; -} -/* Sorted column header */ -table.dir * th.sorted { - background-color: #fc6; - border: thin inset; -} -/* Even rows */ -table.dir * tr.even { - background-color: #fff; -} -/* Odd rows */ -table.dir * tr.odd { - background-color: #fff; -} -/* File and dir name columns */ -table.dir * td.file, table.dir * td.dir { - white-space: nowrap; -} -/* Graph link column */ -table.dir * td.graph { - padding-left: 3px; - padding-right: 3px; - text-align: center; - width: 1%; -} -/* Age column */ -table.dir * td.age { - font-style: italic; - white-space: nowrap; -} -table.dir * td.author { - white-space: nowrap; -} -/* Log entry column */ -table.dir * td.log { - font-size: smaller; -} -/* Attic toggles in directory view */ -.attic { - font-size: smaller; -} - -/* Option table labels and values */ -.opt-label { - text-align: right; - padding-left: 0.5em; -} -.opt-value { - padding-right: 0.5em; -} - -/* Log entry in markup */ -.log-markup { - background-color: #fff; - width: 100%; -} - -/* Diff-selected revision in log */ -.diff-selected { - padding-right: 0.5em; - border-right: 10px solid #fc6; -} - -/* 'Line'-header of each diffed file */ -.diff-heading { - background-color: #9cc; - border: 2px outset; - padding: 5px; -} -/* Lines that are the same */ -.diff-same { - font-family: Helvetica, Arial, sans-serif; - font-size: smaller; -} -/* Empty lines */ -.diff-empty { - background-color: #ccc; - font-size: smaller; -} -/* Added lines */ -.diff-added { - background-color: #9f9; - font-family: Helvetica, Arial, sans-serif; - font-size: smaller; -} -/* Removed lines */ -.diff-removed { - background-color: #f99; - font-family: Helvetica, Arial, sans-serif; - font-size: smaller; -} -/* Changed lines */ -.diff-changed { - background-color: #ccf; - font-family: Helvetica, Arial, sans-serif; - font-size: smaller; -} -/* Empty changed lines */ -.diff-changed-missing { - background-color: #99c; - font-size: smaller; -} -/* Unchanged text in ediffs */ -.diff-unchanged { - background-color: #ccc; - font-family: Helvetica, Arial, sans-serif; - font-size: smaller; -} - -/* Download links */ -.download-link { - font-weight: bold; -} -/* Display links */ -.display-link { - font-weight: bold; -} diff --git a/documentation/gpibCoreConversion/devKeithley196.c.diff.html b/documentation/gpibCoreConversion/devKeithley196.c.diff.html deleted file mode 100644 index 6c12e3c..0000000 --- a/documentation/gpibCoreConversion/devKeithley196.c.diff.html +++ /dev/null @@ -1,1054 +0,0 @@ -modules/instrument/keithley196/src/devKeithley196.c - diff - 1.5 - - - - - - - - - -

Diff for keithley196/src/devKeithley196.c

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Line 1 - - Line 1 -
 /* devXxK196Gpib.c */ /*************************************************************************\
 /* share/src/devOpt @(#)devXxK196Gpib.c 1.2     3/18/92 */ * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
  *     National Laboratory.
  * Copyright (c) 2002 The Regents of the University of California, as
  *     Operator of Los Alamos National Laboratory.
  * EPICS BASE Versions 3.13.7
  * and higher are distributed subject to a Software License Agreement found
  * in file LICENSE that is included with this distribution.
  \*************************************************************************/
  
 /* /*
  *      Author: John Winans 
  *      Date:   11-19-91 
  * 
  *      Experimental Physics and Industrial Control System (EPICS) 
  * 
  *      Copyright 1988, 1989, the Regents of the University of California, 
  *      and the University of Chicago Board of Governors. 
  * 
  *      This software was produced under  U.S. Government contracts: 
  *      (W-7405-ENG-36) at the Los Alamos National Laboratory, 
  *      and (W-31-109-ENG-38) at Argonne National Laboratory. 
  * 
  *      Initial development by: 
  *              The Controls and Automation Group (AT-8) 
  *              Ground Test Accelerator 
  *              Accelerator Technology Division 
  *              Los Alamos National Laboratory 
  * 
  *      Co-developed with 
  *              The Controls and Computing Group 
  *              Accelerator Systems Division 
  *              Advanced Photon Source 
  *              Argonne National Laboratory 
  * 
  * All rights reserved. No part of this publication may be reproduced, 
  * stored in a retrieval system, transmitted, in any form or by any 
  * means,  electronic, mechanical, photocopying, recording, or otherwise 
  * without prior written permission of Los Alamos National Laboratory 
  * and Argonne National Laboratory. 
  * 
  * Modification Log:  * Modification Log:
  * -----------------  * -----------------
  * .01  05-30-91        jrw     Initial Release  * .01  05-30-91        jrw     Initial Release
  * .02  01-14-02        nda     modified init_dev_sup() per 3.13 req'ts  * .02  01-14-02        nda     modified init_dev_sup() per 3.13 req'ts
   * .03  05-11-04        wen     example of R3.13 to R3.14/ASYN conversion
  */  */
  
   
 #define DSET_AI         devAiK196Gpib #define DSET_AI         devAiK196Gpib
 #define DSET_AO         devAoK196Gpib 
 #define DSET_LI         devLiK196Gpib 
 #define DSET_LO         devLoK196Gpib 
 #define DSET_BI         devBiK196Gpib 
 #define DSET_BO         devBoK196Gpib #define DSET_BO         devBoK196Gpib
 #define DSET_MBBO       devMbboK196Gpib #define DSET_MBBO       devMbboK196Gpib
 #define DSET_MBBI       devMbbiK196Gpib 
 #define DSET_SI         devSiK196Gpib 
 #define DSET_SO         devSoK196Gpib 
  
 #include        <vxWorks.h> 
 #include        <taskLib.h> 
 #include        <rngLib.h> 
 #include        <types.h> 
 #include        <stdioLib.h> 
  
 #include        <alarm.h> 
 #include        <cvtTable.h> 
 #include        <dbDefs.h> 
 #include        <dbAccess.h> 
 #include        <devSup.h> 
 #include        <recSup.h> 
 #include        <drvSup.h> 
 #include        <link.h> 
 #include        <module_types.h> 
 #include        <dbCommon.h> 
 #include        <aiRecord.h> 
 #include        <aoRecord.h> 
 #include        <biRecord.h> 
 #include        <boRecord.h> 
 #include        <mbbiRecord.h> 
 #include        <mbboRecord.h> 
 #include        <stringinRecord.h> 
 #include        <stringoutRecord.h> 
 #include        <longinRecord.h> 
 #include        <longoutRecord.h> 
  
 #include        <drvGpibInterface.h> 
 #include        <devCommonGpib.h> #include        <devCommonGpib.h>
  #include        <devGpib.h>
  
 static  long    init_dev_sup(), report(); 
 static  struct  devGpibParmBlock devSupParms; 
   
 /****************************************************************************** 
  * 
  * Define all the dset's. 
  * 
  * Note that the dset names are provided via the #define lines at the top of 
  * this file. 
  * 
  * Other than for the debugging flag(s), these DSETs are the only items that 
  * will appear in the global name space within the IOC. 
  * 
  * The last 3 items in the DSET structure are used to point to the parm 
  * structure, the  work functions used for each record type, and the srq 
  * handler for each record type. 
  * 
  ******************************************************************************/ 
 gDset DSET_AI   = {6, {report, init_dev_sup, devGpibLib_initAi, NULL, 
         devGpibLib_readAi, NULL, (DRVSUPFUN)&devSupParms, 
         (DRVSUPFUN)devGpibLib_aiGpibWork, (DRVSUPFUN)devGpibLib_aiGpibSrq}}; 
  
 gDset DSET_AO   = {6, {NULL, NULL, devGpibLib_initAo, NULL, 
         devGpibLib_writeAo, NULL, (DRVSUPFUN)&devSupParms, 
         (DRVSUPFUN)devGpibLib_aoGpibWork, NULL}}; 
  
 gDset DSET_BI   = {5, {NULL, NULL, devGpibLib_initBi, NULL, 
         devGpibLib_readBi, (DRVSUPFUN)&devSupParms, 
         (DRVSUPFUN)devGpibLib_biGpibWork, (DRVSUPFUN)devGpibLib_biGpibSrq}}; 
  
 gDset DSET_BO   = {5, {NULL, NULL, devGpibLib_initBo, NULL, 
         devGpibLib_writeBo, (DRVSUPFUN)&devSupParms, 
         (DRVSUPFUN)devGpibLib_boGpibWork, NULL}}; 
  
 gDset DSET_MBBI = {5, {NULL, NULL, devGpibLib_initMbbi, NULL, 
         devGpibLib_readMbbi, (DRVSUPFUN)&devSupParms, 
         (DRVSUPFUN)devGpibLib_mbbiGpibWork, (DRVSUPFUN)devGpibLib_mbbiGpibSrq}}; 
  
 gDset DSET_MBBO = {5, {NULL, NULL, devGpibLib_initMbbo, NULL, 
         devGpibLib_writeMbbo, (DRVSUPFUN)&devSupParms, 
         (DRVSUPFUN)devGpibLib_mbboGpibWork, NULL}}; 
  
 gDset DSET_SI   = {5, {NULL, NULL, devGpibLib_initSi, NULL, 
         devGpibLib_readSi, (DRVSUPFUN)&devSupParms, 
         (DRVSUPFUN)&devGpibLib_stringinGpibWork, (DRVSUPFUN)devGpibLib_stringinGpibSrq}}; 
  
 gDset DSET_SO   = {5, {NULL, NULL, devGpibLib_initSo, NULL, 
         devGpibLib_writeSo, (DRVSUPFUN)&devSupParms, 
         (DRVSUPFUN)devGpibLib_stringoutGpibWork, NULL}}; 
  
 gDset DSET_LI   = {5, {NULL, NULL, devGpibLib_initLi, NULL, 
         devGpibLib_readLi, (DRVSUPFUN)&devSupParms, 
         (DRVSUPFUN)devGpibLib_liGpibWork, (DRVSUPFUN)devGpibLib_liGpibSrq}}; 
  
 gDset DSET_LO   = {5, {NULL, NULL, devGpibLib_initLo, NULL, 
         devGpibLib_writeLo, (DRVSUPFUN)&devSupParms, 
         (DRVSUPFUN)devGpibLib_loGpibWork, NULL}}; 
   
 static int K196Debug = 0;               /* debugging flags */ 
  
 /* /*
  * Use the TIME_WINDOW defn to indicate how long commands should be ignored  * Use the TIME_WINDOW defn to indicate how long commands should be ignored
  * for a given device after it times out.  The ignored commands will be  * for a given device after it times out.  The ignored commands will be
  * returned as errors to device support.  * returned as errors to device support.
  *  *
  * Use the DMA_TIME to define how long you wish to wait for an I/O operation  * Use the TIMEOUT to define how long you wish to wait for an I/O operation
  * to complete once started.  * to complete once started.
  */  */
 #define TIME_WINDOW     600             /* 10 seconds on a getTick call */ #define TIME_WINDOW     10.0             /* 10 seconds */
 #define DMA_TIME       - 30              /* 1/2 second -on a watchdog time */ #define TIMEOUT 0.5             /* 1/2 second */
  
   
  
 /****************************************************************************** /******************************************************************************
  *  *
  * String arrays for EFAST operations.  Note that the last entry must be  * String arrays for EFAST operations.  Note that the last entry must be
  * NULL.  * NULL.
  *  *
  * On input operations, only as many bytes as are found in the string array  * On input operations, only as many bytes as are found in the string array
  * elements are compared.  If there are more bytes than that in the input  * elements are compared.  If there are more bytes than that in the input
  * message, they are ignored.  The first matching string found (starting  * message, they are ignored.  The first matching string found (starting
  * from the 0'th element) will be used as a match.  * from the 0'th element) will be used as a match.
  *  *
  * NOTE: For the input operations, the strings are compared literally!  This  * NOTE: For the input operations, the strings are compared literally!  This
  * can cause problems if the instrument is returning things like \r and \n  * can cause problems if the instrument is returning things like \r and \n
- Line 200  static char     *(set196rate[]) = {"S0X" - - Line 87  static char     *(set196rate[]) = {"S0X" -
  *  *
  * Array of structures that define all GPIB messages  * Array of structures that define all GPIB messages
  * supported for this type of instrument.  * supported for this type of instrument.
  *  *
  ******************************************************************************/  ******************************************************************************/
  
 /* forward declarations of some custom convert routines */ /* forward declarations of some custom convert routines */
  
 static struct gpibCmd gpibCmds[] = static struct gpibCmd gpibCmds[] =
 { {
   /* Param 0, (model)   */   /* Param 0, (model)   */
   FILL,   FILL,
  
   /* Param 1 initialization string */   /* Param 1 initialization string */
   {&DSET_BO, GPIBCMD, IB_Q_HIGH, "L0XR3X", NULL, 0, 32,   {&DSET_BO, GPIBCMD, IB_Q_HIGH, "L0XR3X", NULL, 0, 32,
   NULL, 0, 0, NULL, NULL, -1},   NULL, 0, 0, NULL, NULL, NULL},
  
   /* Param 2 read current or voltage value */   /* Param 2 read current or voltage value */
   /* "%*4c%lf" = ignore first 4 characters, use double precision floating point format */   /* "%*4c%lf" = ignore first 4 characters, use double precision floating point format */
   {&DSET_AI, GPIBREAD, IB_Q_HIGH, "U7", "%*4c%lf", 0, 32,   {&DSET_AI, GPIBREAD, IB_Q_HIGH, "U7", "%*4c%lf", 0, 32,
   NULL, 0, 0, NULL, NULL, -1},   NULL, 0, 0, NULL, NULL, NULL},
  
   /* Param 3 set function */   /* Param 3 set function */
   {&DSET_MBBO, GPIBEFASTO, IB_Q_HIGH, NULL, NULL, 0, 0,   {&DSET_MBBO, GPIBEFASTO, IB_Q_HIGH, NULL, NULL, 0, 0,
   NULL, 0, 0, set196function, NULL, -1},   NULL, 0, 0, set196function, NULL, NULL},
  
   /* Param 4 set range */   /* Param 4 set range */
   {&DSET_MBBO, GPIBEFASTO, IB_Q_HIGH, NULL, NULL, 0, 0,   {&DSET_MBBO, GPIBEFASTO, IB_Q_HIGH, NULL, NULL, 0, 0,
   NULL, 0, 0, set196range, NULL, -1},   NULL, 0, 0, set196range, NULL, NULL},
  
   /* Param 5 set resolution */   /* Param 5 set resolution */
   {&DSET_MBBO, GPIBEFASTO, IB_Q_HIGH, NULL, NULL, 0, 0,   {&DSET_MBBO, GPIBEFASTO, IB_Q_HIGH, NULL, NULL, 0, 0,
   NULL, 0, 0, set196rate, NULL, -1},   NULL, 0, 0, set196rate, NULL, NULL},
  
 }; };
  
  
 /* The following is the number of elements in the command array above.  */ /* The following is the number of elements in the command array above.  */
 #define NUMPARAMS       sizeof(gpibCmds)/sizeof(struct gpibCmd) #define NUMPARAMS       sizeof(gpibCmds)/sizeof(struct gpibCmd)
   
 /****************************************************************************** /******************************************************************************
  *  *
  * Initialization for device support  * Initialization for device support
  * This is called one time before any records are initialized with a parm  * This is called one time before any records are initialized with a parm
  * value of 0.  And then again AFTER all record-level init is complete  * value of 0.  And then again AFTER all record-level init is complete
  * with a param value of 1.  * with a param value of 1.
  *  *
  ******************************************************************************/  ******************************************************************************/
 static long static long
 init_dev_sup(parm) init_ai(int parm)
 int parm; 
 { {
   if(parm==0)  {   if(parm==0)  {
     devSupParms.debugFlag = &K196Debug; 
     devSupParms.respond2Writes = -1;     devSupParms.respond2Writes = -1;
     devSupParms.timeWindow = TIME_WINDOW;     devSupParms.timeWindow = TIME_WINDOW;
     devSupParms.hwpvtHead = 0; 
     devSupParms.gpibCmds = gpibCmds;     devSupParms.gpibCmds = gpibCmds;
     devSupParms.numparams = NUMPARAMS;     devSupParms.numparams = NUMPARAMS;
     devSupParms.magicSrq = -1; 
     devSupParms.name = "devXxK196Gpib";     devSupParms.name = "devXxK196Gpib";
     devSupParms.dmaTimeout = DMA_TIME;     devSupParms.timeout = TIMEOUT;
     devSupParms.srqHandler = 0; 
     devSupParms.wrConversion = 0; 
   }   }
   return(devGpibLib_initDevSup(parm, &DSET_AI));   return 0;
 } }
  
 /****************************************************************************** 
  * 
  * Print a report of operating statistics for all devices supported by this 
  * module. 
  * 
  ******************************************************************************/ 
 static long 
 report() 
 { 
   return(devGpibLib_report(&DSET_AI)); 
 } 
-
- diff --git a/documentation/testErrors.png b/documentation/testErrors.png deleted file mode 100755 index ea4d5cf..0000000 Binary files a/documentation/testErrors.png and /dev/null differ diff --git a/iocBoot/ioctestEpics/Makefile b/iocBoot/ioctestEpics/Makefile index b493509..7011e8a 100644 --- a/iocBoot/ioctestEpics/Makefile +++ b/iocBoot/ioctestEpics/Makefile @@ -1,5 +1,5 @@ TOP = ../.. include $(TOP)/configure/CONFIG -ARCH = linux-x86_64 +ARCH = $(EPICS_HOST_ARCH) TARGETS = envPaths cdCommands dllPath.bat include $(TOP)/configure/RULES.ioc diff --git a/iocBoot/ioctestErrors/st.cmd b/iocBoot/ioctestErrors/st.cmd index d6ed31b..6848c22 100644 --- a/iocBoot/ioctestErrors/st.cmd +++ b/iocBoot/ioctestErrors/st.cmd @@ -6,20 +6,28 @@ testErrorsConfigure("PORT1",1) #asynSetTraceMask("PORT1",0,0xff) asynSetTraceIOMask("PORT1",0,0x2) +# In the following comment out the lines to load testErrorsInt64.db if running on base versions prior to 3.16.1 +# The int64in, int64out, and int64 waveform records are not supported on those earlier versions of base + ### Use periodic scanning and normal timestamp (TSE=0) and no ring buffer on string and waveform records -#dbLoadRecords("../../db/testErrors.db","P=testErrors:,PORT=PORT1,ADDR=0,TIMEOUT=1,TSE=0,SCAN=2 second,FIFO=0") +#dbLoadRecords("../../db/testErrors.db", "P=testErrors:,PORT=PORT1,ADDR=0,TIMEOUT=1,TSE=0,SCAN=2 second,FIFO=0") +#dbLoadRecords("../../db/testErrorsInt64.db","P=testErrors:,PORT=PORT1,ADDR=0,TIMEOUT=1,TSE=0,SCAN=2 second,FIFO=0") ### Use I/O Intr scanning and normal timestamp (TSE=0) and no ring buffer on string and waveform records -#dbLoadRecords("../../db/testErrors.db","P=testErrors:,PORT=PORT1,ADDR=0,TIMEOUT=1,TSE=0,SCAN=I/O Intr,FIFO=0") +#dbLoadRecords("../../db/testErrors.db", "P=testErrors:,PORT=PORT1,ADDR=0,TIMEOUT=1,TSE=0,SCAN=I/O Intr,FIFO=0") +#dbLoadRecords("../../db/testErrorsInt64.db","P=testErrors:,PORT=PORT1,ADDR=0,TIMEOUT=1,TSE=0,SCAN=I/O Intr,FIFO=0") ### Use periodic scanning and timestamp from device support (TSE=-2) and no ring buffer on string and waveform records -#dbLoadRecords("../../db/testErrors.db","P=testErrors:,PORT=PORT1,ADDR=0,TIMEOUT=1,TSE=-2,SCAN=2 second,FIFO=0") +#dbLoadRecords("../../db/testErrors.db", "P=testErrors:,PORT=PORT1,ADDR=0,TIMEOUT=1,TSE=-2,SCAN=2 second,FIFO=0") +#dbLoadRecords("../../db/testErrorsInt64.db","P=testErrors:,PORT=PORT1,ADDR=0,TIMEOUT=1,TSE=-2,SCAN=2 second,FIFO=0") ### Use I/O Intr scanning and timestamp from device support (TSE=-2) and no ring buffer on string and waveform records -#dbLoadRecords("../../db/testErrors.db","P=testErrors:,PORT=PORT1,ADDR=0,TIMEOUT=1,TSE=-2,SCAN=I/O Intr,FIFO=0") +#dbLoadRecords("../../db/testErrors.db", "P=testErrors:,PORT=PORT1,ADDR=0,TIMEOUT=1,TSE=-2,SCAN=I/O Intr,FIFO=0") +#dbLoadRecords("../../db/testErrorsInt64.db","P=testErrors:,PORT=PORT1,ADDR=0,TIMEOUT=1,TSE=-2,SCAN=I/O Intr,FIFO=0") ### Use I/O Intr scanning and timestamp from device support (TSE=-2) and 5 element ring buffer on string and waveform records -dbLoadRecords("../../db/testErrors.db","P=testErrors:,PORT=PORT1,ADDR=0,TIMEOUT=1,TSE=-2,SCAN=I/O Intr,FIFO=5") +dbLoadRecords("../../db/testErrors.db", "P=testErrors:,PORT=PORT1,ADDR=0,TIMEOUT=1,TSE=-2,SCAN=I/O Intr,FIFO=5") +dbLoadRecords("../../db/testErrorsInt64.db","P=testErrors:,PORT=PORT1,ADDR=0,TIMEOUT=1,TSE=-2,SCAN=I/O Intr,FIFO=5") ### Use user-defined time stamp source by uncommenting this line asynRegisterTimeStampSource("PORT1", "myTimeStampSource") diff --git a/iocBoot/ioctestIPServer/st.cmd.asynPortTest b/iocBoot/ioctestIPServer/st.cmd.asynPortTest old mode 100755 new mode 100644 diff --git a/iocBoot/ioctestIPServer/st.cmd.shellEchoTest b/iocBoot/ioctestIPServer/st.cmd.shellEchoTest old mode 100755 new mode 100644 diff --git a/makeSupport/app/_NAME_App/src/_NAME_Main.cpp b/makeSupport/app/_NAME_App/src/_NAME_Main.cpp index ae0ecb6..fe4f105 100644 --- a/makeSupport/app/_NAME_App/src/_NAME_Main.cpp +++ b/makeSupport/app/_NAME_App/src/_NAME_Main.cpp @@ -13,7 +13,7 @@ int main(int argc,char *argv[]) { - if(argc>=2) { + if(argc>=2) { iocsh(argv[1]); epicsThreadSleep(.2); } diff --git a/makeSupport/devGpib/_NAME_Sup/Makefile b/makeSupport/devGpib/_NAME_Sup/Makefile index 3081959..80c2621 100644 --- a/makeSupport/devGpib/_NAME_Sup/Makefile +++ b/makeSupport/devGpib/_NAME_Sup/Makefile @@ -14,7 +14,7 @@ dev_NAME__LIBS += $(EPICS_BASE_IOC_LIBS) # Install .dbd and .db files DBD += dev_NAME_.dbd -DB_INSTALLS += dev_NAME_.db +DB += dev_NAME_.db #======================================= include $(TOP)/configure/RULES diff --git a/makeSupport/devGpib/_NAME_Sup/dev_NAME_.c b/makeSupport/devGpib/_NAME_Sup/dev_NAME_.c index 3fbc43c..47a8ba8 100644 --- a/makeSupport/devGpib/_NAME_Sup/dev_NAME_.c +++ b/makeSupport/devGpib/_NAME_Sup/dev_NAME_.c @@ -8,7 +8,7 @@ /****************************************************************************** * * The following define statements are used to declare the names to be used - * for the dset tables. + * for the dset tables. * * A DSET_AI entry must be declared here and referenced in an application * database description file even if the device provides no AI records. diff --git a/makeSupport/streamSCPI/_NAME_Sup/Makefile b/makeSupport/streamSCPI/_NAME_Sup/Makefile index 9350b62..a351a35 100644 --- a/makeSupport/streamSCPI/_NAME_Sup/Makefile +++ b/makeSupport/streamSCPI/_NAME_Sup/Makefile @@ -3,8 +3,8 @@ include $(TOP)/configure/CONFIG #======================================= # Install .dbd and .db files -DB_INSTALLS += dev_NAME_.db -DB_INSTALLS += $(TOP)/_NAME_Sup/dev_NAME_.proto +DB += dev_NAME_.db +DB += dev_NAME_.proto #======================================= include $(TOP)/configure/RULES diff --git a/opi/Makefile b/opi/Makefile index c8a781b..d7a1ecc 100644 --- a/opi/Makefile +++ b/opi/Makefile @@ -5,5 +5,8 @@ ADL_DIR = medm UI_DIR = caqtdm/autoconvert EDL_DIR = edm/autoconvert OPI_DIR = boy/autoconvert +BOB_DIR = bob/autoconvert + +include $(CONFIG)/RULES_DIRS -include $(SUPPORT)/configure/RULES_OPI diff --git a/opi/bob/autoconvert/asynGPIBSetup.bob b/opi/bob/autoconvert/asynGPIBSetup.bob new file mode 100644 index 0000000..08dc6f1 --- /dev/null +++ b/opi/bob/autoconvert/asynGPIBSetup.bob @@ -0,0 +1,210 @@ + + + asynGPIBSetup + 456 + 239 + 375 + 185 + + + + + false + 5 + + rectangle #6 + 8 + 375 + 29 + + + + + + + + + + + text #9 + $(P)$(R) + 12 + 375 + 25 + + + + + 1 + + + text #12 + GPIB address: + 4 + 68 + 130 + + + + + true + + + text entry #15 + $(P)$(R).ADDR + 139 + 68 + 75 + + + + + + + + + 1 + false + false + + + text #19 + Serial poll response: + 4 + 97 + 210 + + + + + true + + + text update #22 + $(P)$(R).SPR + 224 + 97 + 56 + + + + + + + + + 4 + false + false + + + text #26 + Universal Command + 4 + 126 + 170 + + + + + true + + + menu #29 + $(P)$(R).UCMD + 179 + 126 + 180 + 20 + + + + + false + + + text #32 + Addressed Command + 4 + 151 + 170 + + + + + true + + + menu #35 + $(P)$(R).ACMD + 179 + 151 + 180 + 20 + + + + + false + + + text #38 + Supported + 218 + 42 + 90 + + + + + + + + + true + + + + false + + $(P)$(R).GPIBIV + + + + + text #42 + Unsupported + 208 + 42 + 110 + + + + + + + + + true + + + + false + + $(P)$(R).GPIBIV + + + + + text #46 + asynGpib interface: + 4 + 42 + 190 + + + + + true + + diff --git a/opi/bob/autoconvert/asynIPPortSetup.bob b/opi/bob/autoconvert/asynIPPortSetup.bob new file mode 100644 index 0000000..4a0a022 --- /dev/null +++ b/opi/bob/autoconvert/asynIPPortSetup.bob @@ -0,0 +1,419 @@ + + + asynIPPortSetup + 405 + 149 + 260 + 410 + + + + + false + 5 + + rectangle #6 + 2 + 260 + 16 + + + + + + + + + + + text #9 + $(P)$(R) + 2 + 260 + 16 + + + + + 1 + + + text #12 + Supported + 148 + 25 + 90 + + + + + + + + + true + + + + false + + $(P)$(R).OPTIONIV + + + + + text #16 + Unsupported + 138 + 25 + 110 + + + + + + + + + true + + + + false + + $(P)$(R).OPTIONIV + + + + + text #20 + asynOption: + 8 + 25 + 110 + + + + + true + + + text #23 + Disconnect on + 13 + 51 + 130 + + + + + 2 + + + text #26 + read timeout: + 13 + 76 + 130 + + + + + 2 + + + text #29 + Host info: + 43 + 101 + + + + + 2 + + + text entry #32 + $(P)$(R).HOSTINFO + 150 + 101 + 102 + 18 + + + + + + + + + 6 + false + false + + + menu #36 + $(P)$(R).DRTO + 150 + 76 + 102 + 20 + + + + + false + + + text #39 + Data bits: + 43 + 206 + + + + + 2 + + + text #42 + Stop bits: + 43 + 231 + + + + + 2 + + + text #45 + Modem control: + 3 + 281 + 140 + + + + + 2 + + + text #48 + Parity: + 73 + 256 + 70 + + + + + 2 + + + menu #51 + $(P)$(R).DBIT + 150 + 206 + 102 + 20 + + + + + false + + + menu #54 + $(P)$(R).SBIT + 150 + 231 + 102 + 20 + + + + + false + + + menu #57 + $(P)$(R).PRTY + 150 + 256 + 102 + 20 + + + + + false + + + menu #60 + $(P)$(R).MCTL + 150 + 281 + 102 + 20 + + + + + false + + + text #63 + Flow control: + 13 + 306 + 130 + + + + + 2 + + + menu #66 + $(P)$(R).FCTL + 150 + 306 + 102 + 20 + + + + + false + + + text #69 + XOFF output: + 23 + 331 + 120 + + + + + 2 + + + menu #72 + $(P)$(R).IXON + 150 + 331 + 102 + 20 + + + + + false + + + text #75 + XOFF input: + 33 + 356 + 110 + + + + + 2 + + + menu #78 + $(P)$(R).IXOFF + 150 + 356 + 102 + 20 + + + + + false + + + text #81 + XON=any: + 63 + 381 + 80 + + + + + 2 + + + menu #84 + $(P)$(R).IXANY + 150 + 381 + 102 + 20 + + + + + false + + + text #87 + Baud rate: + 43 + 181 + + + + + 2 + + + text entry #90 + $(P)$(R).LBAUD + 150 + 181 + 102 + 18 + + + + + + + + + 1 + false + false + + + text #94 + COM (RFC 2217) protocol + 15 + 151 + 230 + + + + + 2 + + + text #97 + Parameters for ports with + 5 + 130 + 250 + + + + + 2 + + diff --git a/opi/bob/autoconvert/asynOctet.bob b/opi/bob/autoconvert/asynOctet.bob new file mode 100644 index 0000000..43736cc --- /dev/null +++ b/opi/bob/autoconvert/asynOctet.bob @@ -0,0 +1,795 @@ + + + asynOctet + 457 + 494 + 442 + 350 + + + + + false + 5 + + text update #6 + $(P)$(R).TINP + 81 + 216 + 350 + 18 + + + + + + + + + 6 + false + false + + + text #10 + Timeout (sec): + 6 + 43 + 140 + + + + + true + + + text entry #13 + $(P)$(R).TMOT + 151 + 43 + 50 + + + + + + + + + 1 + false + false + + + menu #17 + $(P)$(R).TMOD + 320 + 43 + 110 + 20 + + + + + false + + + text #20 + Transfer: + 225 + 43 + 90 + + + + + 2 + + + rectangle #23 + 5 + 442 + 29 + + + + + + + + + + + text #26 + $(P)$(R) + 9 + 442 + 21 + + + + + 1 + + + text entry #29 + $(P)$(R).AOUT + 78 + 128 + 350 + + + + + + + + + 6 + false + false + + + text #33 + Output + 13 + 99 + 60 + + + + + + + + + true + + + text #36 + Format: + 91 + 99 + 70 + + + + + true + + + menu #39 + $(P)$(R).OFMT + 166 + 99 + 80 + 20 + + + + + false + + + text #42 + ASCII: + 13 + 126 + 60 + + + + + true + + + rectangle #45 + 6 + 92 + 430 + 85 + 1 + + + + + + + + + true + + + text #48 + Terminator: + 256 + 99 + 110 + + + + + true + + + text entry #51 + $(P)$(R).OEOS + 371 + 99 + 60 + + + + + + + + + 6 + false + false + + + text #55 + Requested: + 88 + 152 + + + + + true + + + text #58 + Length: + 10 + 152 + 70 + + + + + true + + + text #61 + Actual: + 280 + 152 + 70 + + + + + true + + + text update #64 + $(P)$(R).NAWT + 355 + 152 + 56 + + + + + + + + + 1 + false + false + + + text entry #68 + $(P)$(R).NOWT + 193 + 152 + 70 + + + + + + + + + 1 + false + false + + + text #72 + I/O Status: + 10 + 297 + 110 + + + + + true + + + text #75 + I/O Severity: + 217 + 297 + 130 + + + + + true + + + text update #78 + $(P)$(R).STAT + 122 + 297 + 85 + + + + + + + + + 6 + false + + + text update #82 + $(P)$(R).SEVR + 349 + 297 + 85 + + + + + + + + + 6 + false + + + rectangle #86 + 6 + 292 + 430 + 25 + 1 + + + + + + + + + true + + + text #89 + Scan: + 9 + 323 + 50 + + + + + 2 + + + menu #92 + $(P)$(R).SCAN + 64 + 323 + 110 + 20 + + + + + false + + + message button #95 + + + $(P)$(R).PROC + 1 + Write + + + $(P)$(R).PROC + Process + 179 + 323 + 80 + 20 + + + + + + + text #98 + Terminator: + 253 + 189 + 110 + + + + + true + + + text entry #101 + $(P)$(R).IEOS + 368 + 189 + 60 + + + + + + + + + 6 + false + false + + + rectangle #105 + 74 + 213 + 360 + 21 + 1 + + + + + + + + + true + + + text #108 + Input + 16 + 189 + 50 + + + + + + + + + true + + + text #111 + Format: + 86 + 191 + 70 + + + + + true + + + menu #114 + $(P)$(R).IFMT + 161 + 189 + 80 + 20 + + + + + false + + + text #117 + ASCII: + 13 + 215 + 60 + + + + + true + + + rectangle #120 + 6 + 182 + 430 + 105 + 1 + + + + + + + + + true + + + text #123 + Requested: + 88 + 242 + + + + + true + + + text #126 + Length: + 10 + 242 + 70 + + + + + true + + + text #129 + Actual: + 280 + 242 + 70 + + + + + true + + + text update #132 + $(P)$(R).NORD + 355 + 242 + 56 + + + + + + + + + 1 + false + false + + + text entry #136 + $(P)$(R).NRRD + 193 + 242 + 70 + + + + + + + + + 1 + false + false + + + text #140 + EOM reason: + 77 + 265 + 110 + + + + + 2 + + + text update #143 + $(P)$(R).EOMR + 193 + 265 + 70 + + + + + + + + + 6 + false + false + + + text #147 + Supported + 220 + 66 + 90 + + + + + + + + + true + + + + false + + $(P)$(R).OCTETIV + + + + + text #151 + Unsupported + 210 + 66 + 110 + + + + + + + + + true + + + + false + + $(P)$(R).OCTETIV + + + + + text #155 + asynOctet interface: + 6 + 66 + 200 + + + + + true + + + text #158 + Active + 344 + 66 + 60 + + + + + + + + + true + + + + false + + $(P)$(R).IFACE + + + + + text #162 + Inactive + 334 + 66 + 80 + + + + + + + + + true + + + + false + + $(P)$(R).IFACE + + + + + text #166 + More... + 300 + 323 + 70 + + + + + true + + + related display #169 + + + asynRecord.opi + tab + Record parameters + + + asynRegister.opi + tab + Register interfaces I/O + + + asynSerialPortSetup.opi + tab + Serial port parameters + + + asynGPIBSetup.opi + tab + GPIB parameters + + + + 375 + 323 + 56 + 20 + + + + + + diff --git a/opi/bob/autoconvert/asynRecord.bob b/opi/bob/autoconvert/asynRecord.bob new file mode 100644 index 0000000..f28d1f7 --- /dev/null +++ b/opi/bob/autoconvert/asynRecord.bob @@ -0,0 +1,1123 @@ + + + asynRecord + 72 + 61 + 440 + 589 + + + + + false + 5 + + rectangle #6 + 8 + 440 + 29 + + + + + + + + + + + text #9 + $(P)$(R) + 12 + 440 + 21 + + + + + 1 + + + text update #12 + $(P)$(R).ERRS + 75 + 182 + 359 + 16 + + + + + + + + + 6 + false + false + + + text #16 + Error: + 10 + 181 + 60 + + + + + true + + + rectangle #19 + 6 + 178 + 430 + 25 + 1 + + + + + + + + + true + + + text #22 + noAutoConnect + 300 + 212 + 130 + + + + + + + + + 2 + + + + false + + $(P)$(R).AUCT + + + + + text #26 + autoConnect + 310 + 212 + 110 + + + + + + + + + 2 + + + + false + + $(P)$(R).AUCT + + + + + menu #30 + $(P)$(R).AUCT + 305 + 233 + 120 + 20 + + + + + false + + + text #33 + Enabled + 180 + 212 + 70 + + + + + + + + + 2 + + + + false + + $(P)$(R).ENBL + + + + + text #37 + Disabled + 175 + 212 + 80 + + + + + + + + + 2 + + + + false + + $(P)$(R).ENBL + + + + + menu #41 + $(P)$(R).ENBL + 155 + 234 + 120 + 20 + + + + + false + + + rectangle #44 + 6 + 210 + 430 + 49 + 1 + + + + + + + + + true + + + text #47 + traceError + 68 + 316 + 80 + 18 + + + + + true + + + text #50 + traceIODriver + 68 + 385 + 104 + 18 + + + + + true + + + text #53 + traceIOFilter + 68 + 362 + 104 + 18 + + + + + true + + + text #56 + traceIODevice + 68 + 339 + 104 + 18 + + + + + true + + + text #59 + traceMask + 9 + 269 + 90 + + + + + true + + + text #62 + traceIOHex + 242 + 362 + 80 + 18 + + + + + true + + + choice button #65 + $(P)$(R).TB0 + 9 + 316 + 55 + 18 + + + + + false + + Item 1 + Item 2 + + + + choice button #68 + $(P)$(R).TB3 + 9 + 385 + 55 + 18 + + + + + false + + Item 1 + Item 2 + + + + choice button #71 + $(P)$(R).TB2 + 9 + 362 + 55 + 18 + + + + + false + + Item 1 + Item 2 + + + + choice button #74 + $(P)$(R).TB1 + 9 + 339 + 55 + 18 + + + + + false + + Item 1 + Item 2 + + + + choice button #77 + $(P)$(R).TIB2 + 183 + 362 + 55 + 18 + + + + + false + + Item 1 + Item 2 + + + + text #80 + Truncate size + 242 + 385 + 104 + 18 + + + + + true + + + text entry #83 + $(P)$(R).TSIZ + 183 + 385 + 50 + + + + + + + + + 1 + false + false + + + rectangle #87 + 5 + 267 + 430 + 315 + 1 + + + + + + + + + true + + + text entry #90 + $(P)$(R).TMSK + 9 + 293 + 70 + + + + + + + + + 4 + false + false + + + text #94 + drvInfo: + 6 + 97 + 80 + + + + + true + + + text entry #97 + $(P)$(R).DRVINFO + 88 + 97 + 150 + + + + + + + + + 6 + false + false + + + menu #101 + $(P)$(R).IFACE + 111 + 122 + 130 + 20 + + + + + false + + + text #104 + Interface: + 6 + 122 + + + + + true + + + message button #107 + + + $(P)$(R).AQR + 1 + Write + + + $(P)$(R).AQR + Cancel queueRequest + 6 + 147 + 150 + 20 + + + + + + + text #110 + Reason: + 244 + 97 + 70 + + + + + true + + + text entry #113 + $(P)$(R).REASON + 318 + 97 + 50 + + + + + + + + + 1 + false + false + + + text #117 + Connected + 25 + 212 + 90 + + + + + + + + + 2 + + + + false + + $(P)$(R).CNCT + + + + + text #121 + Disconnected + 10 + 212 + 120 + + + + + + + + + 2 + + + + false + + $(P)$(R).CNCT + + + + + menu #125 + $(P)$(R).CNCT + 10 + 234 + 120 + 20 + + + + + false + + + text #128 + Port: + 6 + 47 + 50 + + + + + true + + + text entry #131 + $(P)$(R).PORT + 61 + 47 + 150 + + + + + + + + + 6 + false + false + + + text #135 + Address: + 228 + 47 + 80 + + + + + true + + + text entry #138 + $(P)$(R).ADDR + 318 + 47 + 110 + + + + + + + + + 1 + false + false + + + menu #142 + $(P)$(R).PCNCT + 61 + 72 + 120 + 20 + + + + + false + + + text #145 + Connected + 243 + 72 + 90 + + + + + + + + + 2 + + + + false + + $(P)$(R).PCNCT + + + + + text #149 + Disconnected + 228 + 72 + 120 + + + + + + + + + 2 + + + + false + + $(P)$(R).PCNCT + + + + + text #153 + More... + 291 + 147 + 70 + + + + + true + + + related display #156 + + + asynOctet.opi + tab + asynOctet Interface I/O + + + asynRegister.opi + tab + Register interfaces I/O + + + asynSerialPortSetup.opi + tab + Serial port parameters + + + asynIPPortSetup.opi + tab + IP port parameters + + + asynGPIBSetup.opi + tab + GPIB parameters + + + + 366 + 147 + 56 + 20 + + + + + + + text #163 + traceIOMask + 183 + 269 + 110 + + + + + true + + + text #166 + traceIOASCII + 242 + 316 + 96 + 18 + + + + + true + + + text #169 + traceIOEscape + 242 + 339 + 104 + 18 + + + + + true + + + choice button #172 + $(P)$(R).TIB0 + 183 + 316 + 55 + 18 + + + + + false + + Item 1 + Item 2 + + + + choice button #175 + $(P)$(R).TIB1 + 183 + 339 + 55 + 18 + + + + + false + + Item 1 + Item 2 + + + + text entry #178 + $(P)$(R).TIOM + 183 + 293 + 70 + + + + + + + + + 4 + false + false + + + text #182 + traceInfoMask + 183 + 415 + 130 + + + + + true + + + text entry #185 + $(P)$(R).TINM + 183 + 439 + 70 + + + + + + + + + 4 + false + false + + + text #189 + Trace file: + 9 + 557 + 88 + 18 + + + + + true + + + text entry #192 + $(P)$(R).TFIL + 99 + 555 + 330 + + + + + + + + + 6 + false + false + + + choice button #196 + $(P)$(R).TB4 + 9 + 408 + 55 + 18 + + + + + false + + Item 1 + Item 2 + + + + text #199 + traceFlow + 68 + 408 + 72 + 18 + + + + + true + + + choice button #202 + $(P)$(R).TB5 + 9 + 431 + 55 + 18 + + + + + false + + Item 1 + Item 2 + + + + text #205 + traceWarning + 68 + 431 + 96 + 18 + + + + + true + + + text #208 + traceInfoPort + 242 + 485 + 104 + 18 + + + + + true + + + choice button #211 + $(P)$(R).TINB1 + 183 + 485 + 55 + 18 + + + + + false + + Item 1 + Item 2 + + + + text #214 + traceInfoSource + 242 + 508 + 120 + 18 + + + + + true + + + choice button #217 + $(P)$(R).TINB2 + 183 + 508 + 55 + 18 + + + + + false + + Item 1 + Item 2 + + + + text #220 + traceInfoTime + 242 + 462 + 104 + 18 + + + + + true + + + choice button #223 + $(P)$(R).TINB0 + 183 + 462 + 55 + 18 + + + + + false + + Item 1 + Item 2 + + + + choice button #226 + $(P)$(R).TINB3 + 183 + 531 + 55 + 18 + + + + + false + + Item 1 + Item 2 + + + + text #229 + traceInfoThread + 242 + 531 + 120 + 18 + + + + + true + + diff --git a/opi/bob/autoconvert/asynRegister.bob b/opi/bob/autoconvert/asynRegister.bob new file mode 100644 index 0000000..7c74376 --- /dev/null +++ b/opi/bob/autoconvert/asynRegister.bob @@ -0,0 +1,856 @@ + + + asynRegister + 344 + 142 + 510 + 345 + + + + + false + 5 + + text #6 + Timeout (sec): + 6 + 43 + 140 + + + + + true + + + text entry #9 + $(P)$(R).TMOT + 151 + 43 + 50 + + + + + + + + + 1 + false + false + + + menu #13 + $(P)$(R).TMOD + 320 + 43 + 110 + 20 + + + + + false + + + text #16 + Transfer: + 225 + 43 + 90 + + + + + 2 + + + text #19 + I/O Status: + 10 + 284 + 110 + + + + + true + + + text #22 + I/O Severity: + 217 + 284 + 130 + + + + + true + + + text update #25 + $(P)$(R).STAT + 122 + 284 + 85 + + + + + + + + + 6 + false + + + text update #29 + $(P)$(R).SEVR + 349 + 284 + 85 + + + + + + + + + 6 + false + + + rectangle #33 + 6 + 279 + 430 + 25 + 1 + + + + + + + + + true + + + text #36 + Scan: + 9 + 310 + 50 + + + + + 2 + + + menu #39 + $(P)$(R).SCAN + 64 + 310 + 110 + 20 + + + + + false + + + message button #42 + + + $(P)$(R).PROC + 1 + Write + + + $(P)$(R).PROC + Process + 179 + 310 + 80 + 20 + + + + + + + rectangle #45 + 5 + 510 + 29 + + + + + + + + + + + text #48 + $(P)$(R) + 9 + 510 + 21 + + + + + 1 + + + text #51 + Mask (hex): + 27 + 251 + 110 + + + + + true + + + text #54 + Input (hex): + 17 + 226 + 120 + + + + + true + + + text #57 + Input: + 77 + 201 + 60 + + + + + true + + + text #60 + Output (hex): + 7 + 176 + 130 + + + + + true + + + text #63 + Output: + 67 + 151 + 70 + + + + + true + + + menu #66 + $(P)$(R).IFACE + 5 + 101 + 130 + 20 + + + + + false + + + text #69 + Interface: + 37 + 76 + + + + + true + + + text update #72 + $(P)$(R).I32INP + 147 + 226 + + + + + + + + + 4 + false + false + + + text update #76 + $(P)$(R).I32INP + 147 + 201 + + + + + + + + + 1 + false + false + + + text entry #80 + $(P)$(R).I32OUT + 147 + 176 + + + + + + + + + 4 + false + false + + + text entry #84 + $(P)$(R).I32OUT + 147 + 151 + + + + + + + + + 1 + false + false + + + text #88 + Active + 167 + 126 + 60 + + + + + + + + + true + + + + false + + $(P)$(R).IFACE + + + + + text #92 + Inactive + 157 + 126 + 80 + + + + + + + + + true + + + + false + + $(P)$(R).IFACE + + + + + text #96 + Supported + 152 + 101 + 90 + + + + + + + + + true + + + + false + + $(P)$(R).I32IV + + + + + text #100 + Unsupported + 142 + 101 + 110 + + + + + + + + + true + + + + false + + $(P)$(R).I32IV + + + + + text #104 + Int32 + 172 + 76 + 50 + + + + + true + + + text entry #107 + $(P)$(R).UI32MASK + 272 + 251 + + + + + + + + + 4 + false + false + + + text update #111 + $(P)$(R).UI32INP + 272 + 226 + + + + + + + + + 4 + false + false + + + text update #115 + $(P)$(R).UI32INP + 272 + 201 + + + + + + + + + 1 + false + false + + + text entry #119 + $(P)$(R).UI32OUT + 272 + 176 + + + + + + + + + 4 + false + false + + + text entry #123 + $(P)$(R).UI32OUT + 272 + 151 + + + + + + + + + 1 + false + false + + + text #127 + Active + 292 + 126 + 60 + + + + + + + + + true + + + + false + + $(P)$(R).IFACE + + + + + text #131 + Inactive + 282 + 126 + 80 + + + + + + + + + true + + + + false + + $(P)$(R).IFACE + + + + + text #135 + Unsupported + 267 + 101 + 110 + + + + + + + + + true + + + + false + + $(P)$(R).UI32IV + + + + + text #139 + Supported + 277 + 101 + 90 + + + + + + + + + true + + + + false + + $(P)$(R).UI32IV + + + + + text #143 + UInt32Digital + 257 + 76 + 130 + + + + + true + + + text update #146 + $(P)$(R).F64INP + 397 + 201 + + + + + + + + + 1 + false + false + + + text entry #150 + $(P)$(R).F64OUT + 397 + 151 + + + + + + + + + 1 + false + false + + + text #154 + Active + 417 + 126 + 60 + + + + + + + + + true + + + + false + + $(P)$(R).IFACE + + + + + text #158 + Inactive + 407 + 126 + 80 + + + + + + + + + true + + + + false + + $(P)$(R).IFACE + + + + + text #162 + Unsupported + 392 + 101 + 110 + + + + + + + + + true + + + + false + + $(P)$(R).F64IV + + + + + text #166 + Supported + 402 + 101 + 90 + + + + + + + + + true + + + + false + + $(P)$(R).F64IV + + + + + text #170 + Float64 + 412 + 76 + 70 + + + + + true + + + text #173 + More... + 364 + 310 + 70 + + + + + true + + + related display #176 + + + asynRecord.opi + tab + Record parameters + + + asynRegister.opi + tab + Register interfaces I/O + + + asynSerialPortSetup.opi + tab + Serial port parameters + + + asynGPIBSetup.opi + tab + GPIB parameters + + + + 439 + 310 + 56 + 20 + + + + + + diff --git a/opi/bob/autoconvert/asynSerialPortSetup.bob b/opi/bob/autoconvert/asynSerialPortSetup.bob new file mode 100644 index 0000000..b849dc5 --- /dev/null +++ b/opi/bob/autoconvert/asynSerialPortSetup.bob @@ -0,0 +1,352 @@ + + + asynSerialPortSetup + 228 + 79 + 260 + 300 + + + + + false + 5 + + rectangle #6 + 2 + 260 + 16 + + + + + + + + + + + text #9 + $(P)$(R) + 2 + 260 + 16 + + + + + 1 + + + text #12 + Supported + 148 + 25 + 90 + + + + + + + + + true + + + + false + + $(P)$(R).OPTIONIV + + + + + text #16 + Unsupported + 138 + 25 + 110 + + + + + + + + + true + + + + false + + $(P)$(R).OPTIONIV + + + + + text #20 + asynOption: + 8 + 25 + 110 + + + + + true + + + text #23 + Baud rate: + 43 + 51 + + + + + 2 + + + menu #26 + $(P)$(R).BAUD + 150 + 51 + 102 + 20 + + + + + false + + + text #29 + Baud rate: + 43 + 76 + + + + + 2 + + + text #32 + Data bits: + 43 + 101 + + + + + 2 + + + text #35 + Stop bits: + 43 + 126 + + + + + 2 + + + text #38 + Modem control: + 3 + 176 + 140 + + + + + 2 + + + text #41 + Parity: + 73 + 151 + 70 + + + + + 2 + + + menu #44 + $(P)$(R).DBIT + 150 + 101 + 102 + 20 + + + + + false + + + menu #47 + $(P)$(R).SBIT + 150 + 126 + 102 + 20 + + + + + false + + + menu #50 + $(P)$(R).PRTY + 150 + 151 + 102 + 20 + + + + + false + + + menu #53 + $(P)$(R).MCTL + 150 + 176 + 102 + 20 + + + + + false + + + text #56 + Flow control: + 13 + 201 + 130 + + + + + 2 + + + menu #59 + $(P)$(R).FCTL + 150 + 201 + 102 + 20 + + + + + false + + + text #62 + XOFF output: + 23 + 226 + 120 + + + + + 2 + + + menu #65 + $(P)$(R).IXON + 150 + 226 + 102 + 20 + + + + + false + + + text #68 + XOFF input: + 33 + 251 + 110 + + + + + 2 + + + menu #71 + $(P)$(R).IXOFF + 150 + 251 + 102 + 20 + + + + + false + + + text #74 + XON=any: + 63 + 276 + 80 + + + + + 2 + + + menu #77 + $(P)$(R).IXANY + 150 + 276 + 102 + 20 + + + + + false + + + text entry #80 + $(P)$(R).LBAUD + 150 + 76 + 102 + 18 + + + + + + + + + 1 + false + false + + diff --git a/opi/bob/autoconvert/asynTimeSeries.bob b/opi/bob/autoconvert/asynTimeSeries.bob new file mode 100644 index 0000000..19a7579 --- /dev/null +++ b/opi/bob/autoconvert/asynTimeSeries.bob @@ -0,0 +1,305 @@ + + + asynTimeSeries + 326 + 179 + 500 + 360 + + + + + false + 5 + + rectangle #6 + 5 + 500 + 25 + + + + + + + + + + + text #9 + $(P)$(R) + 5 + 500 + 25 + + + + + + + + + 1 + + + text #12 + Acquiring + 42 + 40 + 90 + + + + + + + + + 1 + + + + false + + $(P)$(R).BUSY + + + + + text #16 + Done + 95 + 40 + 40 + + + + + + + + + 1 + + + + false + + $(P)$(R).BUSY + + + + + text #20 + Status + 142 + 40 + 60 + + + + + true + + + text update #23 + $(P)$(R).NORD + 224 + 40 + + + + + + + + + + + + + 1 + false + 2 + false + + + text #27 + Current point + 329 + 40 + 130 + + + + + true + + + cartesian plot #30 + 10 + 92 + 480 + 230 + $(P)$(R) + + Time point + true + false + 0.0 + 100.0 + false + + + + + + + + + true + + + + Value + true + false + 0.0 + 100.0 + false + + + + + + + + + true + + + + + $(traces[0].y_pv) + + $(P)$(R).VAL + + 0 + 1 + + + + + 1 + 0 + 0 + 10 + true + + + + + message button #37 + + + $(P)$(R).RARM + 1 + Write + + + $(P)$(R).RARM + Erase/Start + 15 + 65 + 90 + 20 + + + + + + + message button #40 + + + $(P)$(R).RARM + 3 + Write + + + $(P)$(R).RARM + Start + 110 + 65 + 90 + 20 + + + + + + + message button #43 + + + $(P)$(R).RARM + 2 + Write + + + $(P)$(R).RARM + Stop + 205 + 65 + 90 + 20 + + + + + + + menu #46 + $(P)$(R)Read.SCAN + 10 + 329 + 20 + + + + + false + + + text #49 + Read rate + 117 + 329 + 90 + + + + + true + + + message button #52 + + + $(P)$(R)Read.PROC + 1 + Write + + + $(P)$(R)Read.PROC + Read + 217 + 329 + 50 + 20 + + + + + + diff --git a/opi/boy/autoconvert/asynGPIBSetup.opi b/opi/boy/autoconvert/asynGPIBSetup.opi index 395c3d1..e1bd127 100644 --- a/opi/boy/autoconvert/asynGPIBSetup.opi +++ b/opi/boy/autoconvert/asynGPIBSetup.opi @@ -9,7 +9,7 @@ - 5.1.0.201801081728 + 5.1.0 diff --git a/opi/boy/autoconvert/asynIPPortSetup.opi b/opi/boy/autoconvert/asynIPPortSetup.opi index 9ddde52..091b709 100644 --- a/opi/boy/autoconvert/asynIPPortSetup.opi +++ b/opi/boy/autoconvert/asynIPPortSetup.opi @@ -9,7 +9,7 @@ - 5.1.0.201801081728 + 5.1.0 @@ -286,7 +286,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -326,7 +326,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -366,7 +366,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -512,7 +512,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -552,7 +552,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -592,7 +592,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -632,7 +632,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -848,7 +848,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -932,7 +932,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -1016,7 +1016,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -1100,7 +1100,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -1184,7 +1184,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -1286,7 +1286,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -1326,7 +1326,7 @@ $(pv_value) 20 - 1 + 2 Label diff --git a/opi/boy/autoconvert/asynOctet.opi b/opi/boy/autoconvert/asynOctet.opi index 2c37bb5..2a5db6d 100644 --- a/opi/boy/autoconvert/asynOctet.opi +++ b/opi/boy/autoconvert/asynOctet.opi @@ -9,7 +9,7 @@ - 5.1.0.201801081728 + 5.1.0 @@ -531,7 +531,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -1241,7 +1241,7 @@ $(pv_value) - true + false @@ -1253,7 +1253,7 @@ $(pv_value) true - + 4 20 @@ -1292,7 +1292,7 @@ $(pv_value) - true + false @@ -1304,7 +1304,7 @@ $(pv_value) true - + 4 20 @@ -1354,7 +1354,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -1990,7 +1990,7 @@ $(pv_value) 20 - 1 + 2 Label diff --git a/opi/boy/autoconvert/asynRecord.opi b/opi/boy/autoconvert/asynRecord.opi index 4b95ef6..1788226 100644 --- a/opi/boy/autoconvert/asynRecord.opi +++ b/opi/boy/autoconvert/asynRecord.opi @@ -9,7 +9,7 @@ - 5.1.0.201801081728 + 5.1.0 @@ -408,7 +408,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -458,7 +458,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -552,7 +552,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -602,7 +602,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -1691,7 +1691,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -1741,7 +1741,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -2083,7 +2083,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -2133,7 +2133,7 @@ $(pv_value) 20 - 1 + 2 Label diff --git a/opi/boy/autoconvert/asynRegister.opi b/opi/boy/autoconvert/asynRegister.opi index efc9164..3ca7415 100644 --- a/opi/boy/autoconvert/asynRegister.opi +++ b/opi/boy/autoconvert/asynRegister.opi @@ -9,7 +9,7 @@ - 5.1.0.201801081728 + 5.1.0 @@ -309,7 +309,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -418,7 +418,7 @@ $(pv_value) - true + false @@ -430,7 +430,7 @@ $(pv_value) true - + 4 20 @@ -469,7 +469,7 @@ $(pv_value) - true + false @@ -481,7 +481,7 @@ $(pv_value) true - + 4 20 @@ -531,7 +531,7 @@ $(pv_value) 20 - 1 + 2 Label diff --git a/opi/boy/autoconvert/asynSerialPortSetup.opi b/opi/boy/autoconvert/asynSerialPortSetup.opi index 379762c..1e600c6 100644 --- a/opi/boy/autoconvert/asynSerialPortSetup.opi +++ b/opi/boy/autoconvert/asynSerialPortSetup.opi @@ -9,7 +9,7 @@ - 5.1.0.201801081728 + 5.1.0 @@ -286,7 +286,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -370,7 +370,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -410,7 +410,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -450,7 +450,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -490,7 +490,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -530,7 +530,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -746,7 +746,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -830,7 +830,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -914,7 +914,7 @@ $(pv_value) 20 - 1 + 2 Label @@ -998,7 +998,7 @@ $(pv_value) 20 - 1 + 2 Label diff --git a/opi/boy/autoconvert/asynTimeSeries.opi b/opi/boy/autoconvert/asynTimeSeries.opi index 1f294d4..be31b50 100644 --- a/opi/boy/autoconvert/asynTimeSeries.opi +++ b/opi/boy/autoconvert/asynTimeSeries.opi @@ -9,7 +9,7 @@ - 5.1.0.201801081728 + 5.1.0 @@ -291,7 +291,7 @@ $(pv_value) 1 20 - 0 + 2 Text Update 0 true @@ -497,15 +497,15 @@ $(pv_value) $(trace_0_y_pv) $(trace_0_y_pv_value) true - 100 - true + 0 + false 1 $(trace_0_y_pv) 0 4 0 - + 0 100 @@ -515,7 +515,7 @@ $(trace_0_y_pv_value) 1 - $(pv_name) + $(P)$(R).VAL true 100 diff --git a/opi/edm/autoconvert/asynGPIBSetup.edl b/opi/edm/autoconvert/asynGPIBSetup.edl index d3aecc1..434a165 100644 --- a/opi/edm/autoconvert/asynGPIBSetup.edl +++ b/opi/edm/autoconvert/asynGPIBSetup.edl @@ -1,29 +1,29 @@ -4 0 0 +4 0 1 beginScreenProperties major 4 minor 0 -release 0 +release 1 x 456 y 239 w 375 h 185 font "helvetica-medium-r-18.0" -ctlFont "helvetica-medium-r-8.0" +ctlFont "helvetica-bold-r-10.0" btnFont "helvetica-medium-r-18.0" -fgColor index 14 -bgColor index 4 -textColor index 14 -ctlFgColor1 index 30 -ctlFgColor2 index 32 -ctlBgColor1 index 34 -ctlBgColor2 index 35 -topShadowColor index 37 -botShadowColor index 44 +fgColor rgb 0 0 0 +bgColor rgb 47872 47872 47872 +textColor rgb 0 0 0 +ctlFgColor1 rgb 64256 62208 18944 +ctlFgColor2 rgb 60928 46592 11008 +ctlBgColor1 rgb 52480 24832 0 +ctlBgColor2 rgb 65280 45056 65280 +topShadowColor rgb 44544 19968 48128 +botShadowColor rgb 13312 13056 34304 +showGrid snapToGrid -gridSize 5 +gridSize 4 endScreenProperties - # (Rectangle) object activeRectangleClass beginObjectProperties @@ -34,9 +34,9 @@ x 0 y 8 w 374 h 28 -lineColor index 2 +lineColor rgb 55808 55808 55808 fill -fillColor index 2 +fillColor rgb 55808 55808 55808 lineWidth 0 endObjectProperties @@ -44,18 +44,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 0 y 12 w 375 h 25 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-18.0" fontAlign "center" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "$(P)$(R)" + "$(P)$(R)" } endObjectProperties @@ -63,17 +64,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 4 y 68 w 130 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "GPIB address:" + "GPIB address:" } endObjectProperties @@ -81,85 +83,87 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 139 y 68 w 75 h 20 controlPv "$(P)$(R).ADDR" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 +format "decimal" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 editable -autoHeight -format decimal motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 4 y 97 w 210 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Serial poll response:" + "Serial poll response:" } endObjectProperties -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 224 y 97 w 56 h 20 controlPv "$(P)$(R).SPR" -font "helvetica-medium-r-8.0" +format "hex" +font "helvetica-medium-r-14.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 14 -bgColor index 51 -autoHeight -format "hex" -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 4 y 126 w 170 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Universal Command" + "Universal Command" } endObjectProperties @@ -167,17 +171,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 4 y 151 w 170 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Addressed Command" + "Addressed Command" } endObjectProperties @@ -185,17 +190,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 218 y 42 w 90 h 20 -font "helvetica-medium-r-8.0" -fgColor index 17 +font "helvetica-medium-r-14.0" +fgColor rgb 13056 39168 0 +bgColor index 3 useDisplayBg value { - "Supported" + "Supported" } visPv "CALC\\\{(A)\}($(P)$(R).GPIBIV)" visInvert @@ -207,17 +213,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 208 y 42 w 110 h 20 -font "helvetica-medium-r-8.0" -fgColor index 21 +font "helvetica-medium-r-14.0" +fgColor rgb 56832 4864 2304 +bgColor index 3 useDisplayBg value { - "Unsupported" + "Unsupported" } visPv "CALC\\\{(A)\}($(P)$(R).GPIBIV)" visMin 0 @@ -228,17 +235,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 4 y 42 w 190 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "asynGpib interface:" + "asynGpib interface:" } endObjectProperties @@ -252,14 +260,14 @@ x 179 y 126 w 180 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).UCMD" indicatorPv "$(P)$(R).UCMD" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -272,13 +280,13 @@ x 179 y 151 w 180 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).ACMD" indicatorPv "$(P)$(R).ACMD" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties diff --git a/opi/edm/autoconvert/asynIPPortSetup.edl b/opi/edm/autoconvert/asynIPPortSetup.edl index 5e95576..392ecf6 100644 --- a/opi/edm/autoconvert/asynIPPortSetup.edl +++ b/opi/edm/autoconvert/asynIPPortSetup.edl @@ -1,29 +1,29 @@ -4 0 0 +4 0 1 beginScreenProperties major 4 minor 0 -release 0 +release 1 x 405 y 149 w 260 h 410 font "helvetica-medium-r-18.0" -ctlFont "helvetica-medium-r-8.0" +ctlFont "helvetica-bold-r-10.0" btnFont "helvetica-medium-r-18.0" -fgColor index 14 -bgColor index 4 -textColor index 14 -ctlFgColor1 index 30 -ctlFgColor2 index 32 -ctlBgColor1 index 34 -ctlBgColor2 index 35 -topShadowColor index 37 -botShadowColor index 44 +fgColor rgb 0 0 0 +bgColor rgb 47872 47872 47872 +textColor rgb 0 0 0 +ctlFgColor1 rgb 64256 62208 18944 +ctlFgColor2 rgb 60928 46592 11008 +ctlBgColor1 rgb 52480 24832 0 +ctlBgColor2 rgb 65280 45056 65280 +topShadowColor rgb 44544 19968 48128 +botShadowColor rgb 13312 13056 34304 +showGrid snapToGrid -gridSize 5 +gridSize 4 endScreenProperties - # (Rectangle) object activeRectangleClass beginObjectProperties @@ -34,9 +34,9 @@ x 0 y 2 w 259 h 15 -lineColor index 2 +lineColor rgb 55808 55808 55808 fill -fillColor index 2 +fillColor rgb 55808 55808 55808 lineWidth 0 endObjectProperties @@ -44,18 +44,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 0 y 2 w 260 h 16 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "center" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "$(P)$(R)" + "$(P)$(R)" } endObjectProperties @@ -63,17 +64,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 148 y 25 w 90 h 20 -font "helvetica-medium-r-8.0" -fgColor index 17 +font "helvetica-medium-r-14.0" +fgColor rgb 13056 39168 0 +bgColor index 3 useDisplayBg value { - "Supported" + "Supported" } visPv "CALC\\\{(A)\}($(P)$(R).OPTIONIV)" visInvert @@ -85,17 +87,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 138 y 25 w 110 h 20 -font "helvetica-medium-r-8.0" -fgColor index 21 +font "helvetica-medium-r-14.0" +fgColor rgb 56832 4864 2304 +bgColor index 3 useDisplayBg value { - "Unsupported" + "Unsupported" } visPv "CALC\\\{(A)\}($(P)$(R).OPTIONIV)" visMin 0 @@ -106,17 +109,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 8 y 25 w 110 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "asynOption:" + "asynOption:" } endObjectProperties @@ -124,18 +128,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 13 y 51 w 130 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Disconnect on" + "Disconnect on" } endObjectProperties @@ -143,18 +148,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 13 y 76 w 130 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "read timeout:" + "read timeout:" } endObjectProperties @@ -162,18 +168,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 43 y 101 w 100 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Host info:" + "Host info:" } endObjectProperties @@ -181,44 +188,45 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 150 y 101 w 102 h 18 controlPv "$(P)$(R).HOSTINFO" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 -editable -autoHeight format "string" +font "helvetica-medium-r-10.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +editable motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 43 y 206 w 100 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Data bits:" + "Data bits:" } endObjectProperties @@ -226,18 +234,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 43 y 231 w 100 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Stop bits:" + "Stop bits:" } endObjectProperties @@ -245,18 +254,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 3 y 281 w 140 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Modem control:" + "Modem control:" } endObjectProperties @@ -264,18 +274,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 73 y 256 w 70 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Parity:" + "Parity:" } endObjectProperties @@ -283,18 +294,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 13 y 306 w 130 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Flow control:" + "Flow control:" } endObjectProperties @@ -302,18 +314,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 23 y 331 w 120 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "XOFF output:" + "XOFF output:" } endObjectProperties @@ -321,18 +334,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 33 y 356 w 110 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "XOFF input:" + "XOFF input:" } endObjectProperties @@ -340,18 +354,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 63 y 381 w 80 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "XON=any:" + "XON=any:" } endObjectProperties @@ -359,18 +374,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 43 y 181 w 100 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Baud rate:" + "Baud rate:" } endObjectProperties @@ -378,44 +394,45 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 150 y 181 w 102 h 18 controlPv "$(P)$(R).LBAUD" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 +format "decimal" +font "helvetica-medium-r-10.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 editable -autoHeight -format decimal motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 15 y 151 w 230 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "COM (RFC 2217) protocol" + "COM (RFC 2217) protocol" } endObjectProperties @@ -423,18 +440,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 5 y 130 w 250 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Parameters for ports with" + "Parameters for ports with" } endObjectProperties @@ -448,14 +466,14 @@ x 150 y 76 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).DRTO" indicatorPv "$(P)$(R).DRTO" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -468,14 +486,14 @@ x 150 y 206 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).DBIT" indicatorPv "$(P)$(R).DBIT" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -488,14 +506,14 @@ x 150 y 231 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).SBIT" indicatorPv "$(P)$(R).SBIT" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -508,14 +526,14 @@ x 150 y 256 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).PRTY" indicatorPv "$(P)$(R).PRTY" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -528,14 +546,14 @@ x 150 y 281 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).MCTL" indicatorPv "$(P)$(R).MCTL" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -548,14 +566,14 @@ x 150 y 306 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).FCTL" indicatorPv "$(P)$(R).FCTL" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -568,14 +586,14 @@ x 150 y 331 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).IXON" indicatorPv "$(P)$(R).IXON" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -588,14 +606,14 @@ x 150 y 356 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).IXOFF" indicatorPv "$(P)$(R).IXOFF" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -608,13 +626,13 @@ x 150 y 381 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).IXANY" indicatorPv "$(P)$(R).IXANY" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties diff --git a/opi/edm/autoconvert/asynOctet.edl b/opi/edm/autoconvert/asynOctet.edl index af89d7b..f436ea0 100644 --- a/opi/edm/autoconvert/asynOctet.edl +++ b/opi/edm/autoconvert/asynOctet.edl @@ -1,68 +1,69 @@ -4 0 0 +4 0 1 beginScreenProperties major 4 minor 0 -release 0 +release 1 x 457 y 494 w 442 h 350 font "helvetica-medium-r-18.0" -ctlFont "helvetica-medium-r-8.0" +ctlFont "helvetica-bold-r-10.0" btnFont "helvetica-medium-r-18.0" -fgColor index 14 -bgColor index 4 -textColor index 14 -ctlFgColor1 index 30 -ctlFgColor2 index 32 -ctlBgColor1 index 34 -ctlBgColor2 index 35 -topShadowColor index 37 -botShadowColor index 44 +fgColor rgb 0 0 0 +bgColor rgb 47872 47872 47872 +textColor rgb 0 0 0 +ctlFgColor1 rgb 64256 62208 18944 +ctlFgColor2 rgb 60928 46592 11008 +ctlBgColor1 rgb 52480 24832 0 +ctlBgColor2 rgb 65280 45056 65280 +topShadowColor rgb 44544 19968 48128 +botShadowColor rgb 13312 13056 34304 +showGrid snapToGrid -gridSize 5 +gridSize 4 endScreenProperties - -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 81 y 216 w 350 h 18 controlPv "$(P)$(R).TINP" -font "helvetica-medium-r-8.0" +format "string" +font "helvetica-medium-r-14.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 47872 47872 47872 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 14 -bgColor index 4 -autoHeight -format "string" -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 6 y 43 w 140 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Timeout (sec):" + "Timeout (sec):" } endObjectProperties @@ -70,44 +71,45 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 151 y 43 w 50 h 20 controlPv "$(P)$(R).TMOT" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 +format "decimal" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 editable -autoHeight -format decimal motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 225 y 43 w 90 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Transfer:" + "Transfer:" } endObjectProperties @@ -121,9 +123,9 @@ x 0 y 5 w 441 h 28 -lineColor index 2 +lineColor rgb 55808 55808 55808 fill -fillColor index 2 +fillColor rgb 55808 55808 55808 lineWidth 0 endObjectProperties @@ -131,18 +133,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 0 y 9 w 442 h 21 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-18.0" fontAlign "center" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "$(P)$(R)" + "$(P)$(R)" } endObjectProperties @@ -150,43 +153,44 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 78 y 128 w 350 h 20 controlPv "$(P)$(R).AOUT" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 -editable -autoHeight format "string" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +editable motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 13 y 99 w 60 h 20 -font "helvetica-medium-r-8.0" -fgColor index 25 +font "helvetica-medium-r-14.0" +fgColor rgb 22528 37632 65280 +bgColor index 3 useDisplayBg value { - "Output" + "Output" } endObjectProperties @@ -194,17 +198,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 91 y 99 w 70 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Format:" + "Format:" } endObjectProperties @@ -212,17 +217,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 13 y 126 w 60 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "ASCII:" + "ASCII:" } endObjectProperties @@ -236,8 +242,8 @@ x 6 y 92 w 430 h 85 -lineColor index 14 -fillColor index 14 +lineColor rgb 0 0 0 +fillColor rgb 0 0 0 lineWidth 0 endObjectProperties @@ -245,17 +251,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 256 y 99 w 110 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Terminator:" + "Terminator:" } endObjectProperties @@ -263,43 +270,44 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 371 y 99 w 60 h 20 controlPv "$(P)$(R).OEOS" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 -editable -autoHeight format "string" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +editable motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 88 y 152 w 100 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Requested:" + "Requested:" } endObjectProperties @@ -307,17 +315,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 10 y 152 w 70 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Length:" + "Length:" } endObjectProperties @@ -325,85 +334,87 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 280 y 152 w 70 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Actual:" + "Actual:" } endObjectProperties -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 355 y 152 w 56 h 20 controlPv "$(P)$(R).NAWT" -font "helvetica-medium-r-8.0" +format "decimal" +font "helvetica-medium-r-14.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 14 -bgColor index 51 -autoHeight -format decimal -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties # (Text Control) object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 193 y 152 w 70 h 20 controlPv "$(P)$(R).NOWT" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 +format "decimal" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 editable -autoHeight -format decimal motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 10 y 297 w 110 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "I/O Status:" + "I/O Status:" } endObjectProperties @@ -411,68 +422,69 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 217 y 297 w 130 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "I/O Severity:" + "I/O Severity:" } endObjectProperties -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 122 y 297 w 85 h 20 controlPv "$(P)$(R).STAT" -font "helvetica-medium-r-8.0" +format "string" +font "helvetica-medium-r-14.0" +fontAlign "left" +fgColor rgb 0 65535 0 +fgAlarm +bgColor rgb 55808 55808 55808 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 14 -fgAlarm -bgColor index 2 -autoHeight -format "string" -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 349 y 297 w 85 h 20 controlPv "$(P)$(R).SEVR" -font "helvetica-medium-r-8.0" +format "string" +font "helvetica-medium-r-14.0" +fontAlign "left" +fgColor rgb 0 65535 0 +fgAlarm +bgColor rgb 55808 55808 55808 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 14 -fgAlarm -bgColor index 2 -autoHeight -format "string" -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties # (Rectangle) @@ -485,8 +497,8 @@ x 6 y 292 w 430 h 25 -lineColor index 14 -fillColor index 14 +lineColor rgb 0 0 0 +fillColor rgb 0 0 0 lineWidth 0 endObjectProperties @@ -494,18 +506,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 9 y 323 w 50 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Scan:" + "Scan:" } endObjectProperties @@ -513,17 +526,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 253 y 189 w 110 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Terminator:" + "Terminator:" } endObjectProperties @@ -531,26 +545,26 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 368 y 189 w 60 h 20 controlPv "$(P)$(R).IEOS" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 -editable -autoHeight format "string" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +editable motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Rectangle) @@ -563,8 +577,8 @@ x 74 y 213 w 360 h 21 -lineColor index 14 -fillColor index 14 +lineColor rgb 0 0 0 +fillColor rgb 0 0 0 lineWidth 0 endObjectProperties @@ -572,17 +586,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 16 y 189 w 50 h 20 -font "helvetica-medium-r-8.0" -fgColor index 25 +font "helvetica-medium-r-14.0" +fgColor rgb 22528 37632 65280 +bgColor index 3 useDisplayBg value { - "Input" + "Input" } endObjectProperties @@ -590,17 +605,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 86 y 191 w 70 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Format:" + "Format:" } endObjectProperties @@ -608,17 +624,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 13 y 215 w 60 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "ASCII:" + "ASCII:" } endObjectProperties @@ -632,8 +649,8 @@ x 6 y 182 w 430 h 105 -lineColor index 14 -fillColor index 14 +lineColor rgb 0 0 0 +fillColor rgb 0 0 0 lineWidth 0 endObjectProperties @@ -641,17 +658,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 88 y 242 w 100 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Requested:" + "Requested:" } endObjectProperties @@ -659,17 +677,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 10 y 242 w 70 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Length:" + "Length:" } endObjectProperties @@ -677,128 +696,131 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 280 y 242 w 70 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Actual:" + "Actual:" } endObjectProperties -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 355 y 242 w 56 h 20 controlPv "$(P)$(R).NORD" -font "helvetica-medium-r-8.0" +format "decimal" +font "helvetica-medium-r-14.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 47872 47872 47872 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 14 -bgColor index 4 -autoHeight -format decimal -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties # (Text Control) object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 193 y 242 w 70 h 20 controlPv "$(P)$(R).NRRD" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 +format "decimal" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 editable -autoHeight -format decimal motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 77 y 265 w 110 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "EOM reason:" + "EOM reason:" } endObjectProperties -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 193 y 265 w 70 h 20 controlPv "$(P)$(R).EOMR" -font "helvetica-medium-r-8.0" +format "string" +font "helvetica-medium-r-14.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 14 -bgColor index 51 -autoHeight -format "string" -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 220 y 66 w 90 h 20 -font "helvetica-medium-r-8.0" -fgColor index 17 +font "helvetica-medium-r-14.0" +fgColor rgb 13056 39168 0 +bgColor index 3 useDisplayBg value { - "Supported" + "Supported" } visPv "CALC\\\{(A)\}($(P)$(R).OCTETIV)" visInvert @@ -810,17 +832,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 210 y 66 w 110 h 20 -font "helvetica-medium-r-8.0" -fgColor index 21 +font "helvetica-medium-r-14.0" +fgColor rgb 56832 4864 2304 +bgColor index 3 useDisplayBg value { - "Unsupported" + "Unsupported" } visPv "CALC\\\{(A)\}($(P)$(R).OCTETIV)" visMin 0 @@ -831,17 +854,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 6 y 66 w 200 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "asynOctet interface:" + "asynOctet interface:" } endObjectProperties @@ -849,17 +873,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 344 y 66 w 60 h 20 -font "helvetica-medium-r-8.0" -fgColor index 17 +font "helvetica-medium-r-14.0" +fgColor rgb 13056 39168 0 +bgColor index 3 useDisplayBg value { - "Active" + "Active" } visPv "CALC\\\{(A=0)\}($(P)$(R).IFACE)" visInvert @@ -871,17 +896,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 334 y 66 w 80 h 20 -font "helvetica-medium-r-8.0" -fgColor index 21 +font "helvetica-medium-r-14.0" +fgColor rgb 56832 4864 2304 +bgColor index 3 useDisplayBg value { - "Inactive" + "Inactive" } visPv "CALC\\\{(!(A=0))\}($(P)$(R).IFACE)" visInvert @@ -893,17 +919,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 300 y 323 w 70 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "More..." + "More..." } endObjectProperties @@ -917,14 +944,14 @@ x 320 y 43 w 110 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).TMOD" indicatorPv "$(P)$(R).TMOD" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -937,14 +964,14 @@ x 166 y 99 w 80 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).OFMT" indicatorPv "$(P)$(R).OFMT" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -957,14 +984,14 @@ x 64 y 323 w 110 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).SCAN" indicatorPv "$(P)$(R).SCAN" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Message Button) @@ -977,11 +1004,11 @@ x 179 y 323 w 80 h 20 -fgColor index 14 -onColor index 51 -offColor index 51 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +onColor rgb 29440 57088 65280 +offColor rgb 29440 57088 65280 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).PROC" pressValue "1" releaseValue @@ -989,7 +1016,7 @@ onLabel "Process" offLabel "Process" 3d useEnumNumeric -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -1002,14 +1029,14 @@ x 161 y 189 w 80 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).IFMT" indicatorPv "$(P)$(R).IFMT" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Related Display) @@ -1022,17 +1049,37 @@ x 375 y 323 w 56 h 20 -fgColor index 14 -bgColor index 51 -topShadowColor index 2 -botShadowColor index 12 -font "helvetica-medium-r-10.0" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 +font "helvetica-medium-r-8.0" icon -numPvs 0 -numDsps 0 +numPvs 8 +numDsps 4 displayFileName { + 0 "asynRecord.edl" + 1 "asynRegister.edl" + 2 "asynSerialPortSetup.edl" + 3 "asynGPIBSetup.edl" } menuLabel { + 0 "Record parameters" + 1 "Register interfaces I/O" + 2 "Serial port parameters" + 3 "GPIB parameters" +} +symbols { + 0 "P=$(P),R=$(R)" + 1 "P=$(P),R=$(R)" + 2 "P=$(P),R=$(R)" + 3 "P=$(P),R=$(R)" +} +replaceSymbols { + 0 1 + 1 1 + 2 1 + 3 1 } endObjectProperties diff --git a/opi/edm/autoconvert/asynRecord.edl b/opi/edm/autoconvert/asynRecord.edl index 39bbb0e..071401e 100644 --- a/opi/edm/autoconvert/asynRecord.edl +++ b/opi/edm/autoconvert/asynRecord.edl @@ -1,29 +1,29 @@ -4 0 0 +4 0 1 beginScreenProperties major 4 minor 0 -release 0 +release 1 x 72 y 61 w 440 h 589 font "helvetica-medium-r-18.0" -ctlFont "helvetica-medium-r-8.0" +ctlFont "helvetica-bold-r-10.0" btnFont "helvetica-medium-r-18.0" -fgColor index 14 -bgColor index 4 -textColor index 14 -ctlFgColor1 index 30 -ctlFgColor2 index 32 -ctlBgColor1 index 34 -ctlBgColor2 index 35 -topShadowColor index 37 -botShadowColor index 44 +fgColor rgb 0 0 0 +bgColor rgb 47872 47872 47872 +textColor rgb 0 0 0 +ctlFgColor1 rgb 64256 62208 18944 +ctlFgColor2 rgb 60928 46592 11008 +ctlBgColor1 rgb 52480 24832 0 +ctlBgColor2 rgb 65280 45056 65280 +topShadowColor rgb 44544 19968 48128 +botShadowColor rgb 13312 13056 34304 +showGrid snapToGrid -gridSize 5 +gridSize 4 endScreenProperties - # (Rectangle) object activeRectangleClass beginObjectProperties @@ -34,9 +34,9 @@ x 0 y 8 w 439 h 28 -lineColor index 2 +lineColor rgb 55808 55808 55808 fill -fillColor index 2 +fillColor rgb 55808 55808 55808 lineWidth 0 endObjectProperties @@ -44,60 +44,62 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 0 y 12 w 440 h 21 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-18.0" fontAlign "center" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "$(P)$(R)" + "$(P)$(R)" } endObjectProperties -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 75 y 182 w 359 h 16 controlPv "$(P)$(R).ERRS" -font "helvetica-medium-r-8.0" +format "string" +font "helvetica-medium-r-14.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 55808 55808 55808 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 14 -bgColor index 2 -autoHeight -format "string" -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 10 y 181 w 60 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Error:" + "Error:" } endObjectProperties @@ -111,8 +113,8 @@ x 6 y 178 w 430 h 25 -lineColor index 14 -fillColor index 14 +lineColor rgb 0 0 0 +fillColor rgb 0 0 0 lineWidth 0 endObjectProperties @@ -120,18 +122,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 300 y 212 w 130 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 30 +fgColor rgb 64256 62208 18944 +bgColor index 3 useDisplayBg value { - "noAutoConnect" + "noAutoConnect" } visPv "CALC\\\{(A)\}($(P)$(R).AUCT)" visMin 0 @@ -142,18 +145,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 310 y 212 w 110 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 62 +fgColor rgb 15360 46080 8192 +bgColor index 3 useDisplayBg value { - "autoConnect" + "autoConnect" } visPv "CALC\\\{(A)\}($(P)$(R).AUCT)" visInvert @@ -165,18 +169,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 180 y 212 w 70 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 62 +fgColor rgb 15360 46080 8192 +bgColor index 3 useDisplayBg value { - "Enabled" + "Enabled" } visPv "CALC\\\{(A)\}($(P)$(R).ENBL)" visInvert @@ -188,18 +193,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 175 y 212 w 80 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 20 +fgColor rgb 64768 0 0 +bgColor index 3 useDisplayBg value { - "Disabled" + "Disabled" } visPv "CALC\\\{(A)\}($(P)$(R).ENBL)" visMin 0 @@ -216,8 +222,8 @@ x 6 y 210 w 430 h 49 -lineColor index 14 -fillColor index 14 +lineColor rgb 0 0 0 +fillColor rgb 0 0 0 lineWidth 0 endObjectProperties @@ -225,17 +231,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 68 y 316 w 80 h 18 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceError" + "traceError" } endObjectProperties @@ -243,17 +250,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 68 y 385 w 104 h 18 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceIODriver" + "traceIODriver" } endObjectProperties @@ -261,17 +269,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 68 y 362 w 104 h 18 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceIOFilter" + "traceIOFilter" } endObjectProperties @@ -279,17 +288,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 68 y 339 -w 104 +w 108 h 18 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceIODevice" + "traceIODevice" } endObjectProperties @@ -297,17 +307,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 9 y 269 w 90 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceMask" + "traceMask" } endObjectProperties @@ -315,17 +326,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 242 y 362 -w 80 +w 88 h 18 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceIOHex" + "traceIOHex" } endObjectProperties @@ -333,17 +345,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 242 y 385 w 104 h 18 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Truncate size" + "Truncate size" } endObjectProperties @@ -351,26 +364,26 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 183 y 385 w 50 h 20 controlPv "$(P)$(R).TSIZ" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 +format "decimal" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 editable -autoHeight -format decimal motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Rectangle) @@ -383,8 +396,8 @@ x 5 y 267 w 430 h 315 -lineColor index 14 -fillColor index 14 +lineColor rgb 0 0 0 +fillColor rgb 0 0 0 lineWidth 0 endObjectProperties @@ -392,43 +405,44 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 9 y 293 w 70 h 20 controlPv "$(P)$(R).TMSK" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 -editable -autoHeight format "hex" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +editable motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 6 y 97 w 80 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "drvInfo:" + "drvInfo:" } endObjectProperties @@ -436,43 +450,44 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 88 y 97 w 150 h 20 controlPv "$(P)$(R).DRVINFO" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 -editable -autoHeight format "string" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +editable motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 6 y 122 w 100 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Interface:" + "Interface:" } endObjectProperties @@ -480,17 +495,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 244 y 97 w 70 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Reason:" + "Reason:" } endObjectProperties @@ -498,44 +514,45 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 318 y 97 w 50 h 20 controlPv "$(P)$(R).REASON" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 +format "decimal" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 editable -autoHeight -format decimal motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 25 y 212 w 90 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 62 +fgColor rgb 15360 46080 8192 +bgColor index 3 useDisplayBg value { - "Connected" + "Connected" } visPv "CALC\\\{(A)\}($(P)$(R).CNCT)" visInvert @@ -547,18 +564,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 10 y 212 w 120 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 20 +fgColor rgb 64768 0 0 +bgColor index 3 useDisplayBg value { - "Disconnected" + "Disconnected" } visPv "CALC\\\{(A)\}($(P)$(R).CNCT)" visMin 0 @@ -569,17 +587,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 6 y 47 w 50 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Port:" + "Port:" } endObjectProperties @@ -587,43 +606,44 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 61 y 47 w 150 h 20 controlPv "$(P)$(R).PORT" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 -editable -autoHeight format "string" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +editable motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 228 y 47 w 80 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Address:" + "Address:" } endObjectProperties @@ -631,44 +651,45 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 318 y 47 w 110 h 20 controlPv "$(P)$(R).ADDR" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 +format "decimal" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 editable -autoHeight -format decimal motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 243 y 72 w 90 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 62 +fgColor rgb 15360 46080 8192 +bgColor index 3 useDisplayBg value { - "Connected" + "Connected" } visPv "CALC\\\{(A)\}($(P)$(R).PCNCT)" visInvert @@ -680,18 +701,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 228 y 72 w 120 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 20 +fgColor rgb 64768 0 0 +bgColor index 3 useDisplayBg value { - "Disconnected" + "Disconnected" } visPv "CALC\\\{(A)\}($(P)$(R).PCNCT)" visMin 0 @@ -702,17 +724,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 291 y 147 w 70 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "More..." + "More..." } endObjectProperties @@ -720,17 +743,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 183 y 269 w 110 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceIOMask" + "traceIOMask" } endObjectProperties @@ -738,17 +762,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 242 y 316 -w 96 +w 103 h 18 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceIOASCII" + "traceIOASCII" } endObjectProperties @@ -756,17 +781,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 242 y 339 -w 104 +w 112 h 18 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceIOEscape" + "traceIOEscape" } endObjectProperties @@ -774,43 +800,44 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 183 y 293 w 70 h 20 controlPv "$(P)$(R).TIOM" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 -editable -autoHeight format "hex" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +editable motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 183 y 415 w 130 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceInfoMask" + "traceInfoMask" } endObjectProperties @@ -818,43 +845,44 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 183 y 439 w 70 h 20 controlPv "$(P)$(R).TINM" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 -editable -autoHeight format "hex" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +editable motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 9 y 557 w 88 h 18 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Trace file:" + "Trace file:" } endObjectProperties @@ -862,43 +890,44 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 99 y 555 w 330 h 20 controlPv "$(P)$(R).TFIL" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 -editable -autoHeight format "string" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +editable motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 68 y 408 -w 72 +w 77 h 18 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceFlow" + "traceFlow" } endObjectProperties @@ -906,17 +935,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 68 y 431 -w 96 +w 102 h 18 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceWarning" + "traceWarning" } endObjectProperties @@ -924,17 +954,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 242 y 485 w 104 h 18 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceInfoPort" + "traceInfoPort" } endObjectProperties @@ -942,17 +973,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 242 y 508 w 120 h 18 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceInfoSource" + "traceInfoSource" } endObjectProperties @@ -960,17 +992,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 242 y 462 w 104 h 18 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceInfoTime" + "traceInfoTime" } endObjectProperties @@ -978,17 +1011,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 242 y 531 w 120 h 18 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "traceInfoThread" + "traceInfoThread" } endObjectProperties @@ -1002,14 +1036,14 @@ x 305 y 233 w 120 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).AUCT" indicatorPv "$(P)$(R).AUCT" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -1022,14 +1056,14 @@ x 155 y 234 w 120 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).ENBL" indicatorPv "$(P)$(R).ENBL" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Choice Button) @@ -1042,12 +1076,12 @@ x 9 y 316 w 55 h 18 -fgColor index 14 -bgColor index 51 -selectColor index 51 -inconsistentColor index 14 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +selectColor rgb 29440 57088 65280 +inconsistentColor rgb 0 0 0 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).TB0" font "helvetica-medium-r-10.0" orientation "horizontal" @@ -1063,12 +1097,12 @@ x 9 y 385 w 55 h 18 -fgColor index 14 -bgColor index 51 -selectColor index 51 -inconsistentColor index 14 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +selectColor rgb 29440 57088 65280 +inconsistentColor rgb 0 0 0 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).TB3" font "helvetica-medium-r-10.0" orientation "horizontal" @@ -1084,12 +1118,12 @@ x 9 y 362 w 55 h 18 -fgColor index 14 -bgColor index 51 -selectColor index 51 -inconsistentColor index 14 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +selectColor rgb 29440 57088 65280 +inconsistentColor rgb 0 0 0 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).TB2" font "helvetica-medium-r-10.0" orientation "horizontal" @@ -1105,12 +1139,12 @@ x 9 y 339 w 55 h 18 -fgColor index 14 -bgColor index 51 -selectColor index 51 -inconsistentColor index 14 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +selectColor rgb 29440 57088 65280 +inconsistentColor rgb 0 0 0 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).TB1" font "helvetica-medium-r-10.0" orientation "horizontal" @@ -1126,12 +1160,12 @@ x 183 y 362 w 55 h 18 -fgColor index 14 -bgColor index 51 -selectColor index 51 -inconsistentColor index 14 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +selectColor rgb 29440 57088 65280 +inconsistentColor rgb 0 0 0 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).TIB2" font "helvetica-medium-r-10.0" orientation "horizontal" @@ -1147,14 +1181,14 @@ x 111 y 122 w 130 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).IFACE" indicatorPv "$(P)$(R).IFACE" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Message Button) @@ -1167,11 +1201,11 @@ x 6 y 147 w 150 h 20 -fgColor index 14 -onColor index 51 -offColor index 51 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +onColor rgb 29440 57088 65280 +offColor rgb 29440 57088 65280 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).AQR" pressValue "1" releaseValue @@ -1179,7 +1213,7 @@ onLabel "Cancel queueRequest" offLabel "Cancel queueRequest" 3d useEnumNumeric -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -1192,14 +1226,14 @@ x 10 y 234 w 120 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).CNCT" indicatorPv "$(P)$(R).CNCT" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -1212,14 +1246,14 @@ x 61 y 72 w 120 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).PCNCT" indicatorPv "$(P)$(R).PCNCT" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Related Display) @@ -1232,17 +1266,41 @@ x 366 y 147 w 56 h 20 -fgColor index 14 -bgColor index 51 -topShadowColor index 2 -botShadowColor index 12 -font "helvetica-medium-r-10.0" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 +font "helvetica-medium-r-8.0" icon -numPvs 0 -numDsps 0 +numPvs 10 +numDsps 5 displayFileName { + 0 "asynOctet.edl" + 1 "asynRegister.edl" + 2 "asynSerialPortSetup.edl" + 3 "asynIPPortSetup.edl" + 4 "asynGPIBSetup.edl" } menuLabel { + 0 "asynOctet Interface I/O" + 1 "Register interfaces I/O" + 2 "Serial port parameters" + 3 "IP port parameters" + 4 "GPIB parameters" +} +symbols { + 0 "P=$(P),R=$(R)" + 1 "P=$(P),R=$(R)" + 2 "P=$(P),R=$(R)" + 3 "P=$(P),R=$(R)" + 4 "P=$(P),R=$(R)" +} +replaceSymbols { + 0 1 + 1 1 + 2 1 + 3 1 + 4 1 } endObjectProperties @@ -1256,12 +1314,12 @@ x 183 y 316 w 55 h 18 -fgColor index 14 -bgColor index 51 -selectColor index 51 -inconsistentColor index 14 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +selectColor rgb 29440 57088 65280 +inconsistentColor rgb 0 0 0 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).TIB0" font "helvetica-medium-r-10.0" orientation "horizontal" @@ -1277,12 +1335,12 @@ x 183 y 339 w 55 h 18 -fgColor index 14 -bgColor index 51 -selectColor index 51 -inconsistentColor index 14 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +selectColor rgb 29440 57088 65280 +inconsistentColor rgb 0 0 0 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).TIB1" font "helvetica-medium-r-10.0" orientation "horizontal" @@ -1298,12 +1356,12 @@ x 9 y 408 w 55 h 18 -fgColor index 14 -bgColor index 51 -selectColor index 51 -inconsistentColor index 14 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +selectColor rgb 29440 57088 65280 +inconsistentColor rgb 0 0 0 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).TB4" font "helvetica-medium-r-10.0" orientation "horizontal" @@ -1319,12 +1377,12 @@ x 9 y 431 w 55 h 18 -fgColor index 14 -bgColor index 51 -selectColor index 51 -inconsistentColor index 14 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +selectColor rgb 29440 57088 65280 +inconsistentColor rgb 0 0 0 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).TB5" font "helvetica-medium-r-10.0" orientation "horizontal" @@ -1340,12 +1398,12 @@ x 183 y 485 w 55 h 18 -fgColor index 14 -bgColor index 51 -selectColor index 51 -inconsistentColor index 14 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +selectColor rgb 29440 57088 65280 +inconsistentColor rgb 0 0 0 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).TINB1" font "helvetica-medium-r-10.0" orientation "horizontal" @@ -1361,12 +1419,12 @@ x 183 y 508 w 55 h 18 -fgColor index 14 -bgColor index 51 -selectColor index 51 -inconsistentColor index 14 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +selectColor rgb 29440 57088 65280 +inconsistentColor rgb 0 0 0 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).TINB2" font "helvetica-medium-r-10.0" orientation "horizontal" @@ -1382,12 +1440,12 @@ x 183 y 462 w 55 h 18 -fgColor index 14 -bgColor index 51 -selectColor index 51 -inconsistentColor index 14 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +selectColor rgb 29440 57088 65280 +inconsistentColor rgb 0 0 0 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).TINB0" font "helvetica-medium-r-10.0" orientation "horizontal" @@ -1403,12 +1461,12 @@ x 183 y 531 w 55 h 18 -fgColor index 14 -bgColor index 51 -selectColor index 51 -inconsistentColor index 14 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +selectColor rgb 29440 57088 65280 +inconsistentColor rgb 0 0 0 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).TINB3" font "helvetica-medium-r-10.0" orientation "horizontal" diff --git a/opi/edm/autoconvert/asynRegister.edl b/opi/edm/autoconvert/asynRegister.edl index 034f398..e279dfb 100644 --- a/opi/edm/autoconvert/asynRegister.edl +++ b/opi/edm/autoconvert/asynRegister.edl @@ -1,44 +1,45 @@ -4 0 0 +4 0 1 beginScreenProperties major 4 minor 0 -release 0 +release 1 x 344 y 142 w 510 h 345 font "helvetica-medium-r-18.0" -ctlFont "helvetica-medium-r-8.0" +ctlFont "helvetica-bold-r-10.0" btnFont "helvetica-medium-r-18.0" -fgColor index 14 -bgColor index 4 -textColor index 14 -ctlFgColor1 index 30 -ctlFgColor2 index 32 -ctlBgColor1 index 34 -ctlBgColor2 index 35 -topShadowColor index 37 -botShadowColor index 44 +fgColor rgb 0 0 0 +bgColor rgb 47872 47872 47872 +textColor rgb 0 0 0 +ctlFgColor1 rgb 64256 62208 18944 +ctlFgColor2 rgb 60928 46592 11008 +ctlBgColor1 rgb 52480 24832 0 +ctlBgColor2 rgb 65280 45056 65280 +topShadowColor rgb 44544 19968 48128 +botShadowColor rgb 13312 13056 34304 +showGrid snapToGrid -gridSize 5 +gridSize 4 endScreenProperties - # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 6 y 43 w 140 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Timeout (sec):" + "Timeout (sec):" } endObjectProperties @@ -46,44 +47,45 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 151 y 43 w 50 h 20 controlPv "$(P)$(R).TMOT" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 +format "decimal" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 editable -autoHeight -format decimal motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 225 y 43 w 90 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Transfer:" + "Transfer:" } endObjectProperties @@ -91,17 +93,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 10 y 284 w 110 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "I/O Status:" + "I/O Status:" } endObjectProperties @@ -109,68 +112,69 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 217 y 284 w 130 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "I/O Severity:" + "I/O Severity:" } endObjectProperties -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 122 y 284 w 85 h 20 controlPv "$(P)$(R).STAT" -font "helvetica-medium-r-8.0" +format "string" +font "helvetica-medium-r-14.0" +fontAlign "left" +fgColor rgb 0 65535 0 +fgAlarm +bgColor rgb 55808 55808 55808 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 14 -fgAlarm -bgColor index 2 -autoHeight -format "string" -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 349 y 284 w 85 h 20 controlPv "$(P)$(R).SEVR" -font "helvetica-medium-r-8.0" +format "string" +font "helvetica-medium-r-14.0" +fontAlign "left" +fgColor rgb 0 65535 0 +fgAlarm +bgColor rgb 55808 55808 55808 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 14 -fgAlarm -bgColor index 2 -autoHeight -format "string" -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties # (Rectangle) @@ -183,8 +187,8 @@ x 6 y 279 w 430 h 25 -lineColor index 14 -fillColor index 14 +lineColor rgb 0 0 0 +fillColor rgb 0 0 0 lineWidth 0 endObjectProperties @@ -192,18 +196,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 9 y 310 w 50 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Scan:" + "Scan:" } endObjectProperties @@ -217,9 +222,9 @@ x 0 y 5 w 509 h 28 -lineColor index 2 +lineColor rgb 55808 55808 55808 fill -fillColor index 2 +fillColor rgb 55808 55808 55808 lineWidth 0 endObjectProperties @@ -227,18 +232,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 0 y 9 w 510 h 21 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-18.0" fontAlign "center" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "$(P)$(R)" + "$(P)$(R)" } endObjectProperties @@ -246,17 +252,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 27 y 251 w 110 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Mask (hex):" + "Mask (hex):" } endObjectProperties @@ -264,17 +271,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 17 y 226 w 120 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Input (hex):" + "Input (hex):" } endObjectProperties @@ -282,17 +290,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 77 y 201 w 60 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Input:" + "Input:" } endObjectProperties @@ -300,17 +309,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 7 y 176 w 130 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Output (hex):" + "Output (hex):" } endObjectProperties @@ -318,17 +328,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 67 y 151 w 70 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Output:" + "Output:" } endObjectProperties @@ -336,135 +347,137 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 37 y 76 w 100 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Interface:" + "Interface:" } endObjectProperties -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 147 y 226 w 100 h 20 controlPv "$(P)$(R).I32INP" -font "helvetica-medium-r-8.0" +format "hex" +font "helvetica-medium-r-14.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 14 -bgColor index 51 -autoHeight -format "hex" -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 147 y 201 w 100 h 20 controlPv "$(P)$(R).I32INP" -font "helvetica-medium-r-8.0" +format "decimal" +font "helvetica-medium-r-14.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 14 -bgColor index 51 -autoHeight -format decimal -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties # (Text Control) object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 147 y 176 w 100 h 20 controlPv "$(P)$(R).I32OUT" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 -editable -autoHeight format "hex" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +editable motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Text Control) object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 147 y 151 w 100 h 20 controlPv "$(P)$(R).I32OUT" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 +format "decimal" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 editable -autoHeight -format decimal motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 167 y 126 w 60 h 20 -font "helvetica-medium-r-8.0" -fgColor index 17 +font "helvetica-medium-r-14.0" +fgColor rgb 13056 39168 0 +bgColor index 3 useDisplayBg value { - "Active" + "Active" } visPv "CALC\\\{(A=1)\}($(P)$(R).IFACE)" visInvert @@ -476,17 +489,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 157 y 126 w 80 h 20 -font "helvetica-medium-r-8.0" -fgColor index 21 +font "helvetica-medium-r-14.0" +fgColor rgb 56832 4864 2304 +bgColor index 3 useDisplayBg value { - "Inactive" + "Inactive" } visPv "CALC\\\{(!(A=1))\}($(P)$(R).IFACE)" visInvert @@ -498,17 +512,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 152 y 101 w 90 h 20 -font "helvetica-medium-r-8.0" -fgColor index 17 +font "helvetica-medium-r-14.0" +fgColor rgb 13056 39168 0 +bgColor index 3 useDisplayBg value { - "Supported" + "Supported" } visPv "CALC\\\{(A)\}($(P)$(R).I32IV)" visInvert @@ -520,17 +535,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 142 y 101 w 110 h 20 -font "helvetica-medium-r-8.0" -fgColor index 21 +font "helvetica-medium-r-14.0" +fgColor rgb 56832 4864 2304 +bgColor index 3 useDisplayBg value { - "Unsupported" + "Unsupported" } visPv "CALC\\\{(A)\}($(P)$(R).I32IV)" visMin 0 @@ -541,17 +557,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 172 y 76 w 50 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Int32" + "Int32" } endObjectProperties @@ -559,143 +576,144 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 272 y 251 w 100 h 20 controlPv "$(P)$(R).UI32MASK" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 -editable -autoHeight format "hex" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +editable motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 272 y 226 w 100 h 20 controlPv "$(P)$(R).UI32INP" -font "helvetica-medium-r-8.0" +format "hex" +font "helvetica-medium-r-14.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 14 -bgColor index 51 -autoHeight -format "hex" -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 272 y 201 w 100 h 20 controlPv "$(P)$(R).UI32INP" -font "helvetica-medium-r-8.0" +format "decimal" +font "helvetica-medium-r-14.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 14 -bgColor index 51 -autoHeight -format decimal -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties # (Text Control) object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 272 y 176 w 100 h 20 controlPv "$(P)$(R).UI32OUT" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 -editable -autoHeight format "hex" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +editable motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Text Control) object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 272 y 151 w 100 h 20 controlPv "$(P)$(R).UI32OUT" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 +format "decimal" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 editable -autoHeight -format decimal motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 292 y 126 w 60 h 20 -font "helvetica-medium-r-8.0" -fgColor index 17 +font "helvetica-medium-r-14.0" +fgColor rgb 13056 39168 0 +bgColor index 3 useDisplayBg value { - "Active" + "Active" } visPv "CALC\\\{(A=2)\}($(P)$(R).IFACE)" visInvert @@ -707,17 +725,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 282 y 126 w 80 h 20 -font "helvetica-medium-r-8.0" -fgColor index 21 +font "helvetica-medium-r-14.0" +fgColor rgb 56832 4864 2304 +bgColor index 3 useDisplayBg value { - "Inactive" + "Inactive" } visPv "CALC\\\{(!(A=2))\}($(P)$(R).IFACE)" visInvert @@ -729,17 +748,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 267 y 101 w 110 h 20 -font "helvetica-medium-r-8.0" -fgColor index 21 +font "helvetica-medium-r-14.0" +fgColor rgb 56832 4864 2304 +bgColor index 3 useDisplayBg value { - "Unsupported" + "Unsupported" } visPv "CALC\\\{(A)\}($(P)$(R).UI32IV)" visMin 0 @@ -750,17 +770,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 277 y 101 w 90 h 20 -font "helvetica-medium-r-8.0" -fgColor index 17 +font "helvetica-medium-r-14.0" +fgColor rgb 13056 39168 0 +bgColor index 3 useDisplayBg value { - "Supported" + "Supported" } visPv "CALC\\\{(A)\}($(P)$(R).UI32IV)" visInvert @@ -772,85 +793,87 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 257 y 76 w 130 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "UInt32Digital" + "UInt32Digital" } endObjectProperties -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 397 y 201 w 100 h 20 controlPv "$(P)$(R).F64INP" -font "helvetica-medium-r-8.0" +format "decimal" +font "helvetica-medium-r-14.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 14 -bgColor index 51 -autoHeight -format decimal -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties # (Text Control) object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 397 y 151 w 100 h 20 controlPv "$(P)$(R).F64OUT" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 +format "decimal" +font "helvetica-medium-r-12.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 editable -autoHeight -format decimal motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 417 y 126 w 60 h 20 -font "helvetica-medium-r-8.0" -fgColor index 17 +font "helvetica-medium-r-14.0" +fgColor rgb 13056 39168 0 +bgColor index 3 useDisplayBg value { - "Active" + "Active" } visPv "CALC\\\{(A=3)\}($(P)$(R).IFACE)" visInvert @@ -862,17 +885,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 407 y 126 w 80 h 20 -font "helvetica-medium-r-8.0" -fgColor index 21 +font "helvetica-medium-r-14.0" +fgColor rgb 56832 4864 2304 +bgColor index 3 useDisplayBg value { - "Inactive" + "Inactive" } visPv "CALC\\\{(!(A=3))\}($(P)$(R).IFACE)" visInvert @@ -884,17 +908,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 392 y 101 w 110 h 20 -font "helvetica-medium-r-8.0" -fgColor index 21 +font "helvetica-medium-r-14.0" +fgColor rgb 56832 4864 2304 +bgColor index 3 useDisplayBg value { - "Unsupported" + "Unsupported" } visPv "CALC\\\{(A)\}($(P)$(R).F64IV)" visMin 0 @@ -905,17 +930,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 402 y 101 w 90 h 20 -font "helvetica-medium-r-8.0" -fgColor index 17 +font "helvetica-medium-r-14.0" +fgColor rgb 13056 39168 0 +bgColor index 3 useDisplayBg value { - "Supported" + "Supported" } visPv "CALC\\\{(A)\}($(P)$(R).F64IV)" visInvert @@ -927,17 +953,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 412 y 76 w 70 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Float64" + "Float64" } endObjectProperties @@ -945,17 +972,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 364 y 310 w 70 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "More..." + "More..." } endObjectProperties @@ -969,14 +997,14 @@ x 320 y 43 w 110 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).TMOD" indicatorPv "$(P)$(R).TMOD" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -989,14 +1017,14 @@ x 64 y 310 w 110 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).SCAN" indicatorPv "$(P)$(R).SCAN" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Message Button) @@ -1009,11 +1037,11 @@ x 179 y 310 w 80 h 20 -fgColor index 14 -onColor index 51 -offColor index 51 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +onColor rgb 29440 57088 65280 +offColor rgb 29440 57088 65280 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).PROC" pressValue "1" releaseValue @@ -1021,7 +1049,7 @@ onLabel "Process" offLabel "Process" 3d useEnumNumeric -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -1034,14 +1062,14 @@ x 5 y 101 w 130 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).IFACE" indicatorPv "$(P)$(R).IFACE" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Related Display) @@ -1054,17 +1082,37 @@ x 439 y 310 w 56 h 20 -fgColor index 14 -bgColor index 51 -topShadowColor index 2 -botShadowColor index 12 -font "helvetica-medium-r-10.0" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 +font "helvetica-medium-r-8.0" icon -numPvs 0 -numDsps 0 +numPvs 8 +numDsps 4 displayFileName { + 0 "asynRecord.edl" + 1 "asynRegister.edl" + 2 "asynSerialPortSetup.edl" + 3 "asynGPIBSetup.edl" } menuLabel { + 0 "Record parameters" + 1 "Register interfaces I/O" + 2 "Serial port parameters" + 3 "GPIB parameters" +} +symbols { + 0 "P=$(P),R=$(R)" + 1 "P=$(P),R=$(R)" + 2 "P=$(P),R=$(R)" + 3 "P=$(P),R=$(R)" +} +replaceSymbols { + 0 1 + 1 1 + 2 1 + 3 1 } endObjectProperties diff --git a/opi/edm/autoconvert/asynSerialPortSetup.edl b/opi/edm/autoconvert/asynSerialPortSetup.edl index a895df4..39d9e50 100644 --- a/opi/edm/autoconvert/asynSerialPortSetup.edl +++ b/opi/edm/autoconvert/asynSerialPortSetup.edl @@ -1,29 +1,29 @@ -4 0 0 +4 0 1 beginScreenProperties major 4 minor 0 -release 0 +release 1 x 228 y 79 w 260 h 300 font "helvetica-medium-r-18.0" -ctlFont "helvetica-medium-r-8.0" +ctlFont "helvetica-bold-r-10.0" btnFont "helvetica-medium-r-18.0" -fgColor index 14 -bgColor index 4 -textColor index 14 -ctlFgColor1 index 30 -ctlFgColor2 index 32 -ctlBgColor1 index 34 -ctlBgColor2 index 35 -topShadowColor index 37 -botShadowColor index 44 +fgColor rgb 0 0 0 +bgColor rgb 47872 47872 47872 +textColor rgb 0 0 0 +ctlFgColor1 rgb 64256 62208 18944 +ctlFgColor2 rgb 60928 46592 11008 +ctlBgColor1 rgb 52480 24832 0 +ctlBgColor2 rgb 65280 45056 65280 +topShadowColor rgb 44544 19968 48128 +botShadowColor rgb 13312 13056 34304 +showGrid snapToGrid -gridSize 5 +gridSize 4 endScreenProperties - # (Rectangle) object activeRectangleClass beginObjectProperties @@ -34,9 +34,9 @@ x 0 y 2 w 259 h 15 -lineColor index 2 +lineColor rgb 55808 55808 55808 fill -fillColor index 2 +fillColor rgb 55808 55808 55808 lineWidth 0 endObjectProperties @@ -44,18 +44,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 0 y 2 w 260 h 16 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "center" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "$(P)$(R)" + "$(P)$(R)" } endObjectProperties @@ -63,17 +64,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 148 y 25 w 90 h 20 -font "helvetica-medium-r-8.0" -fgColor index 17 +font "helvetica-medium-r-14.0" +fgColor rgb 13056 39168 0 +bgColor index 3 useDisplayBg value { - "Supported" + "Supported" } visPv "CALC\\\{(A)\}($(P)$(R).OPTIONIV)" visInvert @@ -85,17 +87,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 138 y 25 w 110 h 20 -font "helvetica-medium-r-8.0" -fgColor index 21 +font "helvetica-medium-r-14.0" +fgColor rgb 56832 4864 2304 +bgColor index 3 useDisplayBg value { - "Unsupported" + "Unsupported" } visPv "CALC\\\{(A)\}($(P)$(R).OPTIONIV)" visMin 0 @@ -106,17 +109,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 8 y 25 w 110 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "asynOption:" + "asynOption:" } endObjectProperties @@ -124,18 +128,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 43 y 51 w 100 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Baud rate:" + "Baud rate:" } endObjectProperties @@ -143,18 +148,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 43 y 76 w 100 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Baud rate:" + "Baud rate:" } endObjectProperties @@ -162,18 +168,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 43 y 101 w 100 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Data bits:" + "Data bits:" } endObjectProperties @@ -181,18 +188,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 43 y 126 w 100 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Stop bits:" + "Stop bits:" } endObjectProperties @@ -200,18 +208,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 3 y 176 w 140 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Modem control:" + "Modem control:" } endObjectProperties @@ -219,18 +228,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 73 y 151 w 70 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Parity:" + "Parity:" } endObjectProperties @@ -238,18 +248,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 13 y 201 w 130 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Flow control:" + "Flow control:" } endObjectProperties @@ -257,18 +268,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 23 y 226 w 120 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "XOFF output:" + "XOFF output:" } endObjectProperties @@ -276,18 +288,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 33 y 251 w 110 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "XOFF input:" + "XOFF input:" } endObjectProperties @@ -295,18 +308,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 63 y 276 w 80 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "right" -fgColor index 14 +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "XON=any:" + "XON=any:" } endObjectProperties @@ -314,26 +328,26 @@ endObjectProperties object activeXTextDspClass beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 150 y 76 w 102 h 18 controlPv "$(P)$(R).LBAUD" -font "helvetica-medium-r-8.0" -smartRefresh -fastUpdate -fgColor index 14 -bgColor index 51 +format "decimal" +font "helvetica-medium-r-10.0" +fontAlign "left" +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 editable -autoHeight -format decimal motifWidget -nullColor index 32 -useHexPrefix -objType "controls" +limitsFromDb +nullColor rgb 60928 46592 11008 +smartRefresh +fastUpdate newPos +objType "controls" endObjectProperties # (Menu Button) @@ -346,14 +360,14 @@ x 150 y 51 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).BAUD" indicatorPv "$(P)$(R).BAUD" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -366,14 +380,14 @@ x 150 y 101 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).DBIT" indicatorPv "$(P)$(R).DBIT" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -386,14 +400,14 @@ x 150 y 126 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).SBIT" indicatorPv "$(P)$(R).SBIT" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -406,14 +420,14 @@ x 150 y 151 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).PRTY" indicatorPv "$(P)$(R).PRTY" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -426,14 +440,14 @@ x 150 y 176 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).MCTL" indicatorPv "$(P)$(R).MCTL" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -446,14 +460,14 @@ x 150 y 201 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).FCTL" indicatorPv "$(P)$(R).FCTL" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -466,14 +480,14 @@ x 150 y 226 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).IXON" indicatorPv "$(P)$(R).IXON" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -486,14 +500,14 @@ x 150 y 251 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).IXOFF" indicatorPv "$(P)$(R).IXOFF" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -506,13 +520,13 @@ x 150 y 276 w 102 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R).IXANY" indicatorPv "$(P)$(R).IXANY" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties diff --git a/opi/edm/autoconvert/asynTimeSeries.edl b/opi/edm/autoconvert/asynTimeSeries.edl index df63c15..348be1e 100644 --- a/opi/edm/autoconvert/asynTimeSeries.edl +++ b/opi/edm/autoconvert/asynTimeSeries.edl @@ -1,29 +1,29 @@ -4 0 0 +4 0 1 beginScreenProperties major 4 minor 0 -release 0 +release 1 x 326 y 179 w 500 h 360 font "helvetica-medium-r-18.0" -ctlFont "helvetica-medium-r-8.0" +ctlFont "helvetica-bold-r-10.0" btnFont "helvetica-medium-r-18.0" -fgColor index 14 -bgColor index 4 -textColor index 14 -ctlFgColor1 index 30 -ctlFgColor2 index 32 -ctlBgColor1 index 34 -ctlBgColor2 index 35 -topShadowColor index 37 -botShadowColor index 44 +fgColor rgb 0 0 0 +bgColor rgb 47872 47872 47872 +textColor rgb 0 0 0 +ctlFgColor1 rgb 64256 62208 18944 +ctlFgColor2 rgb 60928 46592 11008 +ctlBgColor1 rgb 52480 24832 0 +ctlBgColor2 rgb 65280 45056 65280 +topShadowColor rgb 44544 19968 48128 +botShadowColor rgb 13312 13056 34304 +showGrid snapToGrid -gridSize 5 +gridSize 4 endScreenProperties - # (Rectangle) object activeRectangleClass beginObjectProperties @@ -34,9 +34,9 @@ x 0 y 5 w 499 h 24 -lineColor index 54 +lineColor rgb 2560 0 47104 fill -fillColor index 54 +fillColor rgb 2560 0 47104 lineWidth 0 endObjectProperties @@ -44,18 +44,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 0 y 5 w 500 h 25 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-18.0" fontAlign "center" -fgColor index 0 +fgColor rgb 65280 65280 65280 +bgColor index 3 useDisplayBg value { - "$(P)$(R)" + "$(P)$(R)" } endObjectProperties @@ -63,18 +64,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 42 y 40 w 90 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "center" -fgColor index 18 +fgColor rgb 11520 32512 0 +bgColor index 3 useDisplayBg value { - "Acquiring" + "Acquiring" } visPv "CALC\\\{(A)\}($(P)$(R).BUSY)" visInvert @@ -86,18 +88,19 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 -x 95 +minor 1 +release 1 +x 91 y 40 -w 40 +w 48 h 20 -font "helvetica-medium-r-8.0" +font "helvetica-medium-r-14.0" fontAlign "center" -fgColor index 21 +fgColor rgb 56832 4864 2304 +bgColor index 3 useDisplayBg value { - "Done" + "Done" } visPv "CALC\\\{(A)\}($(P)$(R).BUSY)" visMin 0 @@ -108,60 +111,61 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 142 y 40 w 60 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Status" + "Status" } endObjectProperties -# (Text Control) -object activeXTextDspClass +# (Text Monitor) +object activeXTextDspClass:noedit beginObjectProperties major 4 -minor 0 +minor 7 release 0 x 224 y 40 w 100 h 20 controlPv "$(P)$(R).NORD" -font "helvetica-medium-r-8.0" +format "decimal" +font "helvetica-medium-r-14.0" fontAlign "right" +fgColor rgb 2560 0 47104 +bgColor rgb 47872 47872 47872 +limitsFromDb +nullColor rgb 60928 46592 11008 smartRefresh fastUpdate -fgColor index 54 -bgColor index 4 -autoHeight -format decimal -nullColor index 32 -useHexPrefix -objType "controls" newPos +objType "controls" endObjectProperties # (Static Text) object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 329 y 40 w 130 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Current point" + "Current point" } endObjectProperties @@ -180,9 +184,9 @@ border graphTitle "$(P)$(R)" xLabel "Time point" yLabel "Value" -fgColor index 14 -bgColor index 2 -gridColor index 14 +fgColor rgb 0 0 0 +bgColor rgb 55808 55808 55808 +gridColor rgb 0 0 0 font "helvetica-medium-r-10.0" # Operating Modes plotMode "plotLastNPts" @@ -209,7 +213,7 @@ plotSymbolType { 0 "circle" } plotColor { - 0 index 27 + 0 rgb 19200 28160 50944 } endObjectProperties @@ -217,17 +221,18 @@ endObjectProperties object activeXTextClass beginObjectProperties major 4 -minor 0 -release 0 +minor 1 +release 1 x 117 y 329 w 90 h 20 -font "helvetica-medium-r-8.0" -fgColor index 14 +font "helvetica-medium-r-14.0" +fgColor rgb 0 0 0 +bgColor index 3 useDisplayBg value { - "Read rate" + "Read rate" } endObjectProperties @@ -241,11 +246,11 @@ x 15 y 65 w 90 h 20 -fgColor index 14 -onColor index 51 -offColor index 51 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +onColor rgb 29440 57088 65280 +offColor rgb 29440 57088 65280 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).RARM" pressValue "1" releaseValue @@ -253,7 +258,7 @@ onLabel "Erase/Start" offLabel "Erase/Start" 3d useEnumNumeric -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Message Button) @@ -266,11 +271,11 @@ x 110 y 65 w 90 h 20 -fgColor index 14 -onColor index 51 -offColor index 51 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +onColor rgb 29440 57088 65280 +offColor rgb 29440 57088 65280 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).RARM" pressValue "3" releaseValue @@ -278,7 +283,7 @@ onLabel "Start" offLabel "Start" 3d useEnumNumeric -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Message Button) @@ -291,11 +296,11 @@ x 205 y 65 w 90 h 20 -fgColor index 14 -onColor index 51 -offColor index 51 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +onColor rgb 29440 57088 65280 +offColor rgb 29440 57088 65280 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R).RARM" pressValue "2" releaseValue @@ -303,7 +308,7 @@ onLabel "Stop" offLabel "Stop" 3d useEnumNumeric -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Menu Button) @@ -316,14 +321,14 @@ x 10 y 329 w 100 h 20 -fgColor index 14 -bgColor index 51 -inconsistentColor index 12 -topShadowColor index 2 -botShadowColor index 12 +fgColor rgb 0 0 0 +bgColor rgb 29440 57088 65280 +inconsistentColor rgb 17920 17920 17920 +topShadowColor rgb 55808 55808 55808 +botShadowColor rgb 17920 17920 17920 controlPv "$(P)$(R)Read.SCAN" indicatorPv "$(P)$(R)Read.SCAN" -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties # (Message Button) @@ -336,11 +341,11 @@ x 217 y 329 w 50 h 20 -fgColor index 14 -onColor index 51 -offColor index 51 -topShadowColor index 0 -botShadowColor index 14 +fgColor rgb 0 0 0 +onColor rgb 29440 57088 65280 +offColor rgb 29440 57088 65280 +topShadowColor rgb 65280 65280 65280 +botShadowColor rgb 0 0 0 controlPv "$(P)$(R)Read.PROC" pressValue "1" releaseValue @@ -348,6 +353,6 @@ onLabel "Read" offLabel "Read" 3d useEnumNumeric -font "helvetica-medium-r-10.0" +font "helvetica-medium-r-12.0" endObjectProperties diff --git a/testApp/src/Makefile b/testApp/src/Makefile index e80a6d8..8ffd0ab 100644 --- a/testApp/src/Makefile +++ b/testApp/src/Makefile @@ -9,6 +9,8 @@ ASYN = $(TOP) ASYN_LIB = $(TOP)/lib/$(T_A) ASYN_BIN = $(TOP)/bin/$(T_A) +USR_CFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET -DUSE_TYPED_DRVET + DBD += devTestBlock.dbd DBD += test.dbd diff --git a/testApp/src/addrChangeDriver.c b/testApp/src/addrChangeDriver.c index 76ab7f5..cdda7c8 100644 --- a/testApp/src/addrChangeDriver.c +++ b/testApp/src/addrChangeDriver.c @@ -9,7 +9,7 @@ ***********************************************************************/ /*test driver for multi-device driver using single-device driver*/ -/* +/* * Author: Marty Kraimer */ @@ -67,7 +67,7 @@ typedef struct addrChangePvt { eosSave *peosSave; void *pasynPvt; /*For registerInterruptSource*/ }addrChangePvt; - + /* private routines */ static asynStatus lowerPortInit(addrChangePvt *paddrChangePvt); static int addrChangeDriverInit(const char *portName, const char *lowerPort, @@ -92,7 +92,7 @@ static asynStatus writeIt(void *drvPvt,asynUser *pasynUser, static asynStatus readIt(void *drvPvt,asynUser *pasynUser, char *data,size_t maxchars,size_t *nbytesTransfered,int *eomReason); - + static asynStatus lowerPortInit(addrChangePvt *paddrChangePvt) { lowerPort *plowerPort = paddrChangePvt->plowerPort; @@ -134,7 +134,7 @@ static asynStatus lowerPortInit(addrChangePvt *paddrChangePvt) free(paddrChangePvt); return asynError; } - + static int addrChangeDriverInit(const char *portName, const char *lowerPortName, int addr) { @@ -148,9 +148,9 @@ static int addrChangeDriverInit(const char *portName, const char *lowerPortName, asynOctet *pasynOctet; nbytes = sizeof(addrChangePvt) + sizeof(lowerPort) + sizeof(eosSave) - + sizeof(asynOctet) + + sizeof(asynOctet) + strlen(portName) + 1 + strlen(lowerPortName) + 1; - + paddrChangePvt = callocMustSucceed(nbytes,sizeof(char), "addrChangeDriverInit"); paddrChangePvt->plowerPort = plowerPort = (lowerPort *)(paddrChangePvt + 1); @@ -216,7 +216,7 @@ static int addrChangeDriverInit(const char *portName, const char *lowerPortName, pasynManager->exceptionCallbackAdd(plowerPort->pasynUser, exceptCallback); return(0); } - + static void exceptCallback(asynUser * pasynUser, asynException exception) { addrChangePvt *paddrChangePvt = pasynUser->userPvt; @@ -237,7 +237,7 @@ static void exceptCallback(asynUser * pasynUser, asynException exception) paddrChangePvt->isConnected = 0; pasynManager->exceptionDisconnect(paddrChangePvt->pasynUser); } - + static asynStatus lockPort(void *drvPvt,asynUser *pasynUser) { addrChangePvt *paddrChangePvt = (addrChangePvt *)drvPvt; @@ -264,7 +264,7 @@ static asynStatus unlockPort(void *pvt,asynUser *pasynUser) addrChangePvt *paddrChangePvt = (addrChangePvt *)pvt; lowerPort *plowerPort = paddrChangePvt->plowerPort; asynUser *pasynUserLower = plowerPort->pasynUser; - + if((pasynManager->unlockPort(pasynUserLower))!=asynSuccess ) { asynPrint(pasynUser,ASYN_TRACE_ERROR, @@ -273,7 +273,7 @@ static asynStatus unlockPort(void *pvt,asynUser *pasynUser) } return asynSuccess; } - + /* asynCommon methods */ static void report(void *drvPvt,FILE *fp,int details) { @@ -283,7 +283,7 @@ static void report(void *drvPvt,FILE *fp,int details) fprintf(fp," %s connected to %s\n", paddrChangePvt->portName,plowerPort->portName); } - + static asynStatus connect(void *drvPvt,asynUser *pasynUser) { addrChangePvt *paddrChangePvt = (addrChangePvt *)drvPvt; @@ -321,7 +321,7 @@ static asynStatus connect(void *drvPvt,asynUser *pasynUser) pasynManager->exceptionConnect(pasynUser); return asynSuccess; } - + static asynStatus disconnect(void *drvPvt,asynUser *pasynUser) { addrChangePvt *paddrChangePvt = (addrChangePvt *)drvPvt; @@ -362,7 +362,7 @@ static asynStatus disconnect(void *drvPvt,asynUser *pasynUser) pasynManager->exceptionDisconnect(pasynUser); return(asynSuccess); } - + /* asynOctet methods*/ static asynStatus writeIt(void *drvPvt,asynUser *pasynUser, const char *data,size_t numchars,size_t *nbytesTransfered) @@ -382,7 +382,7 @@ static asynStatus writeIt(void *drvPvt,asynUser *pasynUser, } return status; } - + static asynStatus readIt(void *drvPvt,asynUser *pasynUser, char *data,size_t maxchars,size_t *nbytesTransfered,int *eomReason) { @@ -405,7 +405,7 @@ static asynStatus readIt(void *drvPvt,asynUser *pasynUser, "addrChangeDriver\n"); return status; } - + /* register addrChangeDriverInit*/ static const iocshArg addrChangeDriverInitArg0 = { "portName", iocshArgString }; static const iocshArg addrChangeDriverInitArg1 = { "lowerPort", iocshArgString}; diff --git a/testApp/src/asynExample.c b/testApp/src/asynExample.c index 14d6e75..d7fd499 100644 --- a/testApp/src/asynExample.c +++ b/testApp/src/asynExample.c @@ -24,7 +24,7 @@ #include #include #include - + #define BUFFER_SIZE 80 typedef struct myData { epicsEventId done; diff --git a/testApp/src/devTestBlock.c b/testApp/src/devTestBlock.c index 5aaff01..7a35734 100644 --- a/testApp/src/devTestBlock.c +++ b/testApp/src/devTestBlock.c @@ -74,7 +74,7 @@ typedef struct devPvt{ processState state; DBADDR dbAddr; }devPvt; - + static asynStatus queueIt(devPvt *pdevPvt); static void queueItDelayed(CALLBACK * pvt); static asynStatus writeIt(asynUser *pasynUser, @@ -99,7 +99,7 @@ commonDset devTestBlockInp = { 5,0,0,initSiWriteRead, 0 ,processCommon}; epicsExportAddress(dset, devTestBlockInp); - + static long initSiWriteRead(stringinRecord *precord) { DBLINK *plink = &precord->inp; @@ -117,7 +117,7 @@ static long initSiWriteRead(stringinRecord *precord) pasynUser = pasynManager->createAsynUser(callbackSiWriteRead, 0); pasynUser->userPvt = pdevPvt; pdevPvt->pasynUser = pasynUser; - status = pasynEpicsUtils->parseLink(pasynUser, plink, + status = pasynEpicsUtils->parseLink(pasynUser, plink, &pdevPvt->portName, &pdevPvt->addr,&userParam); if (status != asynSuccess) { printf("%s devTestBlock::initCommon error in link %s\n", @@ -168,10 +168,10 @@ static long processCommon(dbCommon *precord) status = queueIt(pdevPvt); if(status==asynSuccess) return 0; precord->pact = 0; - } + } return(0); } - + static asynStatus queueIt(devPvt *pdevPvt) { asynStatus status; @@ -216,7 +216,7 @@ static void queueItDelayed(CALLBACK * pvt) &pdevPvt->processCallback,precord->prio,precord); } } - + static asynStatus writeIt(asynUser *pasynUser,const char *message,size_t nbytes) { devPvt *pdevPvt = (devPvt *)pasynUser->userPvt; @@ -269,7 +269,7 @@ static asynStatus readIt(asynUser *pasynUser,char *message, "%s devTestBlock: readIt eomReason %d\n",precord->name,eomReason); return status; } - + static void callbackSiWriteRead(asynUser *pasynUser) { devPvt *pdevPvt = (devPvt *)pasynUser->userPvt; diff --git a/testApp/src/echoDriver.c b/testApp/src/echoDriver.c index a0a740f..39183ca 100644 --- a/testApp/src/echoDriver.c +++ b/testApp/src/echoDriver.c @@ -9,7 +9,7 @@ ***********************************************************************/ /*test driver for asyn support*/ -/* +/* * Author: Marty Kraimer */ @@ -53,7 +53,7 @@ typedef struct echoPvt { int eoslen; void *pasynPvt; /*For registerInterruptSource*/ }echoPvt; - + /* init routine */ static int echoDriverInit(const char *dn, double delay, int noAutoConnect,int multiDevice); @@ -74,7 +74,7 @@ static asynStatus setEos(void *drvPvt,asynUser *pasynUser, const char *eos,int eoslen); static asynStatus getEos(void *drvPvt,asynUser *pasynUser, char *eos, int eossize, int *eoslen); - + static int echoDriverInit(const char *dn, double delay, int noAutoConnect,int multiDevice) { @@ -152,7 +152,7 @@ static void report(void *drvPvt,FILE *fp,int details) (int)pechoPvt->device[i].buffer.nchars); } } - + static asynStatus connect(void *drvPvt,asynUser *pasynUser) { echoPvt *pechoPvt = (echoPvt *)drvPvt; @@ -209,7 +209,7 @@ static asynStatus connect(void *drvPvt,asynUser *pasynUser) pasynManager->exceptionConnect(pasynUser); return(asynSuccess); } - + static asynStatus disconnect(void *drvPvt,asynUser *pasynUser) { echoPvt *pechoPvt = (echoPvt *)drvPvt; @@ -260,7 +260,7 @@ static asynStatus disconnect(void *drvPvt,asynUser *pasynUser) pasynManager->exceptionDisconnect(pasynUser); return(asynSuccess); } - + /* asynOctet methods */ static asynStatus echoWrite(void *drvPvt,asynUser *pasynUser, const char *data,size_t nchars,size_t *nbytesTransfered) @@ -309,7 +309,7 @@ static asynStatus echoWrite(void *drvPvt,asynUser *pasynUser, *nbytesTransfered = nchars; return status; } - + static asynStatus echoRead(void *drvPvt,asynUser *pasynUser, char *data,size_t maxchars,size_t *nbytesTransfered,int *eomReason) { @@ -393,7 +393,7 @@ static asynStatus echoRead(void *drvPvt,asynUser *pasynUser, "echoRead nbytesTransfered %lu\n",(unsigned long)*nbytesTransfered); return status; } - + static asynStatus echoFlush(void *drvPvt,asynUser *pasynUser) { echoPvt *pechoPvt = (echoPvt *)drvPvt; @@ -454,7 +454,7 @@ static asynStatus getEos(void *drvPvt,asynUser *pasynUser, asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s setEos\n",pechoPvt->portName); return(asynSuccess); } - + /* register echoDriverInit*/ static const iocshArg echoDriverInitArg0 = { "portName", iocshArgString }; static const iocshArg echoDriverInitArg1 = { "delay", iocshArgDouble }; diff --git a/testApp/src/interposeInterface.c b/testApp/src/interposeInterface.c index d3bb2b1..4652c57 100644 --- a/testApp/src/interposeInterface.c +++ b/testApp/src/interposeInterface.c @@ -9,7 +9,7 @@ ***********************************************************************/ /*test process module for asyn support*/ -/* +/* * Author: Marty Kraimer */ @@ -36,7 +36,7 @@ typedef struct interposePvt { asynOctet *pasynOctet; void *asynOctetPvt; }interposePvt; - + static int interposeInterfaceInit(const char *interposeInterfaceName, const char *portName,int addr); @@ -64,7 +64,7 @@ static asynOctet octet = { registerInterruptUser,cancelInterruptUser, setInputEos,getInputEos,setOutputEos,getOutputEos }; - + static int interposeInterfaceInit(const char *pmn,const char *dn,int addr) { interposePvt *pinterposePvt; @@ -99,7 +99,7 @@ static int interposeInterfaceInit(const char *pmn,const char *dn,int addr) pinterposePvt->asynOctetPvt = poctetasynInterface->drvPvt; return(0); } - + /* asynOctet methods */ static asynStatus writeIt(void *ppvt,asynUser *pasynUser, const char *data,size_t numchars,size_t *nbytesTransfered) @@ -198,7 +198,7 @@ static asynStatus getOutputEos(void *ppvt,asynUser *pasynUser, return pinterposePvt->pasynOctet->getOutputEos(pinterposePvt->asynOctetPvt, pasynUser,eos,eossize,eoslen); } - + /* register interposeInterfaceInit*/ static const iocshArg interposeInterfaceInitArg0 = {"interposeInterfaceName", iocshArgString }; @@ -206,7 +206,7 @@ static const iocshArg interposeInterfaceInitArg1 = { "portName", iocshArgString }; static const iocshArg interposeInterfaceInitArg2 = { "addr", iocshArgInt }; -static const iocshArg *interposeInterfaceInitArgs[] = +static const iocshArg *interposeInterfaceInitArgs[] = {&interposeInterfaceInitArg0,&interposeInterfaceInitArg1, &interposeInterfaceInitArg2}; static const iocshFuncDef interposeInterfaceInitFuncDef = diff --git a/testApp/src/testMain.cpp b/testApp/src/testMain.cpp index ae0ecb6..fe4f105 100644 --- a/testApp/src/testMain.cpp +++ b/testApp/src/testMain.cpp @@ -13,7 +13,7 @@ int main(int argc,char *argv[]) { - if(argc>=2) { + if(argc>=2) { iocsh(argv[1]); epicsThreadSleep(.2); } diff --git a/testArrayRingBufferApp/src/testArrayRingBuffer.cpp b/testArrayRingBufferApp/src/testArrayRingBuffer.cpp index 5e54e08..a1656f1 100644 --- a/testArrayRingBufferApp/src/testArrayRingBuffer.cpp +++ b/testArrayRingBufferApp/src/testArrayRingBuffer.cpp @@ -1,6 +1,6 @@ /* * testArrayRingBuffer.h - * + * * Asyn driver that inherits from the asynPortDriver class to test using ring buffers with devAsynXXXArray. * * Author: Mark Rivers @@ -36,7 +36,7 @@ static const char *driverName="testArrayRingBuffer"; class testArrayRingBuffer : public asynPortDriver { public: testArrayRingBuffer(const char *portName, int maxArrayLength); - + /* These are the methods that we override from asynPortDriver */ virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); virtual asynStatus readInt32Array(asynUser *pasynUser, epicsInt32 *value, @@ -55,7 +55,7 @@ class testArrayRingBuffer : public asynPortDriver { int P_BurstDelay; int P_ScalarData; int P_ArrayData; - + private: /* Our data */ epicsEventId eventId_; @@ -72,25 +72,25 @@ void arrayGenTaskC(void *drvPvt) * Calls constructor for the asynPortDriver base class. * \param[in] portName The name of the asyn port driver to be created. * \param[in] maxArrayLength The maximum number of points in the volt and time arrays */ -testArrayRingBuffer::testArrayRingBuffer(const char *portName, int maxArrayLength) - : asynPortDriver(portName, - 1, /* maxAddr */ +testArrayRingBuffer::testArrayRingBuffer(const char *portName, int maxArrayLength) + : asynPortDriver(portName, + 1, /* maxAddr */ asynInt32Mask | asynFloat64Mask | asynInt32ArrayMask | asynDrvUserMask, /* Interface mask */ asynInt32Mask | asynFloat64Mask | asynInt32ArrayMask, /* Interrupt mask */ 0, /* asynFlags. This driver does not block and it is not multi-device, so flag is 0 */ 1, /* Autoconnect */ 0, /* Default priority */ - 0) /* Default stack size*/ + 0) /* Default stack size*/ { asynStatus status; const char *functionName = "testArrayRingBuffer"; /* Make sure maxArrayLength is positive */ if (maxArrayLength < 1) maxArrayLength = 10; - + /* Allocate the waveform array */ pData_ = (epicsInt32 *)calloc(maxArrayLength, sizeof(epicsInt32)); - + eventId_ = epicsEventCreate(epicsEventEmpty); createParam(P_RunStopString, asynParamInt32, &P_RunStop); createParam(P_MaxArrayLengthString, asynParamInt32, &P_MaxArrayLength); @@ -100,11 +100,11 @@ testArrayRingBuffer::testArrayRingBuffer(const char *portName, int maxArrayLengt createParam(P_BurstDelayString, asynParamFloat64, &P_BurstDelay); createParam(P_ScalarDataString, asynParamInt32, &P_ScalarData); createParam(P_ArrayDataString, asynParamInt32Array, &P_ArrayData); - + /* Set the initial values of some parameters */ setIntegerParam(P_MaxArrayLength, maxArrayLength); setIntegerParam(P_ArrayLength, maxArrayLength); - + /* Create the thread that does the array callbacks in the background */ status = (asynStatus)(epicsThreadCreate("testArrayRingBufferTask", epicsThreadPriorityMedium, @@ -118,22 +118,22 @@ testArrayRingBuffer::testArrayRingBuffer(const char *portName, int maxArrayLengt } - + /** Array generation ask that runs as a separate thread. When the P_RunStop parameter is set to 1 * it periodically generates a burst of arrays. */ void testArrayRingBuffer::arrayGenTask(void) { double loopDelay; - epicsInt32 runStop; + epicsInt32 runStop; int i, j; epicsInt32 burstLength; double burstDelay; epicsInt32 maxArrayLength; epicsInt32 arrayLength; - + lock(); - /* Loop forever */ - getIntegerParam(P_MaxArrayLength, &maxArrayLength); + /* Loop forever */ + getIntegerParam(P_MaxArrayLength, &maxArrayLength); while (1) { getDoubleParam(P_LoopDelay, &loopDelay); getDoubleParam(P_BurstDelay, &burstDelay); @@ -143,7 +143,7 @@ void testArrayRingBuffer::arrayGenTask(void) if (runStop) epicsEventWaitWithTimeout(eventId_, loopDelay); else (void)epicsEventWait(eventId_); // Take the lock again - lock(); + lock(); /* runStop could have changed while we were waiting */ getIntegerParam(P_RunStop, &runStop); if (!runStop) continue; @@ -160,7 +160,7 @@ void testArrayRingBuffer::arrayGenTask(void) setIntegerParam(P_ScalarData, i); callParamCallbacks(); doCallbacksInt32Array(pData_, arrayLength, P_ArrayData, 0); - if (burstDelay > 0.0) + if (burstDelay > 0.0) epicsThreadSleep(burstDelay); } } @@ -180,40 +180,40 @@ asynStatus testArrayRingBuffer::writeInt32(asynUser *pasynUser, epicsInt32 value /* Set the parameter in the parameter library. */ status = (asynStatus) setIntegerParam(function, value); - + /* Fetch the parameter string name for possible use in debugging */ getParamName(function, ¶mName); if (function == P_RunStop) { if (value) epicsEventSignal(eventId_); - } + } else { /* All other parameters just get set in parameter list, no need to * act on them here */ } - + /* Do callbacks so higher layers see any changes */ status = (asynStatus) callParamCallbacks(); - - 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; } - + /** Called when asyn clients call pasynInt32Array->read(). - * Returns the value of the P_ArrayData array. + * Returns the value of the P_ArrayData array. * \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 testArrayRingBuffer::readInt32Array(asynUser *pasynUser, epicsInt32 *value, +asynStatus testArrayRingBuffer::readInt32Array(asynUser *pasynUser, epicsInt32 *value, size_t nElements, size_t *nIn) { int function = pasynUser->reason; @@ -227,17 +227,17 @@ asynStatus testArrayRingBuffer::readInt32Array(asynUser *pasynUser, epicsInt32 * memcpy(value, pData_, nCopy*sizeof(epicsInt32)); *nIn = nCopy; } - if (status) - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "%s:%s: status=%d, function=%d", + if (status) + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s:%s: status=%d, function=%d", driverName, functionName, status, function); - else - asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, - "%s:%s: function=%d\n", + else + asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, + "%s:%s: function=%d\n", driverName, functionName, function); return status; } - + /* Configuration routine. Called directly, or from the iocsh function below */ extern "C" { diff --git a/testArrayRingBufferApp/src/testArrayRingBufferMain.cpp b/testArrayRingBufferApp/src/testArrayRingBufferMain.cpp index ae0ecb6..fe4f105 100644 --- a/testArrayRingBufferApp/src/testArrayRingBufferMain.cpp +++ b/testArrayRingBufferApp/src/testArrayRingBufferMain.cpp @@ -13,7 +13,7 @@ int main(int argc,char *argv[]) { - if(argc>=2) { + if(argc>=2) { iocsh(argv[1]); epicsThreadSleep(.2); } diff --git a/testAsynPortClientApp/src/testAsynIPPortClient.cpp b/testAsynPortClientApp/src/testAsynIPPortClient.cpp index e9d280a..2e41948 100644 --- a/testAsynPortClientApp/src/testAsynIPPortClient.cpp +++ b/testAsynPortClientApp/src/testAsynIPPortClient.cpp @@ -1,6 +1,6 @@ /* * testAsynIPPortClient.cpp - * + * * Program that creates an asyn IP port driver without an IOC and communicates over standard asyn interfaces * * Author: Mark Rivers @@ -17,13 +17,13 @@ #include /** Test program that demonstrates how to write C++ program that instantiates an asyn port driver - * and communicates with it directly over the asyn interfaces without running an EPICS IOC. + * and communicates with it directly over the asyn interfaces without running an EPICS IOC. * It 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 provides that show how to use testAsynIPPortClient to communicate * with a Web server, XPS motor controller, and a telnet host respectively. - * + * * Usage: testAsynIPPortClient hostInfo outputString [outputEos] [inputEos] * * Example: testAsynIPPortClient cars.uchicago.edu:80 "GET / HTTP/1.0" "\n\n" */ @@ -32,27 +32,27 @@ int main(int argc, char **argv) char input[10000], inputEos[10], outputEos[10]; size_t nIn, nOut; int eomReason; - + if (argc < 3) { printf("Usage: testAsynIPPortClient hostInfo outputString [outputEos] [inputEos]\n"); return 0; } - + drvAsynIPPortConfigure("IP", argv[1], 0, 0, 0); asynOctetClient ip = asynOctetClient("IP", 0); - + if (argc > 3) { epicsStrnRawFromEscaped(outputEos, sizeof(outputEos), argv[3], strlen(argv[3])); - ip.setOutputEos(outputEos, strlen(outputEos)); + ip.setOutputEos(outputEos, (int)strlen(outputEos)); } if (argc > 4) { epicsStrnRawFromEscaped(inputEos, sizeof(inputEos), argv[4], strlen(argv[4])); - ip.setInputEos(inputEos, strlen(inputEos)); + ip.setInputEos(inputEos, (int)strlen(inputEos)); } ip.write(argv[2], strlen(argv[2]), &nOut); ip.read(input, sizeof(input), &nIn, &eomReason); - + printf("Sent %d bytes, output:\n%s\n", (int)nOut, argv[2]); printf("Received %d bytes, eomReason=%d, response:\n%s\n", (int)nIn, eomReason, input); - + } diff --git a/testAsynPortDriverApp/src/testAsynPortDriver.cpp b/testAsynPortDriverApp/src/testAsynPortDriver.cpp index 6443eee..359c89a 100644 --- a/testAsynPortDriverApp/src/testAsynPortDriver.cpp +++ b/testAsynPortDriverApp/src/testAsynPortDriver.cpp @@ -1,6 +1,6 @@ /* * testAsynPortDriver.cpp - * + * * Asyn driver that inherits from the asynPortDriver class to demonstrate its use. * It simulates a digital scope looking at a 1kHz 1000-point noisy sine wave. Controls are * provided for time/division, volts/division, volt offset, trigger delay, noise amplitude, update time, @@ -41,20 +41,20 @@ static int allVoltsPerDivSelections[NUM_VERT_SELECTIONS]={1,2,5,10}; static const char *driverName="testAsynPortDriver"; void simTask(void *drvPvt); - + /** Constructor for the testAsynPortDriver class. * Calls constructor for the asynPortDriver base class. * \param[in] portName The name of the asyn port driver to be created. * \param[in] maxPoints The maximum number of points in the volt and time arrays */ -testAsynPortDriver::testAsynPortDriver(const char *portName, int maxPoints) - : asynPortDriver(portName, - 1, /* maxAddr */ +testAsynPortDriver::testAsynPortDriver(const char *portName, int maxPoints) + : asynPortDriver(portName, + 1, /* maxAddr */ asynInt32Mask | asynFloat64Mask | asynFloat64ArrayMask | asynEnumMask | asynDrvUserMask, /* Interface mask */ asynInt32Mask | asynFloat64Mask | asynFloat64ArrayMask | asynEnumMask, /* Interrupt mask */ 0, /* asynFlags. This driver does not block and it is not multi-device, so flag is 0 */ 1, /* Autoconnect */ 0, /* Default priority */ - 0) /* Default stack size*/ + 0) /* Default stack size*/ { asynStatus status; int i; @@ -62,7 +62,7 @@ testAsynPortDriver::testAsynPortDriver(const char *portName, int maxPoints) /* Make sure maxPoints is positive */ if (maxPoints < 1) maxPoints = 100; - + /* Allocate the waveform array */ pData_ = (epicsFloat64 *)calloc(maxPoints, sizeof(epicsFloat64)); @@ -70,7 +70,7 @@ testAsynPortDriver::testAsynPortDriver(const char *portName, int maxPoints) pTimeBase_ = (epicsFloat64 *)calloc(maxPoints, sizeof(epicsFloat64)); /* Set the time base array */ for (i=0; isimTask(); } @@ -149,9 +149,9 @@ void testAsynPortDriver::simTask(void) double noise, yScale; epicsInt32 run, i, maxPoints; double pi=4.0*atan(1.0); - + lock(); - /* Loop forever */ + /* Loop forever */ while (1) { getDoubleParam(P_UpdateTime, &updateTime); getIntegerParam(P_Run, &run); @@ -160,7 +160,7 @@ void testAsynPortDriver::simTask(void) if (run) epicsEventWaitWithTimeout(eventId_, updateTime); else (void) epicsEventWait(eventId_); // Take the lock again - lock(); + lock(); /* run could have changed while we were waiting */ getIntegerParam(P_Run, &run); if (!run) continue; @@ -175,7 +175,7 @@ void testAsynPortDriver::simTask(void) minValue = 1e6; maxValue = -1e6; meanValue = 0.; - + yScale = 1.0 / voltsPerDiv; for (i=0; ierrorMessage, 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; } @@ -270,7 +270,7 @@ asynStatus testAsynPortDriver::writeFloat64(asynUser *pasynUser, epicsFloat64 va /* Make sure the update time is valid. If not change it and put back in parameter library */ if (value < MIN_UPDATE_TIME) { asynPrint(pasynUser, ASYN_TRACE_WARNING, - "%s:%s: warning, update time too small, changed from %f to %f\n", + "%s:%s: warning, update time too small, changed from %f to %f\n", driverName, functionName, value, MIN_UPDATE_TIME); value = MIN_UPDATE_TIME; setDoubleParam(P_UpdateTime, value); @@ -282,29 +282,29 @@ asynStatus testAsynPortDriver::writeFloat64(asynUser *pasynUser, epicsFloat64 va /* All other parameters just get set in parameter list, no need to * act on them here */ } - + /* Do callbacks so higher layers see any changes */ status = (asynStatus) callParamCallbacks(); - - if (status) - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "%s:%s: status=%d, function=%d, name=%s, value=%f", + + 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; } - + /** Called when asyn clients call pasynFloat64Array->read(). - * Returns the value of the P_Waveform or P_TimeBase arrays. + * Returns the value of the P_Waveform or P_TimeBase arrays. * \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 testAsynPortDriver::readFloat64Array(asynUser *pasynUser, epicsFloat64 *value, +asynStatus testAsynPortDriver::readFloat64Array(asynUser *pasynUser, epicsFloat64 *value, size_t nElements, size_t *nIn) { int function = pasynUser->reason; @@ -326,17 +326,17 @@ asynStatus testAsynPortDriver::readFloat64Array(asynUser *pasynUser, epicsFloat6 memcpy(value, pTimeBase_, ncopy*sizeof(epicsFloat64)); *nIn = ncopy; } - if (status) - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "%s:%s: status=%d, function=%d", + if (status) + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s:%s: status=%d, function=%d", driverName, functionName, status, function); - else - asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, - "%s:%s: function=%d\n", + else + asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, + "%s:%s: function=%d\n", driverName, functionName, function); return status; } - + asynStatus testAsynPortDriver::readEnum(asynUser *pasynUser, char *strings[], int values[], int severities[], size_t nElements, size_t *nIn) { int function = pasynUser->reason; @@ -355,14 +355,14 @@ asynStatus testAsynPortDriver::readEnum(asynUser *pasynUser, char *strings[], in return asynError; } *nIn = i; - return asynSuccess; + return asynSuccess; } void testAsynPortDriver::setVertGain() { epicsInt32 igain, i; double gain; - + getIntegerParam(P_VertGainSelect, &igain); gain = igain; setDoubleParam(P_VertGain, gain); @@ -377,7 +377,7 @@ void testAsynPortDriver::setVertGain() void testAsynPortDriver::setVoltsPerDiv() { epicsInt32 mVPerDiv; - + // Integer volts are in mV getIntegerParam(P_VoltsPerDivSelect, &mVPerDiv); setDoubleParam(P_VoltsPerDiv, mVPerDiv / 1000.); @@ -386,13 +386,13 @@ void testAsynPortDriver::setVoltsPerDiv() void testAsynPortDriver::setTimePerDiv() { epicsInt32 microSecPerDiv; - + // Integer times are in microseconds getIntegerParam(P_TimePerDivSelect, µSecPerDiv); setDoubleParam(P_TimePerDiv, microSecPerDiv / 1000000.); } - + /* Configuration routine. Called directly, or from the iocsh function below */ extern "C" { diff --git a/testAsynPortDriverApp/src/testAsynPortDriver.h b/testAsynPortDriverApp/src/testAsynPortDriver.h index afb55f7..c9deb4a 100644 --- a/testAsynPortDriverApp/src/testAsynPortDriver.h +++ b/testAsynPortDriverApp/src/testAsynPortDriver.h @@ -1,6 +1,6 @@ /* * testAsynPortDriver.h - * + * * Asyn driver that inherits from the asynPortDriver class to demonstrate its use. * It simulates a digital scope looking at a 1kHz 1000-point noisy sine wave. Controls are * provided for time/division, volts/division, volt offset, trigger delay, noise amplitude, update time, @@ -40,13 +40,13 @@ /** Class that demonstrates the use of the asynPortDriver base class to greatly simplify the task * of writing an asyn port driver. * This class does a simple simulation of a digital oscilloscope. It computes a waveform, computes - * statistics on the waveform, and does callbacks with the statistics and the waveform data itself. + * statistics on the waveform, and does callbacks with the statistics and the waveform data itself. * I have made the methods of this class public in order to generate doxygen documentation for them, * but they should really all be private. */ class testAsynPortDriver : public asynPortDriver { public: testAsynPortDriver(const char *portName, int maxArraySize); - + /* These are the methods that we override from asynPortDriver */ virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value); @@ -77,7 +77,7 @@ class testAsynPortDriver : public asynPortDriver { int P_MinValue; int P_MaxValue; int P_MeanValue; - + private: /* Our data */ epicsEventId eventId_; diff --git a/testAsynPortDriverApp/src/testAsynPortDriverMain.cpp b/testAsynPortDriverApp/src/testAsynPortDriverMain.cpp index ae0ecb6..fe4f105 100644 --- a/testAsynPortDriverApp/src/testAsynPortDriverMain.cpp +++ b/testAsynPortDriverApp/src/testAsynPortDriverMain.cpp @@ -13,7 +13,7 @@ int main(int argc,char *argv[]) { - if(argc>=2) { + if(argc>=2) { iocsh(argv[1]); epicsThreadSleep(.2); } diff --git a/testBroadcastApp/src/testBroadcastAsyn.c b/testBroadcastApp/src/testBroadcastAsyn.c index bc6d054..3b80576 100644 --- a/testBroadcastApp/src/testBroadcastAsyn.c +++ b/testBroadcastApp/src/testBroadcastAsyn.c @@ -1,6 +1,6 @@ /* * testBroadcastAsyn.c - * + * * Program to test sending a broadcast message and reading the responses. * This version uses asyn. * This program requires an NSLS electrometer to be present. @@ -29,7 +29,7 @@ int main(int argc, char *argv[]) { int eomReason; int i; asynUser *pasynUser; - + status = (asynStatus)drvAsynIPPortConfigure(PORT_NAME, "164.54.160.255:37747 UDP*", 0, 0, 0); printf("Called drvAsynIPPortConfigure for UDP port, status=%d\n", status); @@ -38,7 +38,7 @@ int main(int argc, char *argv[]) { printf("Called asynSetTraceIOMask for UDP port, status=%d\n", status); status = (asynStatus)asynSetTraceMask(PORT_NAME, 0, 9); printf("Called asynSetTraceMask for UDP port, status=%d\n", status); - + /* Connect to the broadcast port */ status = pasynOctetSyncIO->connect(PORT_NAME, 0, &pasynUser, NULL); printf("Connected to UDP port, status=%d\n", status); @@ -60,4 +60,4 @@ int main(int argc, char *argv[]) { return 0; } - + diff --git a/testBroadcastApp/src/testBroadcastBurst.c b/testBroadcastApp/src/testBroadcastBurst.c index b0255e9..32cca07 100644 --- a/testBroadcastApp/src/testBroadcastBurst.c +++ b/testBroadcastApp/src/testBroadcastBurst.c @@ -1,6 +1,6 @@ /* * testBroadcastBurst.c - * + * * Program to test sending a burst of broadcast messages in a loop. * Usage: testBroadcastBurst broadcastAddress broadcastPort numBroadcast numLoops delayTime * @@ -23,7 +23,7 @@ #include #include -int main(int argc, char *argv[]) +int main(int argc, char *argv[]) { size_t nwrite=0; char buffer[256]; @@ -72,10 +72,10 @@ int main(int argc, char *argv[]) nwrite = sendto(usock, buffer, strlen(buffer), 0, (struct sockaddr *) &rem, sizeof(rem)); } gettimeofday(&tv, NULL); - printf("[%10.10ld.%6.6ld] loop %d, sent %d broadcasts to %s:%d, nwrite on last=%d\n", + printf("[%10.10ld.%6.6ld] loop %d, sent %d broadcasts to %s:%d, nwrite on last=%d\n", (long)tv.tv_sec, (long)tv.tv_usec, i, j, broadcastAddress, port, (int)nwrite); nanosleep(&ts, &tsrem); } return 0; } - + diff --git a/testBroadcastApp/src/testBroadcastNoAsyn.c b/testBroadcastApp/src/testBroadcastNoAsyn.c index 2aa4b3c..166d721 100644 --- a/testBroadcastApp/src/testBroadcastNoAsyn.c +++ b/testBroadcastApp/src/testBroadcastNoAsyn.c @@ -1,6 +1,6 @@ /* * testBroadcastNoAsyn.c - * + * * Program to test sending a broadcast message and reading the responses. * This version uses native socket calls, not asyn. * This program requires an NSLS electrometer to be present. @@ -50,9 +50,9 @@ int main(int argc, char *argv[]) { epicsThreadSleep(0.1); nread = recvfrom(usock, buffer, sizeof(buffer), 0, (struct sockaddr *)&rem, (uint32_t*)&rem_len); printf("Read from UDP port, nread=%d, buffer=\n%s\n", (int)nread, buffer); - + system("netstat -a | grep 164.54.160.255 | grep -v ca-2"); - + return 0; } - + diff --git a/testConnectApp/src/testConnect.cpp b/testConnectApp/src/testConnect.cpp index 033eb00..4f55775 100644 --- a/testConnectApp/src/testConnect.cpp +++ b/testConnectApp/src/testConnect.cpp @@ -1,6 +1,6 @@ /* * testConnect.cpp - * + * * Asyn driver that inherits from the asynPortDriver class to test connection handling * * Author: Mark Rivers @@ -36,9 +36,9 @@ static const char *driverName="testConnect"; static void pollerTask(void *drvPvt); -testConnect::testConnect(const char *portName, const char *IPPortName, const char *outputString) - : asynPortDriver(portName, - 1, /* maxAddr */ +testConnect::testConnect(const char *portName, const char *IPPortName, const char *outputString) + : asynPortDriver(portName, + 1, /* maxAddr */ /* Interface mask */ asynOctetMask, /* Interrupt mask */ @@ -46,20 +46,20 @@ testConnect::testConnect(const char *portName, const char *IPPortName, const cha ASYN_CANBLOCK, /* asynFlags. This driver does block and it is not multi-device*/ 1, /* Autoconnect */ 0, /* Default priority */ - 0) /* Default stack size*/ + 0) /* Default stack size*/ { asynStatus status; const char *functionName = "testConnect"; - + outputString_ = epicsStrDup(outputString); - + /* Connect to the port */ status = pasynOctetSyncIO->connect(IPPortName, 0, &pasynUserIPPort_, NULL); if (status) { printf("%s:%s: pasynOctetSyncIO->connect failure, status=%d\n", driverName, functionName, status); return; } - + /* Create the thread that computes the waveforms in the background */ status = (asynStatus)(epicsThreadCreate("testConnectTask", epicsThreadPriorityMedium, @@ -73,11 +73,11 @@ testConnect::testConnect(const char *portName, const char *IPPortName, const cha } - + static void pollerTask(void *drvPvt) { testConnect *pPvt = (testConnect *)drvPvt; - + pPvt->pollerTask(); } @@ -90,30 +90,30 @@ void testConnect::pollerTask(void) int isConnected; int eomReason; static const char *functionName = "pollerTask"; - - /* Loop forever */ + + /* Loop forever */ while (1) { lock(); status = pasynManager->isConnected(pasynUserIPPort_, &isConnected); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, - "%s:%s: error calling pasynManager->isConnected, status=%d, error=%s\n", + "%s:%s: error calling pasynManager->isConnected, status=%d, error=%s\n", driverName, functionName, status, pasynUserIPPort_->errorMessage); } asynPrint(pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:%s: isConnected = %d\n", driverName, functionName, isConnected); - + status = pasynOctetSyncIO->writeRead(pasynUserIPPort_, outputString_, strlen(outputString_), - response, sizeof(response), + response, sizeof(response), 1.0, &numWrite, &numRead, &eomReason); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, - "%s:%s: error calling pasynOctetSyncIO->writeRead, status=%d, error=%s\n", + "%s:%s: error calling pasynOctetSyncIO->writeRead, status=%d, error=%s\n", driverName, functionName, status, pasynUserIPPort_->errorMessage); } else { asynPrint(pasynUserSelf, ASYN_TRACEIO_DRIVER, - "%s:%s: numWrite=%ld, wrote: %s, numRead=%ld, response=%s\n", + "%s:%s: numWrite=%ld, wrote: %s, numRead=%ld, response=%s\n", driverName, functionName, (long)numWrite, outputString_, (long)numRead, response); } unlock(); diff --git a/testConnectApp/src/testConnectMain.cpp b/testConnectApp/src/testConnectMain.cpp index ae0ecb6..fe4f105 100644 --- a/testConnectApp/src/testConnectMain.cpp +++ b/testConnectApp/src/testConnectMain.cpp @@ -13,7 +13,7 @@ int main(int argc,char *argv[]) { - if(argc>=2) { + if(argc>=2) { iocsh(argv[1]); epicsThreadSleep(.2); } diff --git a/testEpicsApp/Db/Makefile b/testEpicsApp/Db/Makefile index 3eab38b..65968ff 100644 --- a/testEpicsApp/Db/Makefile +++ b/testEpicsApp/Db/Makefile @@ -3,4 +3,11 @@ include $(TOP)/configure/CONFIG DB += devInt32.db DB += devDigital.db DB += devOctet.db + +ifdef BASE_3_15 +DB += devOctetLs.db +endif +ifdef CALC +DB += devOctetCalc.db +endif include $(TOP)/configure/RULES diff --git a/testEpicsApp/Db/devOctetCalc.db b/testEpicsApp/Db/devOctetCalc.db new file mode 100644 index 0000000..d0fb436 --- /dev/null +++ b/testEpicsApp/Db/devOctetCalc.db @@ -0,0 +1,14 @@ +record(stringin,"devScalcoutData") +{ + field(VAL, "devScalcoutAsynWrite test") +} + +record(scalcout,"devScalcoutAsynWrite") +{ + field(INAA, "devScalcoutData") + field(CALC, "AA") + field(OOPT, "Every Time") + field(DOPT, "Use CALC") + field(DTYP, "asynOctetWrite") + field(OUT, "@asyn($(PORT),$(ADDR))") +} diff --git a/testEpicsApp/Db/devOctetLs.db b/testEpicsApp/Db/devOctetLs.db new file mode 100644 index 0000000..f96590b --- /dev/null +++ b/testEpicsApp/Db/devOctetLs.db @@ -0,0 +1,47 @@ +record(lsi,"devLsiAsynCmdResponse") +{ + field(DTYP,"asynOctetCmdResponse") + field(INP,"@asyn($(PORT),$(ADDR)) cmdForCmdResponse") + field(SIZV,"40") +} +record(stringin,"devLsiAsynCmdForWriteRead") +{ + field(VAL,"devLsiAsynWriteRead test") + field(FLNK,"devLsiAsynWriteRead") +} +record(lsi,"devLsiAsynWriteRead") +{ + field(DTYP,"asynOctetWriteRead") + field(INP,"@asyn($(PORT),$(ADDR)) devLsiAsynCmdForWriteRead") + field(SIZV,"40") +} +record(lsi,"devLsiAsynRead") +{ + field(DTYP,"asynOctetRead") + field(INP,"@asyn($(PORT),$(ADDR)) ") + field(SIZV,"40") +} +record(lso,"devLsoAsynWrite") +{ + field(DTYP,"asynOctetWrite") + field(OUT,"@asyn($(PORT),$(ADDR))") + field(SIZV,"40") +} +record(lsi,"devLsiAsynReadIntr") +{ + field(DTYP,"asynOctetRead") + field(INP,"@asyn($(PORT),$(ADDR)) ") + field(SCAN,"I/O Intr") +} +record(stringin, "devPfData") +{ + field(VAL, "dataForDevPfAsynWrite") +} +record(printf,"devPfAsynWrite") +{ + field(DTYP,"asynOctetWrite") + field(OUT,"@asyn($(PORT),$(ADDR))") + field(SIZV,"40") + field(FMT, "%s") + field(INP0, "devPfData") +} diff --git a/testEpicsApp/src/Makefile b/testEpicsApp/src/Makefile index 66d57c7..872d648 100644 --- a/testEpicsApp/src/Makefile +++ b/testEpicsApp/src/Makefile @@ -10,11 +10,25 @@ ASYN_LIB = $(TOP)/lib/$(T_A) ASYN_BIN = $(TOP)/bin/$(T_A) DBD += testEpics.dbd +testEpics_DBD += testEpicsCommon.dbd +ifdef CALC +testEpics_DBD += calcSupport.dbd +testEpics_DBD += asynCalc.dbd +endif LIBRARY_IOC += testEpicsSupport testEpicsSupport_SRCS += int32Driver.c testEpicsSupport_SRCS += uint32DigitalDriver.c testEpicsSupport_LIBS += asyn +ifdef CALC +testEpicsSupport_LIBS += calc +endif +ifdef SSCAN +testEpicsSupport_LIBS += sscan +endif +ifdef SNCSEQ +testEpicsSupport_LIBS += seq pv +endif testEpicsSupport_LIBS += $(EPICS_BASE_IOC_LIBS) PROD_IOC += testEpics @@ -26,6 +40,16 @@ testEpics_SRCS += testEpicsMain.c testEpics_LIBS += testEpicsSupport testEpics_LIBS += testSupport testEpics_LIBS += asyn +ifdef CALC +testEpics_LIBS += calc +endif +# SSCAN is needed if calc was built with SSCAN support. +ifdef SSCAN +testEpics_LIBS += sscan +endif +ifdef SNCSEQ +testEpics_LIBS += seq pv +endif testEpics_LIBS += $(EPICS_BASE_IOC_LIBS) include $(TOP)/configure/RULES diff --git a/testEpicsApp/src/int32Driver.c b/testEpicsApp/src/int32Driver.c index 26ba888..6494007 100644 --- a/testEpicsApp/src/int32Driver.c +++ b/testEpicsApp/src/int32Driver.c @@ -84,7 +84,7 @@ static asynStatus float64Write(void *drvPvt,asynUser *pasynUser, epicsFloat64 value); static asynStatus float64Read(void *drvPvt,asynUser *pasynUser, epicsFloat64 *value); - + static int int32DriverInit(const char *dn,int low,int high) { drvPvt *pdrvPvt; @@ -164,11 +164,11 @@ static int int32DriverInit(const char *dn,int low,int high) (EPICSTHREADFUNC)interruptThread,pdrvPvt); return(0); } - + static asynStatus getAddr(drvPvt *pdrvPvt,asynUser *pasynUser, int *paddr,int portOK) { - asynStatus status; + asynStatus status; status = pasynManager->getAddr(pasynUser,paddr); if(status!=asynSuccess) return status; @@ -190,7 +190,7 @@ static void interruptThread(drvPvt *pdrvPvt) ELLLIST *pclientList; interruptNode *pnode; asynInt32Interrupt *pinterrupt; - + if(pdrvPvt->interruptDelay <= .0001) break; for(addr=0; addrchannel[addr]; @@ -218,7 +218,7 @@ static void interruptThread(drvPvt *pdrvPvt) } } } - + /* asynCommon methods */ static void report(void *pvt,FILE *fp,int details) { @@ -233,7 +233,7 @@ static asynStatus connect(void *pvt,asynUser *pasynUser) { drvPvt *pdrvPvt = (drvPvt *)pvt; int addr; - asynStatus status; + asynStatus status; status = getAddr(pdrvPvt,pasynUser,&addr,1); if(status!=asynSuccess) return status; @@ -258,7 +258,7 @@ static asynStatus disconnect(void *pvt,asynUser *pasynUser) { drvPvt *pdrvPvt = (drvPvt *)pvt; int addr; - asynStatus status; + asynStatus status; status = getAddr(pdrvPvt,pasynUser,&addr,1); if(status!=asynSuccess) return status; @@ -278,13 +278,13 @@ static asynStatus disconnect(void *pvt,asynUser *pasynUser) pasynManager->exceptionDisconnect(pasynUser); return asynSuccess; } - + static asynStatus int32Write(void *pvt,asynUser *pasynUser, epicsInt32 value) { drvPvt *pdrvPvt = (drvPvt *)pvt; int addr; - asynStatus status; + asynStatus status; ELLLIST *pclientList; interruptNode *pnode; asynInt32Interrupt *pinterrupt; @@ -324,7 +324,7 @@ static asynStatus int32Read(void *pvt,asynUser *pasynUser, { drvPvt *pdrvPvt = (drvPvt *)pvt; int addr; - asynStatus status; + asynStatus status; status = getAddr(pdrvPvt,pasynUser,&addr,0); if(status!=asynSuccess) return status; @@ -354,7 +354,7 @@ static asynStatus int32GetBounds(void *pvt, asynUser *pasynUser, "%s int32GetBounds low %d high %d\n",pdrvPvt->portName,*low,*high); return asynSuccess; } - + static asynStatus float64Write(void *pvt,asynUser *pasynUser, epicsFloat64 value) { @@ -412,7 +412,7 @@ static asynStatus float64Read(void *pvt,asynUser *pasynUser, "%s read %f\n",pdrvPvt->portName,*value); return asynSuccess; } - + static const char *testDriverReason = "testDriverReason"; static const char *skipWhite(const char *pstart) { @@ -472,7 +472,7 @@ static asynStatus getType(void *drvPvt,asynUser *pasynUser, static asynStatus destroy(void *drvPvt,asynUser *pasynUser) { return asynSuccess;} - + /* register int32DriverInit*/ static const iocshArg int32DriverInitArg0 = { "portName", iocshArgString }; static const iocshArg int32DriverInitArg1 = { "low", iocshArgInt }; diff --git a/testEpicsApp/src/testEpicsInclude.dbd b/testEpicsApp/src/testEpicsCommon.dbd similarity index 100% rename from testEpicsApp/src/testEpicsInclude.dbd rename to testEpicsApp/src/testEpicsCommon.dbd diff --git a/testEpicsApp/src/testEpicsMain.cpp b/testEpicsApp/src/testEpicsMain.cpp index ae0ecb6..fe4f105 100644 --- a/testEpicsApp/src/testEpicsMain.cpp +++ b/testEpicsApp/src/testEpicsMain.cpp @@ -13,7 +13,7 @@ int main(int argc,char *argv[]) { - if(argc>=2) { + if(argc>=2) { iocsh(argv[1]); epicsThreadSleep(.2); } diff --git a/testEpicsApp/src/uint32DigitalDriver.c b/testEpicsApp/src/uint32DigitalDriver.c index 69d3cda..5345bef 100644 --- a/testEpicsApp/src/uint32DigitalDriver.c +++ b/testEpicsApp/src/uint32DigitalDriver.c @@ -81,7 +81,7 @@ static asynStatus uint32Read(void *drvPvt,asynUser *pasynUser, /* asynFloat64 methods */ static asynStatus float64Write(void *drvPvt,asynUser *pasynUser, epicsFloat64 value); static asynStatus float64Read(void *drvPvt,asynUser *pasynUser, epicsFloat64 *value); - + static int uint32DigitalDriverInit(const char *dn) { drvPvt *pdrvPvt; @@ -159,11 +159,11 @@ static int uint32DigitalDriverInit(const char *dn) (EPICSTHREADFUNC)interruptThread,pdrvPvt); return(0); } - + static asynStatus getAddr(drvPvt *pdrvPvt,asynUser *pasynUser, int *paddr,int portOK) { - asynStatus status; + asynStatus status; status = pasynManager->getAddr(pasynUser,paddr); if(status!=asynSuccess) return status; @@ -185,7 +185,7 @@ static void interruptThread(drvPvt *pdrvPvt) ELLLIST *pclientList; interruptNode *pnode; asynUInt32DigitalInterrupt *pinterrupt; - + if(pdrvPvt->interruptDelay <= .0001) break; for(addr=0; addrchannel[addr]; @@ -217,7 +217,7 @@ static void interruptThread(drvPvt *pdrvPvt) } } - + /* asynCommon methods */ static void report(void *pvt,FILE *fp,int details) { @@ -232,7 +232,7 @@ static asynStatus connect(void *pvt,asynUser *pasynUser) { drvPvt *pdrvPvt = (drvPvt *)pvt; int addr; - asynStatus status; + asynStatus status; status = getAddr(pdrvPvt,pasynUser,&addr,1); if(status!=asynSuccess) return status; @@ -257,7 +257,7 @@ static asynStatus disconnect(void *pvt,asynUser *pasynUser) { drvPvt *pdrvPvt = (drvPvt *)pvt; int addr; - asynStatus status; + asynStatus status; status = getAddr(pdrvPvt,pasynUser,&addr,1); if(status!=asynSuccess) return status; @@ -277,13 +277,13 @@ static asynStatus disconnect(void *pvt,asynUser *pasynUser) pasynManager->exceptionDisconnect(pasynUser); return asynSuccess; } - + static asynStatus uint32Write(void *pvt,asynUser *pasynUser, epicsUInt32 value,epicsUInt32 mask) { drvPvt *pdrvPvt = (drvPvt *)pvt; int addr; - asynStatus status; + asynStatus status; epicsUInt32 newvalue; ELLLIST *pclientList; interruptNode *pnode; @@ -327,7 +327,7 @@ static asynStatus uint32Read(void *pvt,asynUser *pasynUser, { drvPvt *pdrvPvt = (drvPvt *)pvt; int addr; - asynStatus status; + asynStatus status; status = getAddr(pdrvPvt,pasynUser,&addr,0); if(status!=asynSuccess) return status; @@ -347,7 +347,7 @@ static asynStatus uint32Read(void *pvt,asynUser *pasynUser, "%s read %d\n",pdrvPvt->portName,*value); return asynSuccess; } - + static asynStatus float64Write(void *pvt,asynUser *pasynUser, epicsFloat64 value) { @@ -405,7 +405,7 @@ static asynStatus float64Read(void *pvt,asynUser *pasynUser, "%s read %f\n",pdrvPvt->portName,*value); return asynSuccess; } - + static const char *testDriverReason = "testDriverReason"; static const char *skipWhite(const char *pstart) { @@ -466,7 +466,7 @@ static asynStatus getType(void *drvPvt,asynUser *pasynUser, static asynStatus destroy(void *drvPvt,asynUser *pasynUser) { return asynSuccess;} - + /* register uint32DigitalDriverInit*/ static const iocshArg uint32DigitalDriverInitArg0 = { "portName", iocshArgString }; static const iocshArg *uint32DigitalDriverInitArgs[] = { diff --git a/testErrorsApp/Db/Makefile b/testErrorsApp/Db/Makefile index 717864f..09effac 100644 --- a/testErrorsApp/Db/Makefile +++ b/testErrorsApp/Db/Makefile @@ -1,4 +1,5 @@ TOP=../.. include $(TOP)/configure/CONFIG DB += testErrors.db +DB += testErrorsInt64.db include $(TOP)/configure/RULES diff --git a/testErrorsApp/Db/testErrors.db b/testErrorsApp/Db/testErrors.db index 2019d46..7b463b0 100644 --- a/testErrorsApp/Db/testErrors.db +++ b/testErrorsApp/Db/testErrors.db @@ -448,9 +448,8 @@ record(waveform, "$(P)WfInOctet") info(asyn:FIFO, "$(FIFO)") } - ################################################################### -# Records that use devAsynXXXArray # +# Waveform Records that use devAsynXXXArray # ################################################################### record(waveform, "$(P)WfInt8In") { @@ -609,6 +608,168 @@ record(waveform, "$(P)WfFloat64OutRB") info("asyn:FIFO", "$(FIFO)") } + + +################################################################### +# aao and aai Records that use devAsynXXXArray # +################################################################### +record(aai, "$(P)AaiInt8In") +{ + field(DTYP, "asynInt8ArrayIn") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT8_ARRAY_VALUE") + field(FTVL, "CHAR") + field(NELM, "100") + field(TSE, "$(TSE)") + field(SCAN, "$(SCAN)") + info("asyn:FIFO", "$(FIFO)") +} + +record(aao, "$(P)AaoInt8Out") +{ + field(DTYP, "asynInt8ArrayOut") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT8_ARRAY_VALUE") + field(FTVL, "CHAR") + field(NELM, "100") + field(TSE, "$(TSE)") + info("asyn:FIFO", "$(FIFO)") +} + +record(aao, "$(P)AaoInt8OutRB") +{ + field(DTYP, "asynInt8ArrayOut") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT8_ARRAY_VALUE") + field(FTVL, "CHAR") + field(NELM, "100") + field(TSE, "$(TSE)") + info(asyn:READBACK,"1") + info("asyn:FIFO", "$(FIFO)") +} + +record(aai, "$(P)AaiInt16In") +{ + field(DTYP, "asynInt16ArrayIn") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT16_ARRAY_VALUE") + field(FTVL, "SHORT") + field(NELM, "100") + field(TSE, "$(TSE)") + field(SCAN, "$(SCAN)") + info("asyn:FIFO", "$(FIFO)") +} + +record(aao, "$(P)AaoInt16Out") +{ + field(DTYP, "asynInt16ArrayOut") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT16_ARRAY_VALUE") + field(FTVL, "SHORT") + field(NELM, "100") + field(TSE, "$(TSE)") + info("asyn:FIFO", "$(FIFO)") +} + +record(aao, "$(P)AaoInt16OutRB") +{ + field(DTYP, "asynInt16ArrayOut") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT16_ARRAY_VALUE") + field(FTVL, "SHORT") + field(NELM, "100") + field(TSE, "$(TSE)") + info(asyn:READBACK,"1") +} + +record(aai, "$(P)AaiInt32In") +{ + field(DTYP, "asynInt32ArrayIn") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT32_ARRAY_VALUE") + field(FTVL, "LONG") + field(NELM, "100") + field(TSE, "$(TSE)") + field(SCAN, "$(SCAN)") + info("asyn:FIFO", "$(FIFO)") +} + +record(aao, "$(P)AaoInt32Out") +{ + field(DTYP, "asynInt32ArrayOut") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT32_ARRAY_VALUE") + field(FTVL, "LONG") + field(NELM, "100") + field(TSE, "$(TSE)") +} + +record(aao, "$(P)AaoInt32OutRB") +{ + field(DTYP, "asynInt32ArrayOut") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT32_ARRAY_VALUE") + field(FTVL, "LONG") + field(NELM, "100") + field(TSE, "$(TSE)") + info(asyn:READBACK,"1") + info("asyn:FIFO", "$(FIFO)") +} + +record(aai, "$(P)AaiFloat32In") +{ + field(DTYP, "asynFloat32ArrayIn") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))FLOAT32_ARRAY_VALUE") + field(FTVL, "FLOAT") + field(NELM, "100") + field(TSE, "$(TSE)") + field(SCAN, "$(SCAN)") + info("asyn:FIFO", "$(FIFO)") +} + +record(aao, "$(P)AaoFloat32Out") +{ + field(DTYP, "asynFloat32ArrayOut") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))FLOAT32_ARRAY_VALUE") + field(FTVL, "FLOAT") + field(NELM, "100") + field(TSE, "$(TSE)") +} + +record(aao, "$(P)AaoFloat32OutRB") +{ + field(DTYP, "asynFloat32ArrayOut") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))FLOAT32_ARRAY_VALUE") + field(FTVL, "FLOAT") + field(NELM, "100") + field(TSE, "$(TSE)") + info(asyn:READBACK,"1") + info("asyn:FIFO", "$(FIFO)") +} + +record(aai, "$(P)AaiFloat64In") +{ + field(DTYP, "asynFloat64ArrayIn") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))FLOAT64_ARRAY_VALUE") + field(FTVL, "DOUBLE") + field(NELM, "100") + field(TSE, "$(TSE)") + field(SCAN, "$(SCAN)") + info("asyn:FIFO", "$(FIFO)") +} + +record(aao, "$(P)AaoFloat64Out") +{ + field(DTYP, "asynFloat64ArrayOut") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))FLOAT64_ARRAY_VALUE") + field(FTVL, "DOUBLE") + field(NELM, "100") + field(TSE, "$(TSE)") + info("asyn:FIFO", "$(FIFO)") +} + +record(aao, "$(P)AaoFloat64OutRB") +{ + field(DTYP, "asynFloat64ArrayOut") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))FLOAT64_ARRAY_VALUE") + field(FTVL, "DOUBLE") + field(NELM, "100") + field(TSE, "$(TSE)") + info(asyn:READBACK,"1") + info("asyn:FIFO", "$(FIFO)") +} + ################################################################### # asynRecord to test I/O Intr scanning # ################################################################### diff --git a/testErrorsApp/Db/testErrorsInt64.db b/testErrorsApp/Db/testErrorsInt64.db new file mode 100644 index 0000000..4c34afc --- /dev/null +++ b/testErrorsApp/Db/testErrorsInt64.db @@ -0,0 +1,91 @@ +################################################################### +# Records that use devAsynInt64 # +################################################################### + +record(int64out, "$(P)Int64Out") +{ + field(PINI, "1") + field(DTYP, "asynInt64") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT64_VALUE") + field(VAL, "0") +} + +record(int64out, "$(P)Int64OutRB") +{ + field(PINI, "1") + field(DTYP, "asynInt64") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT64_VALUE") + field(VAL, "0") + info(asyn:READBACK,"1") +} + +record(int64in, "$(P)Int64In") +{ + field(DTYP, "asynInt64") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT64_VALUE") + field(TSE, "$(TSE)") + field(SCAN, "$(SCAN)") +} + +record(waveform, "$(P)WfInt64In") +{ + field(DTYP, "asynInt64ArrayIn") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT64_ARRAY_VALUE") + field(FTVL, "INT64") + field(NELM, "100") + field(TSE, "$(TSE)") + field(SCAN, "$(SCAN)") + info("asyn:FIFO", "$(FIFO)") +} + +record(waveform, "$(P)WfInt64Out") +{ + field(DTYP, "asynInt64ArrayOut") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT64_ARRAY_VALUE") + field(FTVL, "INT64") + field(NELM, "100") + field(TSE, "$(TSE)") +} + +record(waveform, "$(P)WfInt64OutRB") +{ + field(DTYP, "asynInt64ArrayOut") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT64_ARRAY_VALUE") + field(FTVL, "INT64") + field(NELM, "100") + field(TSE, "$(TSE)") + info(asyn:READBACK,"1") + info("asyn:FIFO", "$(FIFO)") +} + +record(aai, "$(P)AaiInt64In") +{ + field(DTYP, "asynInt64ArrayIn") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT64_ARRAY_VALUE") + field(FTVL, "INT64") + field(NELM, "100") + field(TSE, "$(TSE)") + field(SCAN, "$(SCAN)") + info("asyn:FIFO", "$(FIFO)") +} + +record(aao, "$(P)AaoInt64Out") +{ + field(DTYP, "asynInt64ArrayOut") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT64_ARRAY_VALUE") + field(FTVL, "INT64") + field(NELM, "100") + field(TSE, "$(TSE)") +} + +record(aao, "$(P)AaoInt64OutRB") +{ + field(DTYP, "asynInt64ArrayOut") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))INT64_ARRAY_VALUE") + field(FTVL, "INT64") + field(NELM, "100") + field(TSE, "$(TSE)") + info(asyn:READBACK,"1") + info("asyn:FIFO", "$(FIFO)") +} + diff --git a/testErrorsApp/adl/testErrors.adl b/testErrorsApp/adl/testErrors.adl index 3e8b5b4..3979e24 100644 --- a/testErrorsApp/adl/testErrors.adl +++ b/testErrorsApp/adl/testErrors.adl @@ -1,14 +1,14 @@ file { - name="/home/epics/devel/asyn-4-29/testErrorsApp/adl/testErrors.adl" - version=030107 + name="/home/epics/devel/asyn/testErrorsApp/adl/testErrors.adl" + version=030109 } display { object { - x=168 - y=51 + x=10 + y=10 width=1360 - height=1000 + height=1055 } clr=14 bclr=4 @@ -100,15 +100,27 @@ text { textix="asyn Error Tests (P=$(P))" align="horiz. centered" } +text { + object { + x=590 + y=35 + width=90 + height=20 + } + "basic attribute" { + clr=54 + } + textix="asynInt32" +} "text update" { object { - x=689 - y=439 + x=690 + y=165 width=61 height=18 } monitor { - chan="$(P)SiOctet" + chan="$(P)MbbiInt32" clr=54 bclr=2 } @@ -118,13 +130,13 @@ text { } "text update" { object { - x=753 - y=439 + x=754 + y=165 width=61 height=18 } monitor { - chan="$(P)SiOctet.STAT" + chan="$(P)MbbiInt32.STAT" clr=54 bclr=2 } @@ -135,13 +147,13 @@ text { } "text update" { object { - x=818 - y=439 + x=819 + y=165 width=61 height=18 } monitor { - chan="$(P)SiOctet.SEVR" + chan="$(P)MbbiInt32.SEVR" clr=54 bclr=2 } @@ -152,56 +164,55 @@ text { } text { object { - x=604 - y=438 - width=80 + x=645 + y=164 + width=40 height=20 } "basic attribute" { clr=14 } - textix="stringin" + textix="mbbi" align="horiz. right" } menu { object { - x=885 - y=438 + x=886 + y=164 width=100 height=20 } control { - chan="$(P)SiOctet.SCAN" + chan="$(P)MbbiInt32.SCAN" clr=14 bclr=51 } } "text update" { object { - x=689 - y=464 + x=690 + y=140 width=61 height=18 } monitor { - chan="$(P)WfInOctet" + chan="$(P)BiInt32" clr=54 bclr=2 } align="horiz. centered" - format="string" limits { } } "text update" { object { - x=753 - y=464 + x=754 + y=140 width=61 height=18 } monitor { - chan="$(P)WfInOctet.STAT" + chan="$(P)BiInt32.STAT" clr=54 bclr=2 } @@ -212,13 +223,13 @@ menu { } "text update" { object { - x=818 - y=464 + x=819 + y=140 width=61 height=18 } monitor { - chan="$(P)WfInOctet.SEVR" + chan="$(P)BiInt32.SEVR" clr=54 bclr=2 } @@ -229,63 +240,39 @@ menu { } text { object { - x=574 - y=463 - width=110 + x=665 + y=139 + width=20 height=20 } "basic attribute" { clr=14 } - textix="waveform in" + textix="bi" align="horiz. right" } menu { object { - x=885 - y=463 + x=886 + y=139 width=100 height=20 } control { - chan="$(P)WfInOctet.SCAN" + chan="$(P)BiInt32.SCAN" clr=14 bclr=51 } } -text { - object { - x=590 - y=409 - width=90 - height=20 - } - "basic attribute" { - clr=54 - } - textix="asynOctet" -} -text { - object { - x=580 - y=325 - width=110 - height=20 - } - "basic attribute" { - clr=54 - } - textix="asynFloat64" -} "text update" { object { x=690 - y=380 + y=90 width=61 height=18 } monitor { - chan="$(P)AiFloat64Average" + chan="$(P)AiInt32Average" clr=54 bclr=2 } @@ -296,12 +283,12 @@ text { "text update" { object { x=754 - y=380 + y=90 width=61 height=18 } monitor { - chan="$(P)AiFloat64Average.STAT" + chan="$(P)AiInt32Average.STAT" clr=54 bclr=2 } @@ -313,12 +300,12 @@ text { "text update" { object { x=819 - y=380 + y=90 width=61 height=18 } monitor { - chan="$(P)AiFloat64Average.SEVR" + chan="$(P)AiInt32Average.SEVR" clr=54 bclr=2 } @@ -330,7 +317,7 @@ text { text { object { x=595 - y=379 + y=89 width=90 height=20 } @@ -343,12 +330,12 @@ text { menu { object { x=886 - y=379 + y=89 width=100 height=20 } control { - chan="$(P)AiFloat64Average.SCAN" + chan="$(P)AiInt32Average.SCAN" clr=14 bclr=51 } @@ -356,12 +343,12 @@ menu { "text update" { object { x=690 - y=355 + y=115 width=61 height=18 } monitor { - chan="$(P)AiFloat64" + chan="$(P)LonginInt32" clr=54 bclr=2 } @@ -372,12 +359,12 @@ menu { "text update" { object { x=754 - y=355 + y=115 width=61 height=18 } monitor { - chan="$(P)AiFloat64.STAT" + chan="$(P)LonginInt32.STAT" clr=54 bclr=2 } @@ -389,12 +376,12 @@ menu { "text update" { object { x=819 - y=355 + y=115 width=61 height=18 } monitor { - chan="$(P)AiFloat64.SEVR" + chan="$(P)LonginInt32.SEVR" clr=54 bclr=2 } @@ -405,52 +392,39 @@ menu { } text { object { - x=665 - y=354 - width=20 + x=625 + y=114 + width=60 height=20 } "basic attribute" { clr=14 } - textix="ai" + textix="longin" align="horiz. right" } menu { object { x=886 - y=354 + y=114 width=100 height=20 } control { - chan="$(P)AiFloat64.SCAN" + chan="$(P)LonginInt32.SCAN" clr=14 bclr=51 } } -text { - object { - x=550 - y=194 - width=170 - height=20 - } - "basic attribute" { - clr=54 - } - textix="asynUInt32Digital" - align="horiz. centered" -} "text update" { object { x=690 - y=271 + y=65 width=61 height=18 } monitor { - chan="$(P)MbbiUInt32D" + chan="$(P)AiInt32" clr=54 bclr=2 } @@ -461,12 +435,12 @@ text { "text update" { object { x=754 - y=271 + y=65 width=61 height=18 } monitor { - chan="$(P)MbbiUInt32D.STAT" + chan="$(P)AiInt32.STAT" clr=54 bclr=2 } @@ -478,12 +452,12 @@ text { "text update" { object { x=819 - y=271 + y=65 width=61 height=18 } monitor { - chan="$(P)MbbiUInt32D.SEVR" + chan="$(P)AiInt32.SEVR" clr=54 bclr=2 } @@ -494,132 +468,124 @@ text { } text { object { - x=645 - y=270 - width=40 + x=665 + y=64 + width=20 height=20 } "basic attribute" { clr=14 } - textix="mbbi" + textix="ai" align="horiz. right" } menu { object { x=886 - y=270 + y=64 width=100 height=20 } control { - chan="$(P)MbbiUInt32D.SCAN" + chan="$(P)AiInt32.SCAN" clr=14 bclr=51 } } -"text update" { +text { object { - x=690 - y=246 - width=61 - height=18 - } - monitor { - chan="$(P)BiUInt32D" - clr=54 - bclr=2 + x=132 + y=39 + width=210 + height=20 } - align="horiz. centered" - limits { + "basic attribute" { + clr=14 } + textix="Without asyn:READBACK" } -"text update" { +menu { object { - x=754 - y=246 - width=61 - height=18 - } - monitor { - chan="$(P)BiUInt32D.STAT" - clr=54 - bclr=2 + x=131 + y=164 + width=80 + height=20 } - clrmod="alarm" - align="horiz. centered" - limits { + control { + chan="$(P)MbboInt32" + clr=14 + bclr=51 } } -"text update" { +menu { object { - x=819 - y=246 - width=61 - height=18 - } - monitor { - chan="$(P)BiUInt32D.SEVR" - clr=54 - bclr=2 + x=131 + y=139 + width=80 + height=20 } - clrmod="alarm" - align="horiz. centered" - limits { + control { + chan="$(P)BoInt32" + clr=14 + bclr=51 } } -text { +"text entry" { object { - x=665 - y=245 - width=20 + x=131 + y=114 + width=80 height=20 } - "basic attribute" { + control { + chan="$(P)LongoutInt32" clr=14 + bclr=2 + } + limits { } - textix="bi" - align="horiz. right" } -menu { +"text entry" { object { - x=886 - y=245 - width=100 + x=131 + y=64 + width=80 height=20 } control { - chan="$(P)BiUInt32D.SCAN" + chan="$(P)AoInt32" clr=14 - bclr=51 + bclr=2 + } + limits { } } "text update" { object { - x=690 - y=221 + x=217 + y=164 width=61 height=18 } monitor { - chan="$(P)LonginUInt32D" + chan="$(P)MbboInt32.STAT" clr=54 bclr=2 } + clrmod="alarm" align="horiz. centered" - format="hexadecimal" limits { } } "text update" { object { - x=754 - y=221 + x=282 + y=164 width=61 height=18 } monitor { - chan="$(P)LonginUInt32D.STAT" + chan="$(P)MbboInt32.SEVR" clr=54 bclr=2 } @@ -630,13 +596,13 @@ menu { } "text update" { object { - x=819 - y=221 + x=217 + y=139 width=61 height=18 } monitor { - chan="$(P)LonginUInt32D.SEVR" + chan="$(P)BoInt32.STAT" clr=54 bclr=2 } @@ -645,58 +611,66 @@ menu { limits { } } -text { +"text update" { object { - x=625 - y=220 - width=60 - height=20 + x=282 + y=139 + width=61 + height=18 } - "basic attribute" { - clr=14 + monitor { + chan="$(P)BoInt32.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { } - textix="longin" - align="horiz. right" } -menu { +"text update" { object { - x=886 - y=220 - width=100 - height=20 + x=217 + y=114 + width=61 + height=18 } - control { - chan="$(P)LonginUInt32D.SCAN" - clr=14 - bclr=51 + monitor { + chan="$(P)LongoutInt32.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { } } "text update" { object { - x=690 - y=296 + x=282 + y=114 width=61 height=18 } monitor { - chan="$(P)MbbiDUInt32D" + chan="$(P)LongoutInt32.SEVR" clr=54 bclr=2 } + clrmod="alarm" align="horiz. centered" - format="hexadecimal" limits { } } "text update" { object { - x=754 - y=296 + x=217 + y=64 width=61 height=18 } monitor { - chan="$(P)MbbiDUInt32D.STAT" + chan="$(P)AoInt32.STAT" clr=54 bclr=2 } @@ -707,13 +681,13 @@ menu { } "text update" { object { - x=819 - y=296 + x=282 + y=64 width=61 height=18 } monitor { - chan="$(P)MbbiDUInt32D.SEVR" + chan="$(P)AoInt32.SEVR" clr=54 bclr=2 } @@ -724,67 +698,81 @@ menu { } text { object { - x=585 - y=295 - width=100 + x=364 + y=39 + width=180 height=20 } "basic attribute" { clr=14 } - textix="mbbiDirect" - align="horiz. right" + textix="With asyn:READBACK" } menu { object { - x=886 - y=295 - width=100 + x=348 + y=164 + width=80 height=20 } control { - chan="$(P)MbbiDUInt32D.SCAN" + chan="$(P)MbboInt32RB" clr=14 bclr=51 } } -text { +menu { object { - x=590 - y=35 - width=90 + x=348 + y=139 + width=80 height=20 } - "basic attribute" { - clr=54 + control { + chan="$(P)BoInt32RB" + clr=14 + bclr=51 } - textix="asynInt32" } -"text update" { +"text entry" { object { - x=690 - y=165 - width=61 - height=18 + x=348 + y=114 + width=80 + height=20 } - monitor { - chan="$(P)MbbiInt32" - clr=54 + control { + chan="$(P)LongoutInt32RB" + clr=14 + bclr=2 + } + limits { + } +} +"text entry" { + object { + x=348 + y=64 + width=80 + height=20 + } + control { + chan="$(P)AoInt32RB" + clr=14 bclr=2 } - align="horiz. centered" limits { } } "text update" { object { - x=754 + x=434 y=165 width=61 height=18 } monitor { - chan="$(P)MbbiInt32.STAT" + chan="$(P)MbboInt32RB.STAT" clr=54 bclr=2 } @@ -795,13 +783,13 @@ text { } "text update" { object { - x=819 + x=499 y=165 width=61 height=18 } monitor { - chan="$(P)MbbiInt32.SEVR" + chan="$(P)MbboInt32RB.SEVR" clr=54 bclr=2 } @@ -810,57 +798,32 @@ text { limits { } } -text { - object { - x=645 - y=164 - width=40 - height=20 - } - "basic attribute" { - clr=14 - } - textix="mbbi" - align="horiz. right" -} -menu { - object { - x=886 - y=164 - width=100 - height=20 - } - control { - chan="$(P)MbbiInt32.SCAN" - clr=14 - bclr=51 - } -} "text update" { object { - x=690 + x=434 y=140 width=61 height=18 } monitor { - chan="$(P)BiInt32" + chan="$(P)BoInt32RB.STAT" clr=54 bclr=2 } + clrmod="alarm" align="horiz. centered" limits { } } "text update" { object { - x=754 + x=499 y=140 width=61 height=18 } monitor { - chan="$(P)BiInt32.STAT" + chan="$(P)BoInt32RB.SEVR" clr=54 bclr=2 } @@ -871,13 +834,13 @@ menu { } "text update" { object { - x=819 - y=140 + x=434 + y=115 width=61 height=18 } monitor { - chan="$(P)BiInt32.SEVR" + chan="$(P)LongoutInt32RB.STAT" clr=54 bclr=2 } @@ -886,57 +849,32 @@ menu { limits { } } -text { - object { - x=665 - y=139 - width=20 - height=20 - } - "basic attribute" { - clr=14 - } - textix="bi" - align="horiz. right" -} -menu { - object { - x=886 - y=139 - width=100 - height=20 - } - control { - chan="$(P)BiInt32.SCAN" - clr=14 - bclr=51 - } -} "text update" { object { - x=690 - y=90 + x=499 + y=115 width=61 height=18 } monitor { - chan="$(P)AiInt32Average" + chan="$(P)LongoutInt32RB.SEVR" clr=54 bclr=2 } + clrmod="alarm" align="horiz. centered" limits { } } "text update" { object { - x=754 - y=90 + x=434 + y=65 width=61 height=18 } monitor { - chan="$(P)AiInt32Average.STAT" + chan="$(P)AoInt32RB.STAT" clr=54 bclr=2 } @@ -947,13 +885,13 @@ menu { } "text update" { object { - x=819 - y=90 + x=499 + y=65 width=61 height=18 } monitor { - chan="$(P)AiInt32Average.SEVR" + chan="$(P)AoInt32RB.SEVR" clr=54 bclr=2 } @@ -964,115 +902,297 @@ menu { } text { object { - x=595 - y=89 - width=90 + x=86 + y=164 + width=40 height=20 } "basic attribute" { clr=14 } - textix="aiAverage" + textix="mbbo" align="horiz. right" } -menu { +text { object { - x=886 - y=89 - width=100 + x=106 + y=139 + width=20 height=20 } - control { - chan="$(P)AiInt32Average.SCAN" + "basic attribute" { clr=14 - bclr=51 } + textix="bo" + align="horiz. right" } -"text update" { +text { object { - x=690 - y=115 - width=61 - height=18 - } - monitor { - chan="$(P)LonginInt32" - clr=54 - bclr=2 + x=56 + y=114 + width=70 + height=20 } - align="horiz. centered" - limits { + "basic attribute" { + clr=14 } + textix="longout" + align="horiz. right" } -"text update" { +text { object { - x=754 - y=115 - width=61 - height=18 + x=106 + y=64 + width=20 + height=20 } - monitor { - chan="$(P)LonginInt32.STAT" - clr=54 - bclr=2 + "basic attribute" { + clr=14 } - clrmod="alarm" - align="horiz. centered" - limits { + textix="ao" + align="horiz. right" +} +text { + object { + x=1032 + y=89 + width=100 + height=20 + } + "basic attribute" { + clr=14 } + textix="Enum order" + align="horiz. right" } -"text update" { +text { object { - x=819 - y=115 - width=61 - height=18 + x=1022 + y=64 + width=110 + height=20 } - monitor { - chan="$(P)LonginInt32.SEVR" - clr=54 - bclr=2 + "basic attribute" { + clr=14 } - clrmod="alarm" - align="horiz. centered" - limits { + textix="Update rate" + align="horiz. right" +} +menu { + object { + x=1137 + y=89 + width=130 + height=20 + } + control { + chan="$(P)EnumOrder" + clr=14 + bclr=51 + } +} +composite { + object { + x=1137 + y=64 + width=216 + height=20 + } + "composite name"="" + children { + menu { + object { + x=1137 + y=64 + width=130 + height=20 + } + control { + chan="$(P)DoUpdate.SCAN" + clr=14 + bclr=51 + } + } + "message button" { + object { + x=1272 + y=64 + width=81 + height=20 + } + control { + chan="$(P)DoUpdate" + clr=14 + bclr=51 + } + label="Update" + press_msg="1" + } } } text { object { - x=625 + x=1002 y=114 - width=60 + width=130 height=20 } "basic attribute" { clr=14 } - textix="longin" + textix="Status return" align="horiz. right" } menu { object { - x=886 + x=1137 y=114 + width=130 + height=20 + } + control { + chan="$(P)StatusReturn" + clr=14 + bclr=51 + } +} +text { + object { + x=1022 + y=189 + width=110 + height=20 + } + "basic attribute" { + clr=14 + } + textix="asyn record" + align="horiz. right" +} +"related display" { + object { + x=1137 + y=189 width=100 height=20 } + display[0] { + label="asyn record" + name="asynRecord.adl" + args="P=testErrors:,R=asyn1" + } + clr=14 + bclr=51 + label="asyn record" +} +text { + object { + x=1012 + y=139 + width=120 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Alarm status" + align="horiz. right" +} +menu { + object { + x=1137 + y=139 + width=130 + height=20 + } control { - chan="$(P)LonginInt32.SCAN" + chan="$(P)AlarmStatus" + clr=14 + bclr=51 + } +} +text { + object { + x=992 + y=164 + width=140 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Alarm severity" + align="horiz. right" +} +menu { + object { + x=1137 + y=164 + width=130 + height=20 + } + control { + chan="$(P)AlarmSeverity" clr=14 bclr=51 } } +text { + object { + x=46 + y=220 + width=80 + height=20 + } + "basic attribute" { + clr=14 + } + textix="int64out" + align="horiz. right" +} +"text update" { + object { + x=217 + y=220 + width=61 + height=18 + } + monitor { + chan="$(P)Int64Out.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=282 + y=220 + width=61 + height=18 + } + monitor { + chan="$(P)Int64Out.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} "text update" { object { x=690 - y=65 + y=221 width=61 height=18 } monitor { - chan="$(P)AiInt32" + chan="$(P)Int64In" clr=54 bclr=2 } @@ -1083,12 +1203,12 @@ menu { "text update" { object { x=754 - y=65 + y=221 width=61 height=18 } monitor { - chan="$(P)AiInt32.STAT" + chan="$(P)Int64In.STAT" clr=54 bclr=2 } @@ -1100,12 +1220,12 @@ menu { "text update" { object { x=819 - y=65 + y=221 width=61 height=18 } monitor { - chan="$(P)AiInt32.SEVR" + chan="$(P)Int64In.SEVR" clr=54 bclr=2 } @@ -1116,51 +1236,39 @@ menu { } text { object { - x=665 - y=64 - width=20 + x=615 + y=220 + width=70 height=20 } "basic attribute" { clr=14 } - textix="ai" + textix="int64in" align="horiz. right" } menu { object { x=886 - y=64 + y=220 width=100 height=20 } control { - chan="$(P)AiInt32.SCAN" + chan="$(P)Int64In.SCAN" clr=14 bclr=51 } } -text { - object { - x=132 - y=39 - width=210 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Without asyn:READBACK" -} "text entry" { object { x=131 - y=438 + y=220 width=80 height=20 } control { - chan="$(P)SoOctet" + chan="$(P)Int64Out" clr=14 bclr=2 } @@ -1169,218 +1277,1598 @@ text { } "text entry" { object { - x=131 - y=463 + x=348 + y=220 width=80 height=20 } control { - chan="$(P)WfOutOctet" + chan="$(P)Int64OutRB" clr=14 bclr=2 } - format="string" limits { } } -"text entry" { +"text update" { object { - x=131 - y=354 - width=80 - height=20 + x=434 + y=221 + width=61 + height=18 } - control { - chan="$(P)AoFloat64" - clr=14 + monitor { + chan="$(P)Int64OutRB.STAT" + clr=54 bclr=2 } + clrmod="alarm" + align="horiz. centered" limits { } } -menu { +"text update" { object { - x=131 - y=270 - width=80 + x=499 + y=221 + width=61 + height=18 + } + monitor { + chan="$(P)Int64OutRB.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +text { + object { + x=590 + y=194 + width=90 height=20 } - control { - chan="$(P)MbboUInt32D" + "basic attribute" { + clr=54 + } + textix="asynInt64" + align="horiz. centered" +} +text { + object { + x=35 + y=494 + width=90 + height=20 + } + "basic attribute" { clr=14 - bclr=51 } + textix="stringout" + align="horiz. right" } -menu { +text { object { - x=131 - y=245 - width=80 + x=5 + y=519 + width=120 height=20 } - control { - chan="$(P)BoUInt32D" + "basic attribute" { clr=14 - bclr=51 } + textix="waveform out" + align="horiz. right" } -"text entry" { +text { object { - x=131 - y=220 - width=80 + x=106 + y=410 + width=20 height=20 } - control { - chan="$(P)LongoutUInt32D" + "basic attribute" { clr=14 - bclr=2 } - format="hexadecimal" - limits { + textix="ao" + align="horiz. right" +} +text { + object { + x=26 + y=351 + width=100 + height=20 + } + "basic attribute" { + clr=14 } + textix="mbboDirect" + align="horiz. right" } -"text entry" { +text { object { - x=131 - y=295 - width=80 + x=86 + y=326 + width=40 height=20 } - control { - chan="$(P)MbboDUInt32D" + "basic attribute" { + clr=14 + } + textix="mbbo" + align="horiz. right" +} +text { + object { + x=106 + y=301 + width=20 + height=20 + } + "basic attribute" { clr=14 + } + textix="bo" + align="horiz. right" +} +"text update" { + object { + x=689 + y=495 + width=61 + height=18 + } + monitor { + chan="$(P)SiOctet" + clr=54 bclr=2 } - format="hexadecimal" + align="horiz. centered" limits { } } -menu { +"text update" { object { - x=131 - y=164 + x=753 + y=495 + width=61 + height=18 + } + monitor { + chan="$(P)SiOctet.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=818 + y=495 + width=61 + height=18 + } + monitor { + chan="$(P)SiOctet.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +text { + object { + x=604 + y=494 width=80 height=20 } - control { - chan="$(P)MbboInt32" + "basic attribute" { clr=14 - bclr=51 } + textix="stringin" + align="horiz. right" } menu { object { - x=131 - y=139 - width=80 + x=885 + y=494 + width=100 height=20 } control { - chan="$(P)BoInt32" + chan="$(P)SiOctet.SCAN" clr=14 bclr=51 } } -"text entry" { +"text update" { object { - x=131 - y=114 - width=80 - height=20 + x=689 + y=520 + width=61 + height=18 } - control { - chan="$(P)LongoutInt32" - clr=14 + monitor { + chan="$(P)WfInOctet" + clr=54 bclr=2 } + align="horiz. centered" + format="string" limits { } } -"text entry" { +"text update" { object { - x=131 - y=64 - width=80 - height=20 + x=753 + y=520 + width=61 + height=18 } - control { - chan="$(P)AoInt32" - clr=14 + monitor { + chan="$(P)WfInOctet.STAT" + clr=54 bclr=2 } + clrmod="alarm" + align="horiz. centered" limits { } } -composite { +"text update" { object { - x=216 - y=64 - width=127 - height=417 + x=818 + y=520 + width=61 + height=18 } - "composite name"="" - children { - "text update" { - object { - x=216 - y=438 - width=61 - height=18 - } - monitor { - chan="$(P)SoOctet.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=281 - y=438 - width=61 - height=18 - } - monitor { - chan="$(P)SoOctet.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=216 - y=463 - width=61 - height=18 - } - monitor { - chan="$(P)WfOutOctet.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } + monitor { + chan="$(P)WfInOctet.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +text { + object { + x=574 + y=519 + width=110 + height=20 + } + "basic attribute" { + clr=14 + } + textix="waveform in" + align="horiz. right" +} +menu { + object { + x=885 + y=519 + width=100 + height=20 + } + control { + chan="$(P)WfInOctet.SCAN" + clr=14 + bclr=51 + } +} +text { + object { + x=590 + y=465 + width=90 + height=20 + } + "basic attribute" { + clr=54 + } + textix="asynOctet" +} +text { + object { + x=580 + y=381 + width=110 + height=20 + } + "basic attribute" { + clr=54 + } + textix="asynFloat64" +} +"text update" { + object { + x=690 + y=436 + width=61 + height=18 + } + monitor { + chan="$(P)AiFloat64Average" + clr=54 + bclr=2 + } + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=754 + y=436 + width=61 + height=18 + } + monitor { + chan="$(P)AiFloat64Average.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=819 + y=436 + width=61 + height=18 + } + monitor { + chan="$(P)AiFloat64Average.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +text { + object { + x=595 + y=435 + width=90 + height=20 + } + "basic attribute" { + clr=14 + } + textix="aiAverage" + align="horiz. right" +} +menu { + object { + x=886 + y=435 + width=100 + height=20 + } + control { + chan="$(P)AiFloat64Average.SCAN" + clr=14 + bclr=51 + } +} +"text update" { + object { + x=690 + y=411 + width=61 + height=18 + } + monitor { + chan="$(P)AiFloat64" + clr=54 + bclr=2 + } + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=754 + y=411 + width=61 + height=18 + } + monitor { + chan="$(P)AiFloat64.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=819 + y=411 + width=61 + height=18 + } + monitor { + chan="$(P)AiFloat64.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +text { + object { + x=665 + y=410 + width=20 + height=20 + } + "basic attribute" { + clr=14 + } + textix="ai" + align="horiz. right" +} +menu { + object { + x=886 + y=410 + width=100 + height=20 + } + control { + chan="$(P)AiFloat64.SCAN" + clr=14 + bclr=51 + } +} +"text update" { + object { + x=690 + y=327 + width=61 + height=18 + } + monitor { + chan="$(P)MbbiUInt32D" + clr=54 + bclr=2 + } + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=754 + y=327 + width=61 + height=18 + } + monitor { + chan="$(P)MbbiUInt32D.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=819 + y=327 + width=61 + height=18 + } + monitor { + chan="$(P)MbbiUInt32D.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +text { + object { + x=645 + y=326 + width=40 + height=20 + } + "basic attribute" { + clr=14 + } + textix="mbbi" + align="horiz. right" +} +menu { + object { + x=886 + y=326 + width=100 + height=20 + } + control { + chan="$(P)MbbiUInt32D.SCAN" + clr=14 + bclr=51 + } +} +"text update" { + object { + x=690 + y=302 + width=61 + height=18 + } + monitor { + chan="$(P)BiUInt32D" + clr=54 + bclr=2 + } + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=754 + y=302 + width=61 + height=18 + } + monitor { + chan="$(P)BiUInt32D.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=819 + y=302 + width=61 + height=18 + } + monitor { + chan="$(P)BiUInt32D.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +text { + object { + x=665 + y=301 + width=20 + height=20 + } + "basic attribute" { + clr=14 + } + textix="bi" + align="horiz. right" +} +menu { + object { + x=886 + y=301 + width=100 + height=20 + } + control { + chan="$(P)BiUInt32D.SCAN" + clr=14 + bclr=51 + } +} +"text update" { + object { + x=690 + y=352 + width=61 + height=18 + } + monitor { + chan="$(P)MbbiDUInt32D" + clr=54 + bclr=2 + } + align="horiz. centered" + format="hexadecimal" + limits { + } +} +"text update" { + object { + x=754 + y=352 + width=61 + height=18 + } + monitor { + chan="$(P)MbbiDUInt32D.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=819 + y=352 + width=61 + height=18 + } + monitor { + chan="$(P)MbbiDUInt32D.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +text { + object { + x=585 + y=351 + width=100 + height=20 + } + "basic attribute" { + clr=14 + } + textix="mbbiDirect" + align="horiz. right" +} +menu { + object { + x=886 + y=351 + width=100 + height=20 + } + control { + chan="$(P)MbbiDUInt32D.SCAN" + clr=14 + bclr=51 + } +} +"text entry" { + object { + x=131 + y=494 + width=80 + height=20 + } + control { + chan="$(P)SoOctet" + clr=14 + bclr=2 + } + limits { + } +} +"text entry" { + object { + x=131 + y=519 + width=80 + height=20 + } + control { + chan="$(P)WfOutOctet" + clr=14 + bclr=2 + } + format="string" + limits { + } +} +"text entry" { + object { + x=131 + y=410 + width=80 + height=20 + } + control { + chan="$(P)AoFloat64" + clr=14 + bclr=2 + } + limits { + } +} +menu { + object { + x=131 + y=326 + width=80 + height=20 + } + control { + chan="$(P)MbboUInt32D" + clr=14 + bclr=51 + } +} +menu { + object { + x=131 + y=301 + width=80 + height=20 + } + control { + chan="$(P)BoUInt32D" + clr=14 + bclr=51 + } +} +"text entry" { + object { + x=131 + y=351 + width=80 + height=20 + } + control { + chan="$(P)MbboDUInt32D" + clr=14 + bclr=2 + } + format="hexadecimal" + limits { + } +} +"text update" { + object { + x=216 + y=494 + width=61 + height=18 + } + monitor { + chan="$(P)SoOctet.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=281 + y=494 + width=61 + height=18 + } + monitor { + chan="$(P)SoOctet.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=216 + y=519 + width=61 + height=18 + } + monitor { + chan="$(P)WfOutOctet.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=281 + y=519 + width=61 + height=18 + } + monitor { + chan="$(P)WfOutOctet.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=217 + y=410 + width=61 + height=18 + } + monitor { + chan="$(P)AoFloat64.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=282 + y=410 + width=61 + height=18 + } + monitor { + chan="$(P)AoFloat64.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=217 + y=326 + width=61 + height=18 + } + monitor { + chan="$(P)MbboUInt32D.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=282 + y=326 + width=61 + height=18 + } + monitor { + chan="$(P)MbboUInt32D.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=217 + y=301 + width=61 + height=18 + } + monitor { + chan="$(P)BoUInt32D.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=282 + y=301 + width=61 + height=18 + } + monitor { + chan="$(P)BoUInt32D.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=217 + y=351 + width=61 + height=18 + } + monitor { + chan="$(P)MbboDUInt32D.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=282 + y=351 + width=61 + height=18 + } + monitor { + chan="$(P)MbboDUInt32D.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text entry" { + object { + x=348 + y=494 + width=80 + height=20 + } + control { + chan="$(P)SoOctetRB" + clr=14 + bclr=2 + } + limits { + } +} +"text entry" { + object { + x=348 + y=519 + width=80 + height=20 + } + control { + chan="$(P)WfOutOctetRB" + clr=14 + bclr=2 + } + format="string" + limits { + } +} +"text entry" { + object { + x=348 + y=410 + width=80 + height=20 + } + control { + chan="$(P)AoFloat64RB" + clr=14 + bclr=2 + } + limits { + } +} +menu { + object { + x=348 + y=326 + width=80 + height=20 + } + control { + chan="$(P)MbboUInt32DRB" + clr=14 + bclr=51 + } +} +menu { + object { + x=348 + y=301 + width=80 + height=20 + } + control { + chan="$(P)BoUInt32DRB" + clr=14 + bclr=51 + } +} +"text entry" { + object { + x=348 + y=351 + width=80 + height=20 + } + control { + chan="$(P)MbboDUInt32DRB" + clr=14 + bclr=2 + } + format="hexadecimal" + limits { + } +} +"text update" { + object { + x=433 + y=495 + width=61 + height=18 + } + monitor { + chan="$(P)SoOctetRB.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=498 + y=495 + width=61 + height=18 + } + monitor { + chan="$(P)SoOctetRB.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=433 + y=520 + width=61 + height=18 + } + monitor { + chan="$(P)WfOutOctetRB.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=498 + y=520 + width=61 + height=18 + } + monitor { + chan="$(P)WfOutOctetRB.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=434 + y=411 + width=61 + height=18 + } + monitor { + chan="$(P)AoFloat64RB.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=499 + y=411 + width=61 + height=18 + } + monitor { + chan="$(P)AoFloat64RB.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=434 + y=327 + width=61 + height=18 + } + monitor { + chan="$(P)MbboUInt32DRB.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=499 + y=327 + width=61 + height=18 + } + monitor { + chan="$(P)MbboUInt32DRB.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=434 + y=302 + width=61 + height=18 + } + monitor { + chan="$(P)BoUInt32DRB.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=499 + y=302 + width=61 + height=18 + } + monitor { + chan="$(P)BoUInt32DRB.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=434 + y=352 + width=61 + height=18 + } + monitor { + chan="$(P)MbboDUInt32DRB.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +"text update" { + object { + x=499 + y=352 + width=61 + height=18 + } + monitor { + chan="$(P)MbboDUInt32DRB.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } +} +composite { + object { + x=16 + y=583 + width=212 + height=150 + } + "composite name"="" + children { + "cartesian plot" { + object { + x=22 + y=608 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfInt8In" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=102 + y=583 + width=40 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Int8" + align="horiz. centered" + } + "text update" { + object { + x=16 + y=714 + width=61 + height=18 + } + monitor { + chan="$(P)WfInt8In.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } + } + "text update" { + object { + x=82 + y=714 + width=61 + height=18 + } + monitor { + chan="$(P)WfInt8In.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } + } + menu { + object { + x=148 + y=713 + width=80 + height=20 + } + control { + chan="$(P)WfInt8In.SCAN" + clr=14 + bclr=51 + } + } + } +} +composite { + object { + x=233 + y=583 + width=212 + height=150 + } + "composite name"="" + children { + "cartesian plot" { + object { + x=239 + y=608 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfFloat32In" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=304 + y=583 + width=70 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Float32" + align="horiz. centered" + } + "text update" { + object { + x=233 + y=714 + width=61 + height=18 + } + monitor { + chan="$(P)WfFloat32In.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } + } + "text update" { + object { + x=299 + y=714 + width=61 + height=18 + } + monitor { + chan="$(P)WfFloat32In.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } + } + menu { + object { + x=365 + y=713 + width=80 + height=20 + } + control { + chan="$(P)WfFloat32In.SCAN" + clr=14 + bclr=51 + } + } + } +} +composite { + object { + x=16 + y=738 + width=212 + height=150 + } + "composite name"="" + children { + "cartesian plot" { + object { + x=22 + y=763 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfInt16In" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=97 + y=738 + width=50 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Int16" + align="horiz. centered" + } + "text update" { + object { + x=16 + y=869 + width=61 + height=18 + } + monitor { + chan="$(P)WfInt16In.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } + } + "text update" { + object { + x=82 + y=869 + width=61 + height=18 + } + monitor { + chan="$(P)WfInt16In.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } + } + menu { + object { + x=148 + y=868 + width=80 + height=20 + } + control { + chan="$(P)WfInt16In.SCAN" + clr=14 + bclr=51 + } + } + } +} +composite { + object { + x=233 + y=738 + width=212 + height=150 + } + "composite name"="" + children { + "cartesian plot" { + object { + x=239 + y=763 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfFloat64In" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=304 + y=738 + width=70 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Float64" + align="horiz. centered" + } "text update" { object { - x=281 - y=463 + x=233 + y=869 width=61 height=18 } monitor { - chan="$(P)WfOutOctet.SEVR" + chan="$(P)WfFloat64In.STAT" clr=54 bclr=2 } @@ -1391,13 +2879,13 @@ composite { } "text update" { object { - x=217 - y=354 + x=299 + y=869 width=61 height=18 } monitor { - chan="$(P)AoFloat64.STAT" + chan="$(P)WfFloat64In.SEVR" clr=54 bclr=2 } @@ -1406,15 +2894,39 @@ composite { limits { } } + menu { + object { + x=365 + y=868 + width=80 + height=20 + } + control { + chan="$(P)WfFloat64In.SCAN" + clr=14 + bclr=51 + } + } + } +} +composite { + object { + x=16 + y=893 + width=212 + height=150 + } + "composite name"="" + children { "text update" { object { - x=282 - y=354 + x=16 + y=1024 width=61 height=18 } monitor { - chan="$(P)AoFloat64.SEVR" + chan="$(P)WfInt32In.STAT" clr=54 bclr=2 } @@ -1425,13 +2937,13 @@ composite { } "text update" { object { - x=217 - y=270 + x=82 + y=1024 width=61 height=18 } monitor { - chan="$(P)MbboUInt32D.STAT" + chan="$(P)WfInt32In.SEVR" clr=54 bclr=2 } @@ -1440,32 +2952,112 @@ composite { limits { } } - "text update" { + menu { object { - x=282 - y=270 - width=61 - height=18 + x=148 + y=1023 + width=80 + height=20 } - monitor { - chan="$(P)MbboUInt32D.SEVR" - clr=54 - bclr=2 + control { + chan="$(P)WfInt32In.SCAN" + clr=14 + bclr=51 } - clrmod="alarm" + } + "cartesian plot" { + object { + x=22 + y=918 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfInt32In" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=97 + y=893 + width=50 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Int32" align="horiz. centered" - limits { + } + } +} +text { + object { + x=130 + y=563 + width=200 + height=20 + } + "basic attribute" { + clr=54 + } + textix="asynXXXArray (input)" + align="horiz. centered" +} +composite { + object { + x=461 + y=583 + width=212 + height=150 + } + "composite name"="" + children { + "cartesian plot" { + object { + x=467 + y=608 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfInt8Out" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=547 + y=583 + width=40 + height=20 + } + "basic attribute" { + clr=14 } + textix="Int8" + align="horiz. centered" } "text update" { object { - x=217 - y=245 + x=461 + y=714 width=61 height=18 } monitor { - chan="$(P)BoUInt32D.STAT" + chan="$(P)WfInt8Out.STAT" clr=54 bclr=2 } @@ -1476,13 +3068,13 @@ composite { } "text update" { object { - x=282 - y=245 + x=527 + y=714 width=61 height=18 } monitor { - chan="$(P)BoUInt32D.SEVR" + chan="$(P)WfInt8Out.SEVR" clr=54 bclr=2 } @@ -1491,15 +3083,69 @@ composite { limits { } } + menu { + object { + x=593 + y=713 + width=80 + height=20 + } + control { + chan="$(P)WfInt8Out.SCAN" + clr=14 + bclr=51 + } + } + } +} +composite { + object { + x=678 + y=583 + width=212 + height=150 + } + "composite name"="" + children { + "cartesian plot" { + object { + x=684 + y=608 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfFloat32Out" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=749 + y=583 + width=70 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Float32" + align="horiz. centered" + } "text update" { object { - x=217 - y=220 + x=678 + y=714 width=61 height=18 } monitor { - chan="$(P)LongoutUInt32D.STAT" + chan="$(P)WfFloat32Out.STAT" clr=54 bclr=2 } @@ -1510,13 +3156,13 @@ composite { } "text update" { object { - x=282 - y=220 + x=744 + y=714 width=61 height=18 } monitor { - chan="$(P)LongoutUInt32D.SEVR" + chan="$(P)WfFloat32Out.SEVR" clr=54 bclr=2 } @@ -1525,15 +3171,69 @@ composite { limits { } } + menu { + object { + x=810 + y=713 + width=80 + height=20 + } + control { + chan="$(P)WfFloat32Out.SCAN" + clr=14 + bclr=51 + } + } + } +} +composite { + object { + x=461 + y=738 + width=212 + height=150 + } + "composite name"="" + children { + "cartesian plot" { + object { + x=467 + y=763 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfInt16Out" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=542 + y=738 + width=50 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Int16" + align="horiz. centered" + } "text update" { object { - x=217 - y=295 + x=461 + y=869 width=61 height=18 } monitor { - chan="$(P)MbboDUInt32D.STAT" + chan="$(P)WfInt16Out.STAT" clr=54 bclr=2 } @@ -1544,13 +3244,13 @@ composite { } "text update" { object { - x=282 - y=295 + x=527 + y=869 width=61 height=18 } monitor { - chan="$(P)MbboDUInt32D.SEVR" + chan="$(P)WfInt16Out.SEVR" clr=54 bclr=2 } @@ -1559,15 +3259,69 @@ composite { limits { } } + menu { + object { + x=593 + y=868 + width=80 + height=20 + } + control { + chan="$(P)WfInt16Out.SCAN" + clr=14 + bclr=51 + } + } + } +} +composite { + object { + x=678 + y=738 + width=212 + height=150 + } + "composite name"="" + children { + "cartesian plot" { + object { + x=684 + y=763 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfFloat64Out" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=749 + y=738 + width=70 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Float64" + align="horiz. centered" + } "text update" { object { - x=217 - y=164 + x=678 + y=869 width=61 height=18 } monitor { - chan="$(P)MbboInt32.STAT" + chan="$(P)WfFloat64Out.STAT" clr=54 bclr=2 } @@ -1578,13 +3332,13 @@ composite { } "text update" { object { - x=282 - y=164 + x=744 + y=869 width=61 height=18 } monitor { - chan="$(P)MbboInt32.SEVR" + chan="$(P)WfFloat64Out.SEVR" clr=54 bclr=2 } @@ -1593,15 +3347,39 @@ composite { limits { } } + menu { + object { + x=810 + y=868 + width=80 + height=20 + } + control { + chan="$(P)WfFloat64Out.SCAN" + clr=14 + bclr=51 + } + } + } +} +composite { + object { + x=461 + y=893 + width=212 + height=150 + } + "composite name"="" + children { "text update" { object { - x=217 - y=139 + x=461 + y=1024 width=61 height=18 } monitor { - chan="$(P)BoInt32.STAT" + chan="$(P)WfInt32Out.STAT" clr=54 bclr=2 } @@ -1612,13 +3390,13 @@ composite { } "text update" { object { - x=282 - y=139 + x=527 + y=1024 width=61 height=18 } monitor { - chan="$(P)BoInt32.SEVR" + chan="$(P)WfInt32Out.SEVR" clr=54 bclr=2 } @@ -1627,32 +3405,112 @@ composite { limits { } } - "text update" { + menu { object { - x=217 - y=114 - width=61 - height=18 + x=593 + y=1023 + width=80 + height=20 } - monitor { - chan="$(P)LongoutInt32.STAT" - clr=54 - bclr=2 + control { + chan="$(P)WfInt32Out.SCAN" + clr=14 + bclr=51 + } + } + "cartesian plot" { + object { + x=467 + y=918 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfInt32Out" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=542 + y=893 + width=50 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Int32" + align="horiz. centered" + } + } +} +text { + object { + x=460 + y=563 + width=430 + height=20 + } + "basic attribute" { + clr=54 + } + textix="asynXXXArray (output without asyn:READBACK)" + align="horiz. centered" +} +composite { + object { + x=906 + y=583 + width=212 + height=150 + } + "composite name"="" + children { + "cartesian plot" { + object { + x=912 + y=608 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfInt8OutRB" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=992 + y=583 + width=40 + height=20 + } + "basic attribute" { + clr=14 } - clrmod="alarm" + textix="Int8" align="horiz. centered" - limits { - } } "text update" { object { - x=282 - y=114 + x=906 + y=714 width=61 height=18 } monitor { - chan="$(P)LongoutInt32.SEVR" + chan="$(P)WfInt8OutRB.STAT" clr=54 bclr=2 } @@ -1663,13 +3521,13 @@ composite { } "text update" { object { - x=217 - y=64 + x=972 + y=714 width=61 height=18 } monitor { - chan="$(P)AoInt32.STAT" + chan="$(P)WfInt8OutRB.SEVR" clr=54 bclr=2 } @@ -1678,359 +3536,408 @@ composite { limits { } } - "text update" { + menu { object { - x=282 - y=64 - width=61 - height=18 - } - monitor { - chan="$(P)AoInt32.SEVR" - clr=54 - bclr=2 + x=1038 + y=713 + width=80 + height=20 } - clrmod="alarm" - align="horiz. centered" - limits { + control { + chan="$(P)WfInt8OutRB.SCAN" + clr=14 + bclr=51 } } } } -text { - object { - x=364 - y=39 - width=180 - height=20 - } - "basic attribute" { - clr=14 - } - textix="With asyn:READBACK" -} -"text entry" { - object { - x=348 - y=438 - width=80 - height=20 - } - control { - chan="$(P)SoOctetRB" - clr=14 - bclr=2 - } - limits { - } -} -"text entry" { - object { - x=348 - y=463 - width=80 - height=20 - } - control { - chan="$(P)WfOutOctetRB" - clr=14 - bclr=2 - } - format="string" - limits { - } -} -"text entry" { - object { - x=348 - y=354 - width=80 - height=20 - } - control { - chan="$(P)AoFloat64RB" - clr=14 - bclr=2 - } - limits { - } -} -menu { - object { - x=348 - y=270 - width=80 - height=20 - } - control { - chan="$(P)MbboUInt32DRB" - clr=14 - bclr=51 - } -} -menu { - object { - x=348 - y=245 - width=80 - height=20 - } - control { - chan="$(P)BoUInt32DRB" - clr=14 - bclr=51 - } -} -"text entry" { - object { - x=348 - y=220 - width=80 - height=20 - } - control { - chan="$(P)LongoutUInt32DRB" - clr=14 - bclr=2 - } - format="hexadecimal" - limits { - } -} -"text entry" { - object { - x=348 - y=295 - width=80 - height=20 - } - control { - chan="$(P)MbboDUInt32DRB" - clr=14 - bclr=2 - } - format="hexadecimal" - limits { - } -} -menu { - object { - x=348 - y=164 - width=80 - height=20 - } - control { - chan="$(P)MbboInt32RB" - clr=14 - bclr=51 - } -} -menu { - object { - x=348 - y=139 - width=80 - height=20 - } - control { - chan="$(P)BoInt32RB" - clr=14 - bclr=51 - } -} -"text entry" { - object { - x=348 - y=114 - width=80 - height=20 - } - control { - chan="$(P)LongoutInt32RB" - clr=14 - bclr=2 - } - limits { - } -} -"text entry" { - object { - x=348 - y=64 - width=80 - height=20 - } - control { - chan="$(P)AoInt32RB" - clr=14 - bclr=2 - } - limits { - } -} -"text update" { - object { - x=433 - y=439 - width=61 - height=18 - } - monitor { - chan="$(P)SoOctetRB.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } -} -"text update" { - object { - x=498 - y=439 - width=61 - height=18 - } - monitor { - chan="$(P)SoOctetRB.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } -} -"text update" { - object { - x=433 - y=464 - width=61 - height=18 - } - monitor { - chan="$(P)WfOutOctetRB.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } -} -"text update" { +composite { object { - x=498 - y=464 - width=61 - height=18 - } - monitor { - chan="$(P)WfOutOctetRB.SEVR" - clr=54 - bclr=2 + x=1123 + y=583 + width=212 + height=150 } - clrmod="alarm" - align="horiz. centered" - limits { + "composite name"="" + children { + "cartesian plot" { + object { + x=1129 + y=608 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfFloat32OutRB" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=1194 + y=583 + width=70 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Float32" + align="horiz. centered" + } + "text update" { + object { + x=1123 + y=714 + width=61 + height=18 + } + monitor { + chan="$(P)WfFloat32OutRB.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } + } + "text update" { + object { + x=1189 + y=714 + width=61 + height=18 + } + monitor { + chan="$(P)WfFloat32OutRB.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } + } + menu { + object { + x=1255 + y=713 + width=80 + height=20 + } + control { + chan="$(P)WfFloat32OutRB.SCAN" + clr=14 + bclr=51 + } + } } } -"text update" { +composite { object { - x=434 - y=355 - width=61 - height=18 - } - monitor { - chan="$(P)AoFloat64RB.STAT" - clr=54 - bclr=2 + x=906 + y=738 + width=212 + height=150 } - clrmod="alarm" - align="horiz. centered" - limits { + "composite name"="" + children { + "cartesian plot" { + object { + x=912 + y=763 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfInt16OutRB" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=987 + y=738 + width=50 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Int16" + align="horiz. centered" + } + "text update" { + object { + x=906 + y=869 + width=61 + height=18 + } + monitor { + chan="$(P)WfInt16OutRB.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } + } + "text update" { + object { + x=972 + y=869 + width=61 + height=18 + } + monitor { + chan="$(P)WfInt16OutRB.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } + } + menu { + object { + x=1038 + y=868 + width=80 + height=20 + } + control { + chan="$(P)WfInt16OutRB.SCAN" + clr=14 + bclr=51 + } + } } } -"text update" { +composite { object { - x=499 - y=355 - width=61 - height=18 - } - monitor { - chan="$(P)AoFloat64RB.SEVR" - clr=54 - bclr=2 + x=1123 + y=738 + width=212 + height=150 } - clrmod="alarm" - align="horiz. centered" - limits { + "composite name"="" + children { + "cartesian plot" { + object { + x=1129 + y=763 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfFloat64OutRB" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=1194 + y=738 + width=70 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Float64" + align="horiz. centered" + } + "text update" { + object { + x=1123 + y=869 + width=61 + height=18 + } + monitor { + chan="$(P)WfFloat64OutRB.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } + } + "text update" { + object { + x=1189 + y=869 + width=61 + height=18 + } + monitor { + chan="$(P)WfFloat64OutRB.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } + } + menu { + object { + x=1255 + y=868 + width=80 + height=20 + } + control { + chan="$(P)WfFloat64OutRB.SCAN" + clr=14 + bclr=51 + } + } } } -"text update" { +composite { object { - x=434 - y=271 - width=61 - height=18 - } - monitor { - chan="$(P)MbboUInt32DRB.STAT" - clr=54 - bclr=2 + x=906 + y=893 + width=212 + height=150 } - clrmod="alarm" - align="horiz. centered" - limits { + "composite name"="" + children { + "text update" { + object { + x=906 + y=1024 + width=61 + height=18 + } + monitor { + chan="$(P)WfInt32OutRB.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } + } + "text update" { + object { + x=972 + y=1024 + width=61 + height=18 + } + monitor { + chan="$(P)WfInt32OutRB.SEVR" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { + } + } + menu { + object { + x=1038 + y=1023 + width=80 + height=20 + } + control { + chan="$(P)WfInt32OutRB.SCAN" + clr=14 + bclr=51 + } + } + "cartesian plot" { + object { + x=912 + y=918 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfInt32OutRB" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=987 + y=893 + width=50 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Int32" + align="horiz. centered" + } } } -"text update" { +text { object { - x=499 - y=271 - width=61 - height=18 + x=920 + y=563 + width=400 + height=20 } - monitor { - chan="$(P)MbboUInt32DRB.SEVR" + "basic attribute" { clr=54 - bclr=2 } - clrmod="alarm" + textix="asynXXXArray (output with asyn:READBACK)" align="horiz. centered" - limits { - } } -"text update" { +text { object { - x=434 - y=246 - width=61 - height=18 - } - monitor { - chan="$(P)BoUInt32DRB.STAT" - clr=54 - bclr=2 + x=56 + y=276 + width=70 + height=20 } - clrmod="alarm" - align="horiz. centered" - limits { + "basic attribute" { + clr=14 } + textix="longout" + align="horiz. right" } "text update" { object { - x=499 - y=246 + x=217 + y=276 width=61 height=18 } monitor { - chan="$(P)BoUInt32DRB.SEVR" + chan="$(P)LongoutUInt32D.STAT" clr=54 bclr=2 } @@ -2041,13 +3948,13 @@ menu { } "text update" { object { - x=434 - y=221 + x=282 + y=276 width=61 height=18 } monitor { - chan="$(P)LongoutUInt32DRB.STAT" + chan="$(P)LongoutUInt32D.SEVR" clr=54 bclr=2 } @@ -2058,30 +3965,30 @@ menu { } "text update" { object { - x=499 - y=221 + x=690 + y=277 width=61 height=18 } monitor { - chan="$(P)LongoutUInt32DRB.SEVR" + chan="$(P)LonginUInt32D" clr=54 bclr=2 } - clrmod="alarm" align="horiz. centered" + format="hexadecimal" limits { } } "text update" { object { - x=434 - y=296 + x=754 + y=277 width=61 height=18 } monitor { - chan="$(P)MbboDUInt32DRB.STAT" + chan="$(P)LonginUInt32D.STAT" clr=54 bclr=2 } @@ -2092,13 +3999,13 @@ menu { } "text update" { object { - x=499 - y=296 + x=819 + y=277 width=61 height=18 } monitor { - chan="$(P)MbboDUInt32DRB.SEVR" + chan="$(P)LonginUInt32D.SEVR" clr=54 bclr=2 } @@ -2107,83 +4014,73 @@ menu { limits { } } -"text update" { +text { object { - x=434 - y=165 - width=61 - height=18 - } - monitor { - chan="$(P)MbboInt32RB.STAT" - clr=54 - bclr=2 + x=625 + y=276 + width=60 + height=20 } - clrmod="alarm" - align="horiz. centered" - limits { + "basic attribute" { + clr=14 } + textix="longin" + align="horiz. right" } -"text update" { +menu { object { - x=499 - y=165 - width=61 - height=18 - } - monitor { - chan="$(P)MbboInt32RB.SEVR" - clr=54 - bclr=2 + x=886 + y=276 + width=100 + height=20 } - clrmod="alarm" - align="horiz. centered" - limits { + control { + chan="$(P)LonginUInt32D.SCAN" + clr=14 + bclr=51 } } -"text update" { +"text entry" { object { - x=434 - y=140 - width=61 - height=18 + x=131 + y=276 + width=80 + height=20 } - monitor { - chan="$(P)BoInt32RB.STAT" - clr=54 + control { + chan="$(P)LongoutUInt32D" + clr=14 bclr=2 } - clrmod="alarm" - align="horiz. centered" + format="hexadecimal" limits { } } -"text update" { +"text entry" { object { - x=499 - y=140 - width=61 - height=18 + x=348 + y=276 + width=80 + height=20 } - monitor { - chan="$(P)BoInt32RB.SEVR" - clr=54 + control { + chan="$(P)LongoutUInt32DRB" + clr=14 bclr=2 } - clrmod="alarm" - align="horiz. centered" + format="hexadecimal" limits { } } "text update" { object { x=434 - y=115 + y=277 width=61 height=18 } monitor { - chan="$(P)LongoutInt32RB.STAT" + chan="$(P)LongoutUInt32DRB.STAT" clr=54 bclr=2 } @@ -2195,29 +4092,12 @@ menu { "text update" { object { x=499 - y=115 - width=61 - height=18 - } - monitor { - chan="$(P)LongoutInt32RB.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } -} -"text update" { - object { - x=434 - y=65 + y=277 width=61 height=18 } monitor { - chan="$(P)AoInt32RB.STAT" + chan="$(P)LongoutUInt32DRB.SEVR" clr=54 bclr=2 } @@ -2226,1784 +4106,280 @@ menu { limits { } } -"text update" { +text { object { - x=499 - y=65 - width=61 - height=18 + x=550 + y=250 + width=170 + height=20 } - monitor { - chan="$(P)AoInt32RB.SEVR" + "basic attribute" { clr=54 - bclr=2 } - clrmod="alarm" + textix="asynUInt32Digital" align="horiz. centered" - limits { - } } composite { object { - x=5 - y=64 - width=121 - height=419 + x=1123 + y=893 + width=212 + height=150 } "composite name"="" children { - text { - object { - x=35 - y=438 - width=90 - height=20 - } - "basic attribute" { - clr=14 - } - textix="stringout" - align="horiz. right" - } - text { - object { - x=5 - y=463 - width=120 - height=20 - } - "basic attribute" { - clr=14 - } - textix="waveform out" - align="horiz. right" - } - text { - object { - x=106 - y=354 - width=20 - height=20 - } - "basic attribute" { - clr=14 - } - textix="ao" - align="horiz. right" - } - text { + "text update" { object { - x=26 - y=295 - width=100 - height=20 - } - "basic attribute" { - clr=14 + x=1123 + y=1024 + width=61 + height=18 } - textix="mbboDirect" - align="horiz. right" - } - text { - object { - x=86 - y=270 - width=40 - height=20 + monitor { + chan="$(P)WfInt64OutRB.STAT" + clr=54 + bclr=2 } - "basic attribute" { - clr=14 + clrmod="alarm" + align="horiz. centered" + limits { } - textix="mbbo" - align="horiz. right" } - text { + "text update" { object { - x=106 - y=245 - width=20 - height=20 - } - "basic attribute" { - clr=14 + x=1189 + y=1024 + width=61 + height=18 } - textix="bo" - align="horiz. right" - } - text { - object { - x=56 - y=220 - width=70 - height=20 + monitor { + chan="$(P)WfInt64OutRB.SEVR" + clr=54 + bclr=2 } - "basic attribute" { - clr=14 + clrmod="alarm" + align="horiz. centered" + limits { } - textix="longout" - align="horiz. right" } - text { + menu { object { - x=86 - y=164 - width=40 + x=1255 + y=1023 + width=80 height=20 } - "basic attribute" { + control { + chan="$(P)WfInt64OutRB.SCAN" clr=14 + bclr=51 } - textix="mbbo" - align="horiz. right" } - text { + "cartesian plot" { object { - x=106 - y=139 - width=20 - height=20 + x=1129 + y=918 + width=200 + height=100 } - "basic attribute" { + plotcom { clr=14 + bclr=4 } - textix="bo" - align="horiz. right" - } - text { - object { - x=56 - y=114 - width=70 - height=20 - } - "basic attribute" { - clr=14 + trace[0] { + ydata="$(P)WfInt64OutRB" + data_clr=53 + yaxis=0 } - textix="longout" - align="horiz. right" } text { object { - x=106 - y=64 - width=20 + x=1204 + y=893 + width=50 height=20 } "basic attribute" { clr=14 } - textix="ao" - align="horiz. right" + textix="Int64" + align="horiz. centered" } } } composite { object { - x=16 - y=507 - width=429 - height=480 + x=233 + y=893 + width=212 + height=150 } "composite name"="" children { - composite { + "text update" { object { - x=16 - y=527 - width=429 - height=460 - } - "composite name"="" - children { - composite { - object { - x=16 - y=527 - width=212 - height=150 - } - "composite name"="" - children { - "cartesian plot" { - object { - x=22 - y=552 - width=200 - height=100 - } - plotcom { - clr=14 - bclr=4 - } - trace[0] { - ydata="$(P)WfInt8In" - data_clr=53 - yaxis=0 - } - } - text { - object { - x=102 - y=527 - width=40 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Int8" - align="horiz. centered" - } - "text update" { - object { - x=16 - y=658 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt8In.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=82 - y=658 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt8In.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - menu { - object { - x=148 - y=657 - width=80 - height=20 - } - control { - chan="$(P)WfInt8In.SCAN" - clr=14 - bclr=51 - } - } - } - } - composite { - object { - x=233 - y=527 - width=212 - height=150 - } - "composite name"="" - children { - "cartesian plot" { - object { - x=239 - y=552 - width=200 - height=100 - } - plotcom { - clr=14 - bclr=4 - } - trace[0] { - ydata="$(P)WfFloat32In" - data_clr=53 - yaxis=0 - } - } - text { - object { - x=304 - y=527 - width=70 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Float32" - align="horiz. centered" - } - "text update" { - object { - x=233 - y=658 - width=61 - height=18 - } - monitor { - chan="$(P)WfFloat32In.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=299 - y=658 - width=61 - height=18 - } - monitor { - chan="$(P)WfFloat32In.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - menu { - object { - x=365 - y=657 - width=80 - height=20 - } - control { - chan="$(P)WfFloat32In.SCAN" - clr=14 - bclr=51 - } - } - } - } - composite { - object { - x=16 - y=682 - width=212 - height=150 - } - "composite name"="" - children { - "cartesian plot" { - object { - x=22 - y=707 - width=200 - height=100 - } - plotcom { - clr=14 - bclr=4 - } - trace[0] { - ydata="$(P)WfInt16In" - data_clr=53 - yaxis=0 - } - } - text { - object { - x=97 - y=682 - width=50 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Int16" - align="horiz. centered" - } - "text update" { - object { - x=16 - y=813 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt16In.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=82 - y=813 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt16In.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - menu { - object { - x=148 - y=812 - width=80 - height=20 - } - control { - chan="$(P)WfInt16In.SCAN" - clr=14 - bclr=51 - } - } - } - } - composite { - object { - x=233 - y=682 - width=212 - height=150 - } - "composite name"="" - children { - "cartesian plot" { - object { - x=239 - y=707 - width=200 - height=100 - } - plotcom { - clr=14 - bclr=4 - } - trace[0] { - ydata="$(P)WfFloat64In" - data_clr=53 - yaxis=0 - } - } - text { - object { - x=304 - y=682 - width=70 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Float64" - align="horiz. centered" - } - "text update" { - object { - x=233 - y=813 - width=61 - height=18 - } - monitor { - chan="$(P)WfFloat64In.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=299 - y=813 - width=61 - height=18 - } - monitor { - chan="$(P)WfFloat64In.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - menu { - object { - x=365 - y=812 - width=80 - height=20 - } - control { - chan="$(P)WfFloat64In.SCAN" - clr=14 - bclr=51 - } - } - } - } - composite { - object { - x=16 - y=837 - width=212 - height=150 - } - "composite name"="" - children { - "text update" { - object { - x=16 - y=968 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt32In.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=82 - y=968 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt32In.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - menu { - object { - x=148 - y=967 - width=80 - height=20 - } - control { - chan="$(P)WfInt32In.SCAN" - clr=14 - bclr=51 - } - } - "cartesian plot" { - object { - x=22 - y=862 - width=200 - height=100 - } - plotcom { - clr=14 - bclr=4 - } - trace[0] { - ydata="$(P)WfInt32In" - data_clr=53 - yaxis=0 - } - } - text { - object { - x=97 - y=837 - width=50 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Int32" - align="horiz. centered" - } - } - } + x=233 + y=1024 + width=61 + height=18 + } + monitor { + chan="$(P)WfInt64In.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { } } - text { + "text update" { object { - x=130 - y=507 - width=200 - height=20 + x=299 + y=1024 + width=61 + height=18 } - "basic attribute" { + monitor { + chan="$(P)WfInt64In.SEVR" clr=54 + bclr=2 } - textix="asynXXXArray (input)" + clrmod="alarm" align="horiz. centered" + limits { + } } - } -} -composite { - object { - x=460 - y=507 - width=430 - height=480 - } - "composite name"="" - children { - composite { + menu { object { - x=461 - y=527 - width=429 - height=460 - } - "composite name"="" - children { - composite { - object { - x=461 - y=527 - width=212 - height=150 - } - "composite name"="" - children { - "cartesian plot" { - object { - x=467 - y=552 - width=200 - height=100 - } - plotcom { - clr=14 - bclr=4 - } - trace[0] { - ydata="$(P)WfInt8Out" - data_clr=53 - yaxis=0 - } - } - text { - object { - x=547 - y=527 - width=40 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Int8" - align="horiz. centered" - } - "text update" { - object { - x=461 - y=658 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt8Out.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=527 - y=658 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt8Out.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - menu { - object { - x=593 - y=657 - width=80 - height=20 - } - control { - chan="$(P)WfInt8Out.SCAN" - clr=14 - bclr=51 - } - } - } - } - composite { - object { - x=678 - y=527 - width=212 - height=150 - } - "composite name"="" - children { - "cartesian plot" { - object { - x=684 - y=552 - width=200 - height=100 - } - plotcom { - clr=14 - bclr=4 - } - trace[0] { - ydata="$(P)WfFloat32Out" - data_clr=53 - yaxis=0 - } - } - text { - object { - x=749 - y=527 - width=70 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Float32" - align="horiz. centered" - } - "text update" { - object { - x=678 - y=658 - width=61 - height=18 - } - monitor { - chan="$(P)WfFloat32Out.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=744 - y=658 - width=61 - height=18 - } - monitor { - chan="$(P)WfFloat32Out.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - menu { - object { - x=810 - y=657 - width=80 - height=20 - } - control { - chan="$(P)WfFloat32Out.SCAN" - clr=14 - bclr=51 - } - } - } - } - composite { - object { - x=461 - y=682 - width=212 - height=150 - } - "composite name"="" - children { - "cartesian plot" { - object { - x=467 - y=707 - width=200 - height=100 - } - plotcom { - clr=14 - bclr=4 - } - trace[0] { - ydata="$(P)WfInt16Out" - data_clr=53 - yaxis=0 - } - } - text { - object { - x=542 - y=682 - width=50 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Int16" - align="horiz. centered" - } - "text update" { - object { - x=461 - y=813 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt16Out.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=527 - y=813 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt16Out.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - menu { - object { - x=593 - y=812 - width=80 - height=20 - } - control { - chan="$(P)WfInt16Out.SCAN" - clr=14 - bclr=51 - } - } - } - } - composite { - object { - x=678 - y=682 - width=212 - height=150 - } - "composite name"="" - children { - "cartesian plot" { - object { - x=684 - y=707 - width=200 - height=100 - } - plotcom { - clr=14 - bclr=4 - } - trace[0] { - ydata="$(P)WfFloat64Out" - data_clr=53 - yaxis=0 - } - } - text { - object { - x=749 - y=682 - width=70 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Float64" - align="horiz. centered" - } - "text update" { - object { - x=678 - y=813 - width=61 - height=18 - } - monitor { - chan="$(P)WfFloat64Out.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=744 - y=813 - width=61 - height=18 - } - monitor { - chan="$(P)WfFloat64Out.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - menu { - object { - x=810 - y=812 - width=80 - height=20 - } - control { - chan="$(P)WfFloat64Out.SCAN" - clr=14 - bclr=51 - } - } - } - } - composite { - object { - x=461 - y=837 - width=212 - height=150 - } - "composite name"="" - children { - "text update" { - object { - x=461 - y=968 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt32Out.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=527 - y=968 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt32Out.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - menu { - object { - x=593 - y=967 - width=80 - height=20 - } - control { - chan="$(P)WfInt32Out.SCAN" - clr=14 - bclr=51 - } - } - "cartesian plot" { - object { - x=467 - y=862 - width=200 - height=100 - } - plotcom { - clr=14 - bclr=4 - } - trace[0] { - ydata="$(P)WfInt32Out" - data_clr=53 - yaxis=0 - } - } - text { - object { - x=542 - y=837 - width=50 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Int32" - align="horiz. centered" - } - } - } + x=365 + y=1023 + width=80 + height=20 + } + control { + chan="$(P)WfInt64In.SCAN" + clr=14 + bclr=51 + } + } + "cartesian plot" { + object { + x=239 + y=918 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfInt64In" + data_clr=53 + yaxis=0 } } text { object { - x=460 - y=507 - width=430 + x=314 + y=893 + width=50 height=20 } "basic attribute" { - clr=54 + clr=14 } - textix="asynXXXArray (output without asyn:READBACK)" + textix="Int64" align="horiz. centered" } } } composite { object { - x=906 - y=507 - width=429 - height=480 + x=678 + y=893 + width=212 + height=150 } "composite name"="" children { - composite { + "text update" { object { - x=906 - y=527 - width=429 - height=460 - } - "composite name"="" - children { - composite { - object { - x=906 - y=527 - width=212 - height=150 - } - "composite name"="" - children { - "cartesian plot" { - object { - x=912 - y=552 - width=200 - height=100 - } - plotcom { - clr=14 - bclr=4 - } - trace[0] { - ydata="$(P)WfInt8OutRB" - data_clr=53 - yaxis=0 - } - } - text { - object { - x=992 - y=527 - width=40 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Int8" - align="horiz. centered" - } - "text update" { - object { - x=906 - y=658 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt8OutRB.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=972 - y=658 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt8OutRB.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - menu { - object { - x=1038 - y=657 - width=80 - height=20 - } - control { - chan="$(P)WfInt8OutRB.SCAN" - clr=14 - bclr=51 - } - } - } - } - composite { - object { - x=1123 - y=527 - width=212 - height=150 - } - "composite name"="" - children { - "cartesian plot" { - object { - x=1129 - y=552 - width=200 - height=100 - } - plotcom { - clr=14 - bclr=4 - } - trace[0] { - ydata="$(P)WfFloat32OutRB" - data_clr=53 - yaxis=0 - } - } - text { - object { - x=1194 - y=527 - width=70 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Float32" - align="horiz. centered" - } - "text update" { - object { - x=1123 - y=658 - width=61 - height=18 - } - monitor { - chan="$(P)WfFloat32OutRB.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=1189 - y=658 - width=61 - height=18 - } - monitor { - chan="$(P)WfFloat32OutRB.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - menu { - object { - x=1255 - y=657 - width=80 - height=20 - } - control { - chan="$(P)WfFloat32OutRB.SCAN" - clr=14 - bclr=51 - } - } - } - } - composite { - object { - x=906 - y=682 - width=212 - height=150 - } - "composite name"="" - children { - "cartesian plot" { - object { - x=912 - y=707 - width=200 - height=100 - } - plotcom { - clr=14 - bclr=4 - } - trace[0] { - ydata="$(P)WfInt16OutRB" - data_clr=53 - yaxis=0 - } - } - text { - object { - x=987 - y=682 - width=50 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Int16" - align="horiz. centered" - } - "text update" { - object { - x=906 - y=813 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt16OutRB.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=972 - y=813 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt16OutRB.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - menu { - object { - x=1038 - y=812 - width=80 - height=20 - } - control { - chan="$(P)WfInt16OutRB.SCAN" - clr=14 - bclr=51 - } - } - } - } - composite { - object { - x=1123 - y=682 - width=212 - height=150 - } - "composite name"="" - children { - "cartesian plot" { - object { - x=1129 - y=707 - width=200 - height=100 - } - plotcom { - clr=14 - bclr=4 - } - trace[0] { - ydata="$(P)WfFloat64OutRB" - data_clr=53 - yaxis=0 - } - } - text { - object { - x=1194 - y=682 - width=70 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Float64" - align="horiz. centered" - } - "text update" { - object { - x=1123 - y=813 - width=61 - height=18 - } - monitor { - chan="$(P)WfFloat64OutRB.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=1189 - y=813 - width=61 - height=18 - } - monitor { - chan="$(P)WfFloat64OutRB.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - menu { - object { - x=1255 - y=812 - width=80 - height=20 - } - control { - chan="$(P)WfFloat64OutRB.SCAN" - clr=14 - bclr=51 - } - } - } - } - composite { - object { - x=906 - y=837 - width=212 - height=150 - } - "composite name"="" - children { - "text update" { - object { - x=906 - y=968 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt32OutRB.STAT" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - "text update" { - object { - x=972 - y=968 - width=61 - height=18 - } - monitor { - chan="$(P)WfInt32OutRB.SEVR" - clr=54 - bclr=2 - } - clrmod="alarm" - align="horiz. centered" - limits { - } - } - menu { - object { - x=1038 - y=967 - width=80 - height=20 - } - control { - chan="$(P)WfInt32OutRB.SCAN" - clr=14 - bclr=51 - } - } - "cartesian plot" { - object { - x=912 - y=862 - width=200 - height=100 - } - plotcom { - clr=14 - bclr=4 - } - trace[0] { - ydata="$(P)WfInt32OutRB" - data_clr=53 - yaxis=0 - } - } - text { - object { - x=987 - y=837 - width=50 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Int32" - align="horiz. centered" - } - } - } + x=678 + y=1024 + width=61 + height=18 + } + monitor { + chan="$(P)WfInt64Out.STAT" + clr=54 + bclr=2 + } + clrmod="alarm" + align="horiz. centered" + limits { } } - text { + "text update" { object { - x=920 - y=507 - width=400 - height=20 + x=744 + y=1024 + width=61 + height=18 } - "basic attribute" { + monitor { + chan="$(P)WfInt64Out.SEVR" clr=54 + bclr=2 } - textix="asynXXXArray (output with asyn:READBACK)" + clrmod="alarm" align="horiz. centered" + limits { + } } - } -} -text { - object { - x=1032 - y=89 - width=100 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Enum order" - align="horiz. right" -} -text { - object { - x=1022 - y=64 - width=110 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Update rate" - align="horiz. right" -} -menu { - object { - x=1137 - y=89 - width=130 - height=20 - } - control { - chan="$(P)EnumOrder" - clr=14 - bclr=51 - } -} -composite { - object { - x=1137 - y=64 - width=216 - height=20 - } - "composite name"="" - children { menu { object { - x=1137 - y=64 - width=130 + x=810 + y=1023 + width=80 height=20 } control { - chan="$(P)DoUpdate.SCAN" + chan="$(P)WfInt64Out.SCAN" clr=14 bclr=51 } } - "message button" { + "cartesian plot" { object { - x=1272 - y=64 - width=81 + x=684 + y=918 + width=200 + height=100 + } + plotcom { + clr=14 + bclr=4 + } + trace[0] { + ydata="$(P)WfInt64Out" + data_clr=53 + yaxis=0 + } + } + text { + object { + x=759 + y=893 + width=50 height=20 } - control { - chan="$(P)DoUpdate" + "basic attribute" { clr=14 - bclr=51 } - label="Update" - press_msg="1" + textix="Int64" + align="horiz. centered" } } } -text { - object { - x=1002 - y=114 - width=130 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Status return" - align="horiz. right" -} -menu { - object { - x=1137 - y=114 - width=130 - height=20 - } - control { - chan="$(P)StatusReturn" - clr=14 - bclr=51 - } -} -text { - object { - x=1022 - y=189 - width=110 - height=20 - } - "basic attribute" { - clr=14 - } - textix="asyn record" - align="horiz. right" -} -"related display" { - object { - x=1137 - y=189 - width=100 - height=20 - } - display[0] { - label="asyn record" - name="asynRecord.adl" - args="P=testErrors:,R=asyn1" - } - clr=14 - bclr=51 - label="asyn record" -} -text { - object { - x=1012 - y=139 - width=120 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Alarm status" - align="horiz. right" -} -menu { - object { - x=1137 - y=139 - width=130 - height=20 - } - control { - chan="$(P)AlarmStatus" - clr=14 - bclr=51 - } -} -text { - object { - x=992 - y=164 - width=140 - height=20 - } - "basic attribute" { - clr=14 - } - textix="Alarm severity" - align="horiz. right" -} -menu { - object { - x=1137 - y=164 - width=130 - height=20 - } - control { - chan="$(P)AlarmSeverity" - clr=14 - bclr=51 - } -} diff --git a/testErrorsApp/src/testErrors.cpp b/testErrorsApp/src/testErrors.cpp index f45cc1a..d62956f 100644 --- a/testErrorsApp/src/testErrors.cpp +++ b/testErrorsApp/src/testErrors.cpp @@ -1,6 +1,6 @@ /* * testErrors.cpp - * + * * Asyn driver that inherits from the asynPortDriver class to test error handling in both normally scanned * and I/O Intr scanned records * @@ -55,25 +55,25 @@ static int allUInt32EnumSeverities[MAX_UINT32_ENUMS] = {0, 0, 1, 1, 2, 2, 3, 3} static void callbackTask(void *drvPvt); - + /** Constructor for the testErrors class. * Calls constructor for the asynPortDriver base class. * \param[in] portName The name of the asyn port driver to be created. */ -testErrors::testErrors(const char *portName, int canBlock) - : asynPortDriver(portName, - 1, /* maxAddr */ +testErrors::testErrors(const char *portName, int canBlock) + : asynPortDriver(portName, + 1, /* maxAddr */ /* Interface mask */ - asynInt32Mask | asynFloat64Mask | asynUInt32DigitalMask | asynOctetMask | - asynInt8ArrayMask | asynInt16ArrayMask | asynInt32ArrayMask | asynFloat32ArrayMask | asynFloat64ArrayMask | - asynOptionMask | asynEnumMask | asynDrvUserMask, + asynInt32Mask | asynInt64Mask | asynFloat64Mask | asynUInt32DigitalMask | asynOctetMask | + asynInt8ArrayMask | asynInt16ArrayMask | asynInt32ArrayMask | asynInt64ArrayMask | asynFloat32ArrayMask | asynFloat64ArrayMask | + asynOptionMask | asynEnumMask | asynDrvUserMask, /* Interrupt mask */ - asynInt32Mask | asynFloat64Mask | asynUInt32DigitalMask | asynOctetMask | - asynInt8ArrayMask | asynInt16ArrayMask | asynInt32ArrayMask | asynFloat32ArrayMask | asynFloat64ArrayMask | - asynEnumMask, + asynInt32Mask | asynInt64Mask | asynFloat64Mask | asynUInt32DigitalMask | asynOctetMask | + asynInt8ArrayMask | asynInt16ArrayMask | asynInt32ArrayMask | asynInt64ArrayMask | asynFloat32ArrayMask | asynFloat64ArrayMask | + asynEnumMask, canBlock ? ASYN_CANBLOCK : 0, /* asynFlags */ 1, /* Autoconnect */ 0, /* Default priority */ - 0) /* Default stack size*/ + 0) /* Default stack size*/ { asynStatus status; int i; @@ -85,6 +85,7 @@ testErrors::testErrors(const char *portName, int canBlock) createParam(P_EnumOrderString, asynParamInt32, &P_EnumOrder); createParam(P_DoUpdateString, asynParamInt32, &P_DoUpdate); createParam(P_Int32ValueString, asynParamInt32, &P_Int32Value); + createParam(P_Int64ValueString, asynParamInt64, &P_Int64Value); createParam(P_BinaryInt32ValueString, asynParamInt32, &P_BinaryInt32Value); createParam(P_MultibitInt32ValueString, asynParamInt32, &P_MultibitInt32Value); createParam(P_Float64ValueString, asynParamFloat64, &P_Float64Value); @@ -95,9 +96,10 @@ testErrors::testErrors(const char *portName, int canBlock) createParam(P_Int8ArrayValueString, asynParamInt8Array, &P_Int8ArrayValue); createParam(P_Int16ArrayValueString, asynParamInt16Array, &P_Int16ArrayValue); createParam(P_Int32ArrayValueString, asynParamInt32Array, &P_Int32ArrayValue); + createParam(P_Int64ArrayValueString, asynParamInt64Array, &P_Int64ArrayValue); createParam(P_Float32ArrayValueString, asynParamFloat32Array, &P_Float32ArrayValue); createParam(P_Float64ArrayValueString, asynParamFloat64Array, &P_Float64ArrayValue); - + for (i=0; icallbackTask(); } @@ -149,13 +152,14 @@ void testErrors::callbackTask(void) epicsInt32 alarmSeverity; epicsInt32 itemp; epicsInt32 iVal; + epicsInt64 i64Val; epicsUInt32 uiVal; epicsFloat64 dVal; int i; char octetValue[20]; - + lock(); - /* Loop forever */ + /* Loop forever */ while (1) { unlock(); (void)epicsEventWait(eventId_); @@ -173,6 +177,14 @@ void testErrors::callbackTask(void) setParamAlarmStatus( P_Int32Value, alarmStatus); setParamAlarmSeverity(P_Int32Value, alarmSeverity); + getInteger64Param(P_Int64Value, &i64Val); + i64Val++; + if (i64Val > 64) i64Val=0; + setInteger64Param( P_Int64Value, i64Val); + setParamStatus( P_Int64Value, currentStatus); + setParamAlarmStatus( P_Int64Value, alarmStatus); + setParamAlarmSeverity(P_Int64Value, alarmSeverity); + getIntegerParam(P_BinaryInt32Value, &iVal); iVal++; if (iVal > 1) iVal=0; @@ -220,7 +232,7 @@ void testErrors::callbackTask(void) setParamAlarmStatus( P_Float64Value, alarmStatus); setParamAlarmSeverity(P_Float64Value, alarmSeverity); - sprintf(octetValue, "%.1f", dVal); + sprintf(octetValue, "%.1f", dVal); setStringParam( P_OctetValue, octetValue); setParamStatus( P_OctetValue, currentStatus); setParamAlarmStatus( P_OctetValue, alarmStatus); @@ -230,6 +242,7 @@ void testErrors::callbackTask(void) int8ArrayValue_[i] = iVal; int16ArrayValue_[i] = iVal; int32ArrayValue_[i] = iVal; + int64ArrayValue_[i] = i64Val; float32ArrayValue_[i] = (epicsFloat32)dVal; float64ArrayValue_[i] = dVal; } @@ -243,6 +256,9 @@ void testErrors::callbackTask(void) setParamStatus( P_Int32ArrayValue, currentStatus); setParamAlarmStatus( P_Int32ArrayValue, alarmStatus); setParamAlarmSeverity(P_Int32ArrayValue, alarmSeverity); + setParamStatus( P_Int64ArrayValue, currentStatus); + setParamAlarmStatus( P_Int64ArrayValue, alarmStatus); + setParamAlarmSeverity(P_Int64ArrayValue, alarmSeverity); setParamStatus( P_Float32ArrayValue, currentStatus); setParamAlarmStatus( P_Float32ArrayValue, alarmStatus); setParamAlarmSeverity(P_Float32ArrayValue, alarmSeverity); @@ -252,6 +268,7 @@ void testErrors::callbackTask(void) doCallbacksInt8Array(int8ArrayValue_, MAX_ARRAY_POINTS, P_Int8ArrayValue, 0); doCallbacksInt16Array(int16ArrayValue_, MAX_ARRAY_POINTS, P_Int16ArrayValue, 0); doCallbacksInt32Array(int32ArrayValue_, MAX_ARRAY_POINTS, P_Int32ArrayValue, 0); + doCallbacksInt64Array(int64ArrayValue_, MAX_ARRAY_POINTS, P_Int64ArrayValue, 0); doCallbacksFloat32Array(float32ArrayValue_, MAX_ARRAY_POINTS, P_Float32ArrayValue, 0); doCallbacksFloat64Array(float64ArrayValue_, MAX_ARRAY_POINTS, P_Float64ArrayValue, 0); } @@ -260,7 +277,7 @@ void testErrors::callbackTask(void) void testErrors::setEnums() { epicsInt32 order, offset=0, dir=1, i, j; - + getIntegerParam(P_EnumOrder, &order); if (order != 0) { offset = MAX_INT32_ENUMS-1; @@ -279,20 +296,20 @@ void testErrors::setEnums() uint32EnumValues_[i] = allUInt32EnumValues[j]; uint32EnumSeverities_[i] = allUInt32EnumSeverities[j]; } - doCallbacksEnum(int32EnumStrings_, int32EnumValues_, int32EnumSeverities_, + doCallbacksEnum(int32EnumStrings_, int32EnumValues_, int32EnumSeverities_, MAX_INT32_ENUMS, P_BinaryInt32Value, 0); - doCallbacksEnum(int32EnumStrings_, int32EnumValues_, int32EnumSeverities_, + doCallbacksEnum(int32EnumStrings_, int32EnumValues_, int32EnumSeverities_, MAX_INT32_ENUMS, P_MultibitInt32Value, 0); - doCallbacksEnum(uint32EnumStrings_, uint32EnumValues_, uint32EnumSeverities_, + doCallbacksEnum(uint32EnumStrings_, uint32EnumValues_, uint32EnumSeverities_, MAX_UINT32_ENUMS, P_BinaryUInt32DigitalValue, 0); - doCallbacksEnum(uint32EnumStrings_, uint32EnumValues_, uint32EnumSeverities_, + doCallbacksEnum(uint32EnumStrings_, uint32EnumValues_, uint32EnumSeverities_, MAX_UINT32_ENUMS, P_MultibitUInt32DigitalValue, 0); } asynStatus testErrors::setStatusAndSeverity(asynUser *pasynUser) { int status; - + getIntegerParam(P_StatusReturn, &status); getIntegerParam(P_AlarmStatus, &pasynUser->alarmStatus); getIntegerParam(P_AlarmSeverity, &pasynUser->alarmSeverity); @@ -331,17 +348,52 @@ asynStatus testErrors::writeInt32(asynUser *pasynUser, epicsInt32 value) /* Set the parameter status in the parameter library except for the above commands which always return OK */ status = setStatusAndSeverity(pasynUser); } - + /* Do callbacks so higher layers see any changes */ callParamCallbacks(); - - 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; +} + +/** Called when asyn clients call pasynInt64->write(). + * This function sends a signal to the simTask thread if the value of P_Run has changed. + * For all parameters it sets the value in the parameter library and calls any registered callbacks.. + * \param[in] pasynUser pasynUser structure that encodes the reason and address. + * \param[in] value Value to write. */ +asynStatus testErrors::writeInt64(asynUser *pasynUser, epicsInt64 value) +{ + int function = pasynUser->reason; + asynStatus status = asynSuccess; + const char *paramName; + const char* functionName = "writeInt64"; + + /* Fetch the parameter string name for use in debugging */ + getParamName(function, ¶mName); + + /* Set the parameter value in the parameter library. */ + setInteger64Param(function, value); + + /* Set the parameter status in the parameter library */ + status = setStatusAndSeverity(pasynUser); + + /* Do callbacks so higher layers see any changes */ + callParamCallbacks(); + + 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; } @@ -367,14 +419,14 @@ asynStatus testErrors::writeFloat64(asynUser *pasynUser, epicsFloat64 value) /* Do callbacks so higher layers see any changes */ callParamCallbacks(); - - if (status) - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "%s:%s: status=%d, function=%d, name=%s, value=%f", + + 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; } @@ -398,29 +450,29 @@ asynStatus testErrors::writeUInt32Digital(asynUser *pasynUser, epicsUInt32 value /* Set the parameter status in the parameter library */ status = setStatusAndSeverity(pasynUser); - + /* Do callbacks so higher layers see any changes */ callParamCallbacks(); - - if (status) - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "%s:%s: status=%d, function=%d, name=%s, value=0x%X", + + if (status) + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s:%s: status=%d, function=%d, name=%s, value=0x%X", driverName, functionName, status, function, paramName, value); - else - asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, - "%s:%s: function=%d, name=%s, value=0x%X\n", + else + asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, + "%s:%s: function=%d, name=%s, value=0x%X\n", driverName, functionName, function, paramName, value); return status; } /** Called when asyn clients call pasynOctet->write(). - * Simply sets the value in the parameter library and - * calls any registered callbacks for this pasynUser->reason and address. + * Simply sets the value in the parameter library and + * calls any registered callbacks for this pasynUser->reason and address. * \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 testErrors::writeOctet(asynUser *pasynUser, const char *value, +asynStatus testErrors::writeOctet(asynUser *pasynUser, const char *value, size_t nChars, size_t *nActual) { int function = pasynUser->reason; @@ -439,13 +491,13 @@ asynStatus testErrors::writeOctet(asynUser *pasynUser, const char *value, /* Do callbacks so higher layers see any changes */ callParamCallbacks(); - 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; @@ -468,7 +520,7 @@ asynStatus testErrors::readEnum(asynUser *pasynUser, char *strings[], int values for (i=0; ((i -asynStatus testErrors::doReadArray(asynUser *pasynUser, epicsType *value, + +template +asynStatus testErrors::doReadArray(asynUser *pasynUser, epicsType *value, size_t nElements, size_t *nIn, int paramIndex, epicsType *pValue) { int function = pasynUser->reason; @@ -557,54 +609,137 @@ asynStatus testErrors::doReadArray(asynUser *pasynUser, epicsType *value, *nIn = ncopy; } - if (status) - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "%s:%s: status=%d, function=%d", + if (status) + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s:%s: status=%d, function=%d", driverName, functionName, status, function); - else - asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, - "%s:%s: function=%d\n", + else + asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, + "%s:%s: function=%d\n", driverName, functionName, function); return (asynStatus)status; } - -asynStatus testErrors::readInt8Array(asynUser *pasynUser, epicsInt8 *value, + +asynStatus testErrors::readInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t nElements, size_t *nIn) { return doReadArray (pasynUser, value, nElements, nIn, P_Int8ArrayValue, int8ArrayValue_); } -asynStatus testErrors::readInt16Array(asynUser *pasynUser, epicsInt16 *value, +asynStatus testErrors::readInt16Array(asynUser *pasynUser, epicsInt16 *value, size_t nElements, size_t *nIn) { return doReadArray (pasynUser, value, nElements, nIn, P_Int16ArrayValue, int16ArrayValue_); } -asynStatus testErrors::readInt32Array(asynUser *pasynUser, epicsInt32 *value, +asynStatus testErrors::readInt32Array(asynUser *pasynUser, epicsInt32 *value, size_t nElements, size_t *nIn) { return doReadArray (pasynUser, value, nElements, nIn, P_Int32ArrayValue, int32ArrayValue_); } -asynStatus testErrors::readFloat32Array(asynUser *pasynUser, epicsFloat32 *value, +asynStatus testErrors::readInt64Array(asynUser *pasynUser, epicsInt64 *value, + size_t nElements, size_t *nIn) +{ + return doReadArray + (pasynUser, value, nElements, nIn, P_Int64ArrayValue, int64ArrayValue_); +} + +asynStatus testErrors::readFloat32Array(asynUser *pasynUser, epicsFloat32 *value, size_t nElements, size_t *nIn) { return doReadArray (pasynUser, value, nElements, nIn, P_Float32ArrayValue, float32ArrayValue_); } -asynStatus testErrors::readFloat64Array(asynUser *pasynUser, epicsFloat64 *value, +asynStatus testErrors::readFloat64Array(asynUser *pasynUser, epicsFloat64 *value, size_t nElements, size_t *nIn) { return doReadArray (pasynUser, value, nElements, nIn, P_Float64ArrayValue, float64ArrayValue_); } - - +template +asynStatus testErrors::doWriteArray(asynUser *pasynUser, epicsType *value, + size_t nElements, int paramIndex, epicsType *pValue) +{ + int function = pasynUser->reason; + size_t ncopy = MAX_ARRAY_POINTS; + epicsInt32 status = asynSuccess; + epicsTimeStamp timestamp; + const char *functionName = "doWriteArray"; + + /* Get the current timestamp */ + getTimeStamp(×tamp); + pasynUser->timestamp = timestamp; + + /* Set the parameter status in the parameter library */ + status = setStatusAndSeverity(pasynUser); + + if (nElements < ncopy) ncopy = nElements; + if (function == paramIndex) { + memcpy(pValue, value, ncopy*sizeof(epicsType)); + } + + if (status) + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s:%s: status=%d, function=%d", + driverName, functionName, status, function); + else + asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, + "%s:%s: function=%d\n", + driverName, functionName, function); + return (asynStatus)status; +} + +asynStatus testErrors::writeInt8Array(asynUser *pasynUser, epicsInt8 *value, + size_t nElements) +{ + return doWriteArray + (pasynUser, value, nElements, P_Int8ArrayValue, int8ArrayValue_); +} + +asynStatus testErrors::writeInt16Array(asynUser *pasynUser, epicsInt16 *value, + size_t nElements) +{ + return doWriteArray + (pasynUser, value, nElements, P_Int16ArrayValue, int16ArrayValue_); +} + +asynStatus testErrors::writeInt32Array(asynUser *pasynUser, epicsInt32 *value, + size_t nElements) +{ + return doWriteArray + (pasynUser, value, nElements, P_Int32ArrayValue, int32ArrayValue_); +} + +asynStatus testErrors::writeInt64Array(asynUser *pasynUser, epicsInt64 *value, + size_t nElements) +{ + return doWriteArray + (pasynUser, value, nElements, P_Int64ArrayValue, int64ArrayValue_); +} + +asynStatus testErrors::writeFloat32Array(asynUser *pasynUser, epicsFloat32 *value, + size_t nElements) +{ + return doWriteArray + (pasynUser, value, nElements, P_Float32ArrayValue, float32ArrayValue_); +} + +asynStatus testErrors::writeFloat64Array(asynUser *pasynUser, epicsFloat64 *value, + size_t nElements) +{ + return doWriteArray + (pasynUser, value, nElements, P_Float64ArrayValue, float64ArrayValue_); +} + + + + /* Configuration routine. Called directly, or from the iocsh function below */ extern "C" { diff --git a/testErrorsApp/src/testErrors.h b/testErrorsApp/src/testErrors.h index d79cf8e..df11d70 100644 --- a/testErrorsApp/src/testErrors.h +++ b/testErrorsApp/src/testErrors.h @@ -1,6 +1,6 @@ /* * testErrors.h - * + * * Asyn driver that inherits from the asynPortDriver class to test error handling in both normally scanned * and I/O Intr scanned records * @@ -27,6 +27,7 @@ #define P_EnumOrderString "ENUM_ORDER" /* asynInt32, r/w */ #define P_DoUpdateString "DO_UPDATE" /* asynInt32, r/w */ #define P_Int32ValueString "INT32_VALUE" /* asynInt32, r/w */ +#define P_Int64ValueString "INT64_VALUE" /* asynInt64, r/w */ #define P_BinaryInt32ValueString "BINARY_INT32_VALUE" /* asynInt32, r/w */ #define P_MultibitInt32ValueString "MULTIBIT_INT32_VALUE" /* asynInt32, r/w */ #define P_Float64ValueString "FLOAT64_VALUE" /* asynFloat64, r/w */ @@ -37,6 +38,7 @@ #define P_Int8ArrayValueString "INT8_ARRAY_VALUE" /* asynInt8Array, r/w */ #define P_Int16ArrayValueString "INT16_ARRAY_VALUE" /* asynInt16Array, r/w */ #define P_Int32ArrayValueString "INT32_ARRAY_VALUE" /* asynInt32Array, r/w */ +#define P_Int64ArrayValueString "INT64_ARRAY_VALUE" /* asynInt64Array, r/w */ #define P_Float32ArrayValueString "FLOAT32_ARRAY_VALUE" /* asynFloat32Array, r/w */ #define P_Float64ArrayValueString "FLOAT64_ARRAY_VALUE" /* asynFloat64Array, r/w */ @@ -45,12 +47,13 @@ class testErrors : public asynPortDriver { public: testErrors(const char *portName, int canBlock); - + /* These are the methods that we override from asynPortDriver */ virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); + virtual asynStatus writeInt64(asynUser *pasynUser, epicsInt64 value); virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value); virtual asynStatus writeUInt32Digital(asynUser *pasynUser, epicsUInt32 value, epicsUInt32 mask); - virtual asynStatus writeOctet(asynUser *pasynUser, const char *value, + virtual asynStatus writeOctet(asynUser *pasynUser, const char *value, size_t nChars, size_t *nActual); virtual asynStatus readInt8Array (asynUser *pasynUser, epicsInt8 *value, size_t nElements, size_t *nIn); @@ -58,10 +61,24 @@ class testErrors : public asynPortDriver { size_t nElements, size_t *nIn); virtual asynStatus readInt32Array (asynUser *pasynUser, epicsInt32 *value, size_t nElements, size_t *nIn); + virtual asynStatus readInt64Array (asynUser *pasynUser, epicsInt64 *value, + size_t nElements, size_t *nIn); virtual asynStatus readFloat32Array(asynUser *pasynUser, epicsFloat32 *value, size_t nElements, size_t *nIn); virtual asynStatus readFloat64Array(asynUser *pasynUser, epicsFloat64 *value, size_t nElements, size_t *nIn); + virtual asynStatus writeInt8Array (asynUser *pasynUser, epicsInt8 *value, + size_t nElements); + virtual asynStatus writeInt16Array (asynUser *pasynUser, epicsInt16 *value, + size_t nElements); + virtual asynStatus writeInt32Array (asynUser *pasynUser, epicsInt32 *value, + size_t nElements); + virtual asynStatus writeInt64Array (asynUser *pasynUser, epicsInt64 *value, + size_t nElements); + virtual asynStatus writeFloat32Array(asynUser *pasynUser, epicsFloat32 *value, + size_t nElements); + virtual asynStatus writeFloat64Array(asynUser *pasynUser, epicsFloat64 *value, + size_t nElements); virtual asynStatus readOption(asynUser *pasynUser, const char *key, char *value, int maxChars); virtual asynStatus writeOption(asynUser *pasynUser, const char *key, const char *value); virtual asynStatus readEnum(asynUser *pasynUser, char *strings[], int values[], int severities[], @@ -78,6 +95,7 @@ class testErrors : public asynPortDriver { int P_EnumOrder; int P_DoUpdate; int P_Int32Value; + int P_Int64Value; int P_BinaryInt32Value; int P_MultibitInt32Value; int P_Float64Value; @@ -88,9 +106,10 @@ class testErrors : public asynPortDriver { int P_Int8ArrayValue; int P_Int16ArrayValue; int P_Int32ArrayValue; + int P_Int64ArrayValue; int P_Float32ArrayValue; int P_Float64ArrayValue; - + private: /* Our data */ char *int32EnumStrings_ [MAX_INT32_ENUMS]; @@ -105,9 +124,13 @@ class testErrors : public asynPortDriver { epicsInt8 int8ArrayValue_ [MAX_ARRAY_POINTS]; epicsInt16 int16ArrayValue_ [MAX_ARRAY_POINTS]; epicsInt32 int32ArrayValue_ [MAX_ARRAY_POINTS]; + epicsInt64 int64ArrayValue_ [MAX_ARRAY_POINTS]; epicsFloat32 float32ArrayValue_[MAX_ARRAY_POINTS]; epicsFloat64 float64ArrayValue_[MAX_ARRAY_POINTS]; - template - asynStatus doReadArray(asynUser *pasynUser, epicsType *value, - size_t nElements, size_t *nIn, int paramIndex, epicsType *pValue); + template + asynStatus doReadArray(asynUser *pasynUser, epicsType *value, + size_t nElements, size_t *nIn, int paramIndex, epicsType *pValue); + template + asynStatus doWriteArray(asynUser *pasynUser, epicsType *value, + size_t nElements, int paramIndex, epicsType *pValue); }; diff --git a/testErrorsApp/src/testErrorsMain.cpp b/testErrorsApp/src/testErrorsMain.cpp index ae0ecb6..fe4f105 100644 --- a/testErrorsApp/src/testErrorsMain.cpp +++ b/testErrorsApp/src/testErrorsMain.cpp @@ -13,7 +13,7 @@ int main(int argc,char *argv[]) { - if(argc>=2) { + if(argc>=2) { iocsh(argv[1]); epicsThreadSleep(.2); } diff --git a/documentation/HowToDoSerial/AB300/AB300App/Makefile b/testFtdiApp/Makefile similarity index 99% rename from documentation/HowToDoSerial/AB300/AB300App/Makefile rename to testFtdiApp/Makefile index ab15bfb..10e0126 100644 --- a/documentation/HowToDoSerial/AB300/AB300App/Makefile +++ b/testFtdiApp/Makefile @@ -5,3 +5,4 @@ DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Src*)) DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *db*)) DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Db*)) include $(TOP)/configure/RULES_DIRS + diff --git a/testFtdiApp/src/Makefile b/testFtdiApp/src/Makefile new file mode 100644 index 0000000..08c615a --- /dev/null +++ b/testFtdiApp/src/Makefile @@ -0,0 +1,10 @@ +TOP=../.. + +include $(TOP)/configure/CONFIG + +PROD_IOC = testFtdi +testFtdi_SRCS += testFtdiMain.cpp +testFtdi_LIBS += asyn $(EPICS_BASE_IOC_LIBS) + +include $(TOP)/configure/RULES + diff --git a/testFtdiApp/src/testFtdiMain.cpp b/testFtdiApp/src/testFtdiMain.cpp new file mode 100644 index 0000000..c8d4cee --- /dev/null +++ b/testFtdiApp/src/testFtdiMain.cpp @@ -0,0 +1,127 @@ +/* + * testFtdiMain.cpp + * + * Program to test drvAsynFtdiPort. + * This test program assumes that there is an FTDI device + * connected to a USB port and that it is wired as a loopback + * (just echoing back what is sent). + * + * Author: Bruno Martins + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +const char *PORT_NAME = "PORT"; +const int VENDOR = 0x0403; +const int PRODUCT = 0x6001; +const int BAUDRATE = 1000000; +const int LATENCY = 2; +const double TIMEOUT = 1.0; + +int main(int argc, char **argv) +{ + asynStatus status; + + status = (asynStatus) drvAsynFTDIPortConfigure( + PORT_NAME, VENDOR, PRODUCT, BAUDRATE, LATENCY, 0, 0, 1, 0 + ); + + printf("drvAsynFTDIPortConfigure(port='%s', vendor=0x%04X, product=0x%04X, baudrate=%d, latency=%d) -> %d\n", + PORT_NAME, VENDOR, PRODUCT, BAUDRATE, LATENCY, status + ); + + // Enable Tracing + /*asynSetTraceInfoMask(PORT_NAME,-1,0x03); + asynSetTraceIOMask(PORT_NAME, -1, 0xFF); + asynSetTraceMask(PORT_NAME, -1, 0xFF);*/ + + asynOctetClient oct(PORT_NAME, 0); + asynOptionClient opt(PORT_NAME, 0); + + oct.setTimeout(TIMEOUT); + + // Test sending strings at different baud rates and different port settings + const char *bauds[] = { + "9600", "14400", "19200", + "38400", "57600", "115200", + "1000000", "3000000" + }; + size_t nbauds = sizeof(bauds)/sizeof(bauds[0]); + + for (size_t i = 0; i < nbauds; ++i) { + size_t nwrite, nread; + int eomReason; + char actualBaud[64] = {}; + char wbuf[256], rbuf[256]; + int ok; + + status = opt.setOption("baud", bauds[i]); + + if (status) { + fprintf(stderr, "Failed to set baud rate\n"); + continue; + } + + status = opt.getOption("baud", actualBaud, sizeof(actualBaud)); + + if (status) { + fprintf(stderr, "Failed to retrieve baud rate\n"); + continue; + } + + printf("Set baud rate to %s (actual: %s)\n", bauds[i], actualBaud); + + int len = snprintf(wbuf, sizeof(wbuf), "Hello!"); + + status = oct.writeRead(wbuf, len+1, rbuf, len+1, &nwrite, &nread, &eomReason); + + if (status) { + fprintf(stderr, " writeRead(string) failed: %d\n", status); + continue; + } + + ok = !strncmp(wbuf, rbuf, sizeof(wbuf)); + printf(" Wrote (%lu) '%s', received (%lu) '%s' --> %sOK!\n", + nwrite, wbuf, nread, rbuf, ok ? "" : "NOT "); + + // Test sending binary data + wbuf[0] = 0x00; + wbuf[1] = 0xAB; + wbuf[2] = 0xCD; + + status = oct.writeRead( + wbuf, 3, rbuf, 3, &nwrite, &nread, &eomReason + ); + + if (status) { + fprintf(stderr, " writeRead(binary) failed: %d\n", status); + continue; + } + + ok = nwrite == nread; + for (size_t j = 0; ok && j < nwrite; ++j) + ok &= wbuf[j] == rbuf[j]; + + printf(" Wrote (%lu) '", nwrite); + for (size_t j = 0; j < nwrite; ++j) + printf("%02X ", (unsigned char)wbuf[j]); + printf("', received (%lu) '", nread); + for (size_t j = 0; j < nread; ++j) + printf("%02X ", (unsigned char)rbuf[j]); + printf("' --> %sOK!\n", ok ? "" : "NOT "); + } + + //asynReport(10, PORT_NAME); + + return EXIT_SUCCESS; +} diff --git a/testGpibApp/src/Makefile b/testGpibApp/src/Makefile index bba05ea..2095700 100644 --- a/testGpibApp/src/Makefile +++ b/testGpibApp/src/Makefile @@ -9,6 +9,8 @@ ASYN = $(TOP) ASYN_LIB = $(TOP)/lib/$(T_A) ASYN_BIN = $(TOP)/bin/$(T_A) +USR_CFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET -DUSE_TYPED_DRVET + DBD += devTestGpib.dbd DBD += testGpib.dbd @@ -40,6 +42,10 @@ testGpibVx_SRCS_vxWorks += testGpibVx_registerRecordDeviceDriver.cpp testGpib_LIBS += devTestGpib testGpib_LIBS += testSupport asyn +ifeq ($(TIRPC),YES) + USR_INCLUDES += -I/usr/include/tirpc + testGpib_SYS_LIBS += tirpc +endif SYS_PROD_LIBS_cygwin32 += $(CYGWIN_RPC_LIB) testGpib_LIBS += $(EPICS_BASE_IOC_LIBS) diff --git a/testGpibApp/src/devTestGpib.c b/testGpibApp/src/devTestGpib.c index acfef37..fbcc667 100644 --- a/testGpibApp/src/devTestGpib.c +++ b/testGpibApp/src/devTestGpib.c @@ -50,11 +50,11 @@ #include #include - + #define TIMEOUT 1.0 #define TIMEWINDOW 2.0 -static struct gpibCmd gpibCmds[] = +static struct gpibCmd gpibCmds[] = { /* Param 0, */ {&DSET_BO, GPIBIFC, IB_Q_LOW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, @@ -102,7 +102,7 @@ static struct gpibCmd gpibCmds[] = /* The following is the number of elements in the command array above. */ #define NUMPARAMS sizeof(gpibCmds)/sizeof(struct gpibCmd) - + /****************************************************************************** * * Initialization for device support diff --git a/testGpibApp/src/testGpibMain.cpp b/testGpibApp/src/testGpibMain.cpp index ae0ecb6..fe4f105 100644 --- a/testGpibApp/src/testGpibMain.cpp +++ b/testGpibApp/src/testGpibMain.cpp @@ -13,7 +13,7 @@ int main(int argc,char *argv[]) { - if(argc>=2) { + if(argc>=2) { iocsh(argv[1]); epicsThreadSleep(.2); } diff --git a/testGpibSerialApp/src/Makefile b/testGpibSerialApp/src/Makefile index 9fcae95..3a49e0f 100644 --- a/testGpibSerialApp/src/Makefile +++ b/testGpibSerialApp/src/Makefile @@ -9,6 +9,8 @@ ASYN = $(TOP) ASYN_LIB = $(TOP)/lib/$(T_A) ASYN_BIN = $(TOP)/bin/$(T_A) +USR_CFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET -DUSE_TYPED_DRVET + ifeq ($(OS_CLASS),vxWorks) DBD += testGpibSerialVx.dbd testGpibSerialVx_DBD += testGpibSerialSupport.dbd diff --git a/testGpibSerialApp/src/devTestGpibSerial.c b/testGpibSerialApp/src/devTestGpibSerial.c index d7bd745..03d72d0 100644 --- a/testGpibSerialApp/src/devTestGpibSerial.c +++ b/testGpibSerialApp/src/devTestGpibSerial.c @@ -51,7 +51,7 @@ #include #include #include - + #define TIMEOUT 1.0 #define TIMEWINDOW 2.0 @@ -63,7 +63,7 @@ static int readString(gpibDpvt *pdpvt,int P1, int P2, char **P3); */ #define EOSNL "\n" -static struct gpibCmd gpibCmds[] = +static struct gpibCmd gpibCmds[] = { /* Param 0, */ {&DSET_BO, GPIBIFC, IB_Q_LOW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, @@ -110,7 +110,7 @@ static struct gpibCmd gpibCmds[] = /* The following is the number of elements in the command array above. */ #define NUMPARAMS sizeof(gpibCmds)/sizeof(struct gpibCmd) - + /****************************************************************************** * * Initialization for device support diff --git a/testGpibSerialApp/src/testGpibSerialMain.cpp b/testGpibSerialApp/src/testGpibSerialMain.cpp index ae0ecb6..fe4f105 100644 --- a/testGpibSerialApp/src/testGpibSerialMain.cpp +++ b/testGpibSerialApp/src/testGpibSerialMain.cpp @@ -13,7 +13,7 @@ int main(int argc,char *argv[]) { - if(argc>=2) { + if(argc>=2) { iocsh(argv[1]); epicsThreadSleep(.2); } diff --git a/testIPServerApp/src/asynPortTest.cpp b/testIPServerApp/src/asynPortTest.cpp index b2e3aff..69e96d5 100644 --- a/testIPServerApp/src/asynPortTest.cpp +++ b/testIPServerApp/src/asynPortTest.cpp @@ -1,8 +1,8 @@ /* * asynPortTest.cpp - * + * * Asyn driver that inherits from the asynPortDriver class to demonstrate its use. - * It communicates with the echoServer driver. + * It communicates with the echoServer driver. * It sends and receives int32, float64 and octet values. * * Author: Mark Rivers @@ -31,11 +31,11 @@ class asynPortTest : public asynPortDriver { public: asynPortTest(const char *portName, const char *echoPortName); - + /* These are the methods that we override from asynPortDriver */ virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value); - virtual asynStatus writeOctet(asynUser *pasynUser, const char *value, + virtual asynStatus writeOctet(asynUser *pasynUser, const char *value, size_t nChars, size_t *nActual); protected: @@ -43,7 +43,7 @@ class asynPortTest : public asynPortDriver { int Int32Data; int Float64Data; int OctetData; - + private: /* Our data */ asynUser *pasynUserEcho; @@ -57,7 +57,7 @@ static const char *driverName="asynPortTest"; /** Called when asyn clients call pasynInt32->write(). * This function converts the integer to a string and sends it to the echoServer. * It reads back the string response, converts it to a number, divides by 2 and calls - * the callbacks with the new value. + * the callbacks with the new value. * For all parameters it sets the value in the parameter library and calls any registered callbacks.. * \param[in] pasynUser pasynUser structure that encodes the reason and address. * \param[in] value Value to write. */ @@ -72,26 +72,26 @@ asynStatus asynPortTest::writeInt32(asynUser *pasynUser, epicsInt32 value) /* Set the parameter in the parameter library. */ status = (asynStatus) setIntegerParam(function, value); - + if (function == Int32Data) { sprintf(writeBuffer, "%d", value); - status = pasynOctetSyncIO->writeRead(pasynUserEcho, writeBuffer, strlen(writeBuffer), readBuffer, + status = pasynOctetSyncIO->writeRead(pasynUserEcho, writeBuffer, strlen(writeBuffer), readBuffer, sizeof(readBuffer), TIMEOUT, &nActual, &nRead, &eomReason); sscanf(readBuffer, "%d", &readValue); readValue /= 2; - setIntegerParam(Int32Data, readValue); - } - + setIntegerParam(Int32Data, readValue); + } + /* Do callbacks so higher layers see any changes */ status = (asynStatus) callParamCallbacks(); - - if (status) - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "%s:%s: status=%d, function=%d, value=%d", + + if (status) + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s:%s: status=%d, function=%d, value=%d", driverName, functionName, status, function, value); - else - asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, - "%s:%s: function=%d, value=%d\n", + else + asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, + "%s:%s: function=%d, value=%d\n", driverName, functionName, function, value); return status; } @@ -114,23 +114,23 @@ asynStatus asynPortTest::writeFloat64(asynUser *pasynUser, epicsFloat64 value) if (function == Float64Data) { sprintf(writeBuffer, "%f", value); - status = pasynOctetSyncIO->writeRead(pasynUserEcho, writeBuffer, strlen(writeBuffer), readBuffer, + status = pasynOctetSyncIO->writeRead(pasynUserEcho, writeBuffer, strlen(writeBuffer), readBuffer, sizeof(readBuffer), TIMEOUT, &nActual, &nRead, &eomReason); sscanf(readBuffer, "%lf", &readValue); readValue /= 3; - setDoubleParam(Float64Data, readValue); + setDoubleParam(Float64Data, readValue); } - + /* Do callbacks so higher layers see any changes */ status = (asynStatus) callParamCallbacks(); - - if (status) - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "%s:%s: status=%d, function=%d, value=%f", + + if (status) + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s:%s: status=%d, function=%d, value=%f", driverName, functionName, status, function, value); - else - asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, - "%s:%s: function=%d, value=%f\n", + else + asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, + "%s:%s: function=%d, value=%f\n", driverName, functionName, function, value); return status; } @@ -140,7 +140,7 @@ asynStatus asynPortTest::writeFloat64(asynUser *pasynUser, epicsFloat64 value) * \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 asynPortTest::writeOctet(asynUser *pasynUser, const char *value, +asynStatus asynPortTest::writeOctet(asynUser *pasynUser, const char *value, size_t nChars, size_t *nActual) { int function = pasynUser->reason; @@ -151,51 +151,51 @@ asynStatus asynPortTest::writeOctet(asynUser *pasynUser, const char *value, const char *functionName = "writeOctet"; if (function == OctetData) { - status = pasynOctetSyncIO->writeRead(pasynUserEcho, value, nChars, readBuffer, + status = pasynOctetSyncIO->writeRead(pasynUserEcho, value, nChars, readBuffer, sizeof(readBuffer), TIMEOUT, nActual, &nRead, &eomReason); /* Convert to upper case */ for (i=0; i<(int)nRead; i++) readBuffer[i] = toupper(readBuffer[i]); - status = (asynStatus)setStringParam(OctetData, readBuffer); + status = (asynStatus)setStringParam(OctetData, readBuffer); } /* Do callbacks so higher layers see any changes */ status = (asynStatus)callParamCallbacks(); - if (status) - epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, - "%s:%s: status=%d, function=%d, value=%s", + if (status) + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s:%s: status=%d, function=%d, value=%s", driverName, functionName, status, function, value); - else - asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, - "%s:%s: function=%d, value=%s\n", + else + asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, + "%s:%s: function=%d, value=%s\n", driverName, functionName, function, value); return status; } - + /** Constructor for the asynPortTest class. * Calls constructor for the asynPortDriver base class. * \param[in] portName The name of the asyn port driver to be created. * \param[in] maxPoints The maximum number of points in the volt and time arrays */ -asynPortTest::asynPortTest(const char *portName, const char *echoPortName) - : asynPortDriver(portName, - 1, /* maxAddr */ +asynPortTest::asynPortTest(const char *portName, const char *echoPortName) + : asynPortDriver(portName, + 1, /* maxAddr */ asynInt32Mask | asynFloat64Mask | asynOctetMask | asynDrvUserMask, /* Interface mask */ asynInt32Mask | asynFloat64Mask | asynOctetMask, /* Interrupt mask */ ASYN_CANBLOCK, /* asynFlags. This driver blocks and it is not multi-device*/ 1, /* Autoconnect */ 0, /* Default priority */ - 0) /* Default stack size*/ + 0) /* Default stack size*/ { //const char *functionName = "asynPortTest"; pasynOctetSyncIO->connect(echoPortName, 0, &pasynUserEcho, NULL); createParam(Int32DataString, asynParamInt32, &Int32Data); createParam(Float64DataString, asynParamFloat64, &Float64Data); - createParam(OctetDataString, asynParamOctet, &OctetData); + createParam(OctetDataString, asynParamOctet, &OctetData); } - + /* Configuration routine. Called directly, or from the iocsh function below */ extern "C" { diff --git a/testIPServerApp/src/ipEchoServer.c b/testIPServerApp/src/ipEchoServer.c index e22ae8b..0c40e12 100644 --- a/testIPServerApp/src/ipEchoServer.c +++ b/testIPServerApp/src/ipEchoServer.c @@ -28,7 +28,7 @@ #include #include #include - + #define MESSAGE_SIZE 80 #define READ_TIMEOUT -1.0 #define WRITE_TIMEOUT 2.0 @@ -53,33 +53,33 @@ static void echoListener(myData *pPvt) status = pasynOctetSyncIO->connect(pPvt->portName, 0, &pasynUser, NULL); if (status) { asynPrint(pasynUser, ASYN_TRACE_ERROR, - "echoListener: unable to connect to port %s\n", + "echoListener: unable to connect to port %s\n", pPvt->portName); return; } status = pasynOctetSyncIO->setInputEos(pasynUser, "\r\n", 2); if (status) { asynPrint(pasynUser, ASYN_TRACE_ERROR, - "echoListener: unable to set input EOS on %s: %s\n", + "echoListener: unable to set input EOS on %s: %s\n", pPvt->portName, pasynUser->errorMessage); return; } status = pasynOctetSyncIO->setOutputEos(pasynUser, "\r\n", 2); if (status) { asynPrint(pasynUser, ASYN_TRACE_ERROR, - "echoListener: unable to set output EOS on %s: %s\n", + "echoListener: unable to set output EOS on %s: %s\n", pPvt->portName, pasynUser->errorMessage); return; } while(1) { /* Erase buffer */ buffer[0] = 0; - status = pasynOctetSyncIO->read(pasynUser, buffer, MESSAGE_SIZE, + status = pasynOctetSyncIO->read(pasynUser, buffer, MESSAGE_SIZE, pPvt->readTimeout, &nread, &eomReason); switch (status) { case asynSuccess: asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, - "echoListener: %s read %lu: %s\n", + "echoListener: %s read %lu: %s\n", pPvt->portName, (unsigned long)nread, buffer); status = pasynOctetSyncIO->write(pasynUser, buffer, strlen(buffer), WRITE_TIMEOUT, &nwrite); @@ -96,13 +96,13 @@ static void echoListener(myData *pPvt) case asynTimeout: asynPrint(pasynUser, ASYN_TRACE_ERROR, - "echoListener: timeout on: %s read %lu: %s\n", + "echoListener: timeout on: %s read %lu: %s\n", pPvt->portName, (unsigned long)nread, buffer); break; default: asynPrint(pasynUser, ASYN_TRACE_ERROR, - "echoListener: read error on: %s: status=%d error=%s\n", + "echoListener: read error on: %s: status=%d error=%s\n", pPvt->portName, status, pasynUser->errorMessage); goto done; } @@ -118,14 +118,14 @@ static void echoListener(myData *pPvt) free(pPvt); } - -static void connectionCallback(void *drvPvt, asynUser *pasynUser, char *portName, + +static void connectionCallback(void *drvPvt, asynUser *pasynUser, char *portName, size_t len, int eomReason) { myData *pPvt = (myData *)drvPvt; myData *newPvt = calloc(1, sizeof(myData)); - asynPrint(pasynUser, ASYN_TRACE_FLOW, + asynPrint(pasynUser, ASYN_TRACE_FLOW, "ipEchoServer: connectionCallback, portName=%s\n", portName); epicsMutexLock(pPvt->mutexId); /* Make a copy of myData, with new portName */ @@ -163,9 +163,9 @@ static void ipEchoServer(const char *portName, int readTimeout) printf("%s driver not supported\n",asynOctetType); return; } - if (readTimeout == 0) + if (readTimeout == 0) pPvt->readTimeout = READ_TIMEOUT; - else + else pPvt->readTimeout = readTimeout/1000.; pPvt->pasynOctet = (asynOctet *)pasynInterface->pinterface; pPvt->octetPvt = pasynInterface->drvPvt; @@ -184,8 +184,8 @@ static const iocshArg *const ipEchoServerArgs[] = { &ipEchoServerArg0, &ipEchoServerArg1}; static const iocshFuncDef ipEchoServerDef = {"ipEchoServer", 2, ipEchoServerArgs}; -static void ipEchoServerCall(const iocshArgBuf * args) -{ +static void ipEchoServerCall(const iocshArgBuf * args) +{ ipEchoServer(args[0].sval, args[1].ival); } diff --git a/testIPServerApp/src/ipEchoServer2.c b/testIPServerApp/src/ipEchoServer2.c index 3d0768f..ad61e13 100644 --- a/testIPServerApp/src/ipEchoServer2.c +++ b/testIPServerApp/src/ipEchoServer2.c @@ -29,7 +29,7 @@ #include #include #include - + #define MESSAGE_SIZE 80 #define NUM_MESSAGES 10 #define READ_TIMEOUT 0.5 @@ -56,45 +56,45 @@ static void echoListener(myData *pPvt) status = pasynOctetSyncIO->connect(pPvt->portName, 0, &pasynUser, NULL); if (status) { asynPrint(pasynUser, ASYN_TRACE_ERROR, - "echoListener: unable to connect to port %s\n", + "echoListener: unable to connect to port %s\n", pPvt->portName); return; } status = pasynOctetSyncIO->setInputEos(pasynUser, "\r\n", 2); if (status) { asynPrint(pasynUser, ASYN_TRACE_ERROR, - "echoListener: unable to set input EOS on %s: %s\n", + "echoListener: unable to set input EOS on %s: %s\n", pPvt->portName, pasynUser->errorMessage); return; } status = pasynOctetSyncIO->setOutputEos(pasynUser, "\r\n", 2); if (status) { asynPrint(pasynUser, ASYN_TRACE_ERROR, - "echoListener: unable to set output EOS on %s: %s\n", + "echoListener: unable to set output EOS on %s: %s\n", pPvt->portName, pasynUser->errorMessage); return; } while(1) { /* Erase buffer */ buffer[0] = 0; - status = pasynOctetSyncIO->read(pasynUser, buffer, MESSAGE_SIZE, + status = pasynOctetSyncIO->read(pasynUser, buffer, MESSAGE_SIZE, pPvt->readTimeout, &nread, &eomReason); switch (status) { case asynSuccess: asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, - "echoListener: %s read %lu: %s\n", + "echoListener: %s read %lu: %s\n", pPvt->portName, (unsigned long)nread, buffer); epicsMessageQueueSend(pPvt->msgQueue, buffer, MESSAGE_SIZE); break; case asynTimeout: asynPrint(pasynUser, ASYN_TRACEIO_DEVICE, - "echoListener: timeout on: %s read %lu: %s\n", + "echoListener: timeout on: %s read %lu: %s\n", pPvt->portName, (unsigned long)nread, buffer); /* Timeout is expected, just try again */ break; default: asynPrint(pasynUser, ASYN_TRACE_ERROR, - "echoListener: read error on: %s: status=%d error=%s\n", + "echoListener: read error on: %s: status=%d error=%s\n", pPvt->portName, status, pasynUser->errorMessage); goto done; } @@ -121,7 +121,7 @@ static void echoWriter(myData *pPvt) status = pasynOctetSyncIO->connect(pPvt->portName, 0, &pasynUser, NULL); if (status) { asynPrint(pasynUser, ASYN_TRACE_ERROR, - "echoWrite: unable to connect to port %s\n", + "echoWrite: unable to connect to port %s\n", pPvt->portName); return; } @@ -129,26 +129,26 @@ static void echoWriter(myData *pPvt) nread = epicsMessageQueueReceive(pPvt->msgQueue, buffer, MESSAGE_SIZE); if (nread < 0) { asynPrint(pasynUser, ASYN_TRACE_ERROR, - "echoWriter: error from epicsMessageQueueReceive: %s: %d\n", + "echoWriter: error from epicsMessageQueueReceive: %s: %d\n", pPvt->portName, status); } - status = pasynOctetSyncIO->write(pasynUser, buffer, strlen(buffer), + status = pasynOctetSyncIO->write(pasynUser, buffer, strlen(buffer), WRITE_TIMEOUT, &nwrite); if (status) { asynPrint(pasynUser, ASYN_TRACE_ERROR, - "echoWriter: write error on: %s: %s\n", + "echoWriter: write error on: %s: %s\n", pPvt->portName, pasynUser->errorMessage); } } } - + static void connectionCallback(void *drvPvt, asynUser *pasynUser, char *portName, size_t len, int eomReason) { myData *pPvt = (myData *)drvPvt; myData *newPvt = calloc(1, sizeof(myData)); - asynPrint(pasynUser, ASYN_TRACE_FLOW, + asynPrint(pasynUser, ASYN_TRACE_FLOW, "ipEchoServer: connectionCallback, portName=%s\n", portName); epicsMutexLock(pPvt->mutexId); /* Make a copy of myData, with new portName */ @@ -193,9 +193,9 @@ static void ipEchoServer(const char *portName, int readTimeout) printf("%s driver not supported\n",asynOctetType); return; } - if (readTimeout == 0) + if (readTimeout == 0) pPvt->readTimeout = READ_TIMEOUT; - else + else pPvt->readTimeout = readTimeout/1000.; pPvt->pasynOctet = (asynOctet *)pasynInterface->pinterface; pPvt->octetPvt = pasynInterface->drvPvt; @@ -214,8 +214,8 @@ static const iocshArg *const ipEchoServerArgs[] = { &ipEchoServerArg0, &ipEchoServerArg1}; static const iocshFuncDef ipEchoServerDef = {"ipEchoServer2", 2, ipEchoServerArgs}; -static void ipEchoServerCall(const iocshArgBuf * args) -{ +static void ipEchoServerCall(const iocshArgBuf * args) +{ ipEchoServer(args[0].sval, args[1].ival); } diff --git a/testIPServerApp/src/testIPServerMain.cpp b/testIPServerApp/src/testIPServerMain.cpp index ae0ecb6..fe4f105 100644 --- a/testIPServerApp/src/testIPServerMain.cpp +++ b/testIPServerApp/src/testIPServerMain.cpp @@ -13,7 +13,7 @@ int main(int argc,char *argv[]) { - if(argc>=2) { + if(argc>=2) { iocsh(argv[1]); epicsThreadSleep(.2); } diff --git a/testManagerApp/testManager.c b/testManagerApp/testManager.c index c6b5026..91c9790 100644 --- a/testManagerApp/testManager.c +++ b/testManagerApp/testManager.c @@ -61,7 +61,7 @@ int checkStatus(asynStatus status,threadInfo *pthreadInfo,const char *message) pthreadInfo->threadName,message,pcmdInfo->pasynUser->errorMessage); return 1; } - + static void connectCallback(asynUser *pasynUser) { cmdInfo *pcmdInfo = (cmdInfo *)pasynUser->userPvt; @@ -123,7 +123,7 @@ static void blockTest(asynUser *pasynUser) status = pasynManager->unblockProcessCallback(pasynUser,0); if(checkStatus(status,pthreadInfo,"testBlock")) return; } - + static void busyCallback(asynUser *pasynUser) { asynStatus status; @@ -211,7 +211,7 @@ static void cancelTest(asynUser *pasynUser) pthreadInfo->threadName,pcmdInfo->message,wasQueued); if(!wasQueued) epicsEventMustWait(pcmdInfo->callbackDone); } - + static void timeoutCallback(asynUser *pasynUser) { cmdInfo *pcmdInfo = (cmdInfo *)pasynUser->userPvt; @@ -261,7 +261,7 @@ static void workThread(threadInfo *pthreadInfo) } epicsEventSignal(pthreadInfo->done); } - + static const char *thread = "thread"; static int testInit(const char *port,int addr, cmdInfo **ppcmdInfo, threadInfo **ppthreadInfo,int ind,FILE *file) @@ -318,7 +318,7 @@ static int testInit(const char *port,int addr, pthreadInfo->pcmdInfo = pcmdInfo; return 0; } - + static void testManager(const char *port,int addr,FILE *file) { cmdInfo *pacmdInfo[2],*pcmdInfo; @@ -384,14 +384,14 @@ static void testManager(const char *port,int addr,FILE *file) return; } pcmdInfo->pasynUser = pasynUserSave; - + } status = pasynManager->freeAsynUser(pasynUser); if(status) { printf("freeAsynUser failed %s\n",pasynUser->errorMessage); return; } - + pasynUser = pacmdInfo[0]->pasynUser; pasynManager->canBlock(pasynUser,&yesNo); if(!yesNo) { @@ -454,7 +454,7 @@ static void testManager(const char *port,int addr,FILE *file) pasynManager->memFree(pcmdInfo,sizeof(cmdInfo)); } } - + static const iocshArg testManagerArg0 = {"port", iocshArgString}; static const iocshArg testManagerArg1 = {"addr", iocshArgInt}; static const iocshArg testManagerArg2 = {"reportFile", iocshArgString}; @@ -495,7 +495,7 @@ static void testManagerAllPortsCall(const iocshArgBuf * args) printf("could not open %s %s\n",filename,strerror(errno)); return; } - } + } testManager("cantBlockSingle",0,file); testManager("cantBlockMulti",0,file); testManager("canBlockSingle",0,file); diff --git a/testManagerApp/testManagerDriver.c b/testManagerApp/testManagerDriver.c index 7ddf163..e2035f1 100644 --- a/testManagerApp/testManagerDriver.c +++ b/testManagerApp/testManagerDriver.c @@ -9,7 +9,7 @@ ***********************************************************************/ /*test driver for asyn support*/ -/* +/* * Author: Marty Kraimer */ @@ -30,13 +30,13 @@ #define NUM_DEVICES 2 typedef struct testManagerPvt { - int deviceConnected[NUM_DEVICES]; + int deviceConnected[NUM_DEVICES]; const char *portName; int connected; int multiDevice; asynInterface common; }testManagerPvt; - + /* init routine */ static int testManagerDriverInit(const char *dn, int canBlock, int noAutoConnect,int multiDevice); @@ -46,7 +46,7 @@ static void report(void *drvPvt,FILE *fp,int details); static asynStatus connect(void *drvPvt,asynUser *pasynUser); static asynStatus disconnect(void *drvPvt,asynUser *pasynUser); static asynCommon asyn = { report, connect, disconnect }; - + static int testManagerDriverInit(const char *dn, int canBlock, int noAutoConnect,int multiDevice) { @@ -98,7 +98,7 @@ static void report(void *drvPvt,FILE *fp,int details) (ptestManagerPvt->deviceConnected[i] ? "Yes" : "No")); } } - + static asynStatus connect(void *drvPvt,asynUser *pasynUser) { testManagerPvt *ptestManagerPvt = (testManagerPvt *)drvPvt; @@ -147,7 +147,7 @@ static asynStatus connect(void *drvPvt,asynUser *pasynUser) pasynManager->exceptionConnect(pasynUser); return(asynSuccess); } - + static asynStatus disconnect(void *drvPvt,asynUser *pasynUser) { testManagerPvt *ptestManagerPvt = (testManagerPvt *)drvPvt; @@ -196,7 +196,7 @@ static asynStatus disconnect(void *drvPvt,asynUser *pasynUser) pasynManager->exceptionDisconnect(pasynUser); return(asynSuccess); } - + /* register testManagerDriverInit*/ static const iocshArg testManagerDriverInitArg0 = { "portName", iocshArgString }; static const iocshArg testManagerDriverInitArg1 = { "canBlock", iocshArgInt }; diff --git a/testManagerApp/testManagerMain.cpp b/testManagerApp/testManagerMain.cpp index ae0ecb6..fe4f105 100644 --- a/testManagerApp/testManagerMain.cpp +++ b/testManagerApp/testManagerMain.cpp @@ -13,7 +13,7 @@ int main(int argc,char *argv[]) { - if(argc>=2) { + if(argc>=2) { iocsh(argv[1]); epicsThreadSleep(.2); } diff --git a/testOutputCallbackApp/src/testOutputCallback.cpp b/testOutputCallbackApp/src/testOutputCallback.cpp index 9b1b014..2110007 100644 --- a/testOutputCallbackApp/src/testOutputCallback.cpp +++ b/testOutputCallbackApp/src/testOutputCallback.cpp @@ -1,6 +1,6 @@ /* * testOutputCallback.cpp - * + * * Asyn driver that inherits from the asynPortDriver class to test output records using callbacks * The output records must have the info tag asyn:READBACK * It tests the following: @@ -39,9 +39,9 @@ static void callbackThreadC(void *pPvt) /** Constructor for the testOutputCallback class. * Calls constructor for the asynPortDriver base class. * \param[in] portName The name of the asyn port driver to be created. */ -testOutputCallback::testOutputCallback(const char *portName, int canBlock) - : asynPortDriver(portName, - 1, /* maxAddr */ +testOutputCallback::testOutputCallback(const char *portName, int canBlock) + : asynPortDriver(portName, + 1, /* maxAddr */ /* Interface mask */ asynInt32Mask | asynFloat64Mask | asynUInt32DigitalMask | asynOctetMask | asynDrvUserMask, /* Interrupt mask */ @@ -50,7 +50,7 @@ testOutputCallback::testOutputCallback(const char *portName, int canBlock) 1, /* Autoconnect */ 0, /* Default priority */ 0) /* Default stack size*/, - numCallbacks_(1), sleepTime_(0.) + numCallbacks_(1), sleepTime_(0.) { createParam(P_Int32ValueString, asynParamInt32, &P_Int32Value); createParam(P_Int32BinaryValueString, asynParamInt32, &P_Int32BinaryValue); @@ -60,10 +60,10 @@ testOutputCallback::testOutputCallback(const char *portName, int canBlock) createParam(P_NumCallbacksString, asynParamInt32, &P_NumCallbacks); createParam(P_SleepTimeString, asynParamFloat64, &P_SleepTime); createParam(P_TriggerCallbacksString, asynParamInt32, &P_TriggerCallbacks); - + setIntegerParam(P_NumCallbacks, numCallbacks_); setDoubleParam(P_SleepTime, sleepTime_); - + callbackEvent_ = epicsEventCreate(epicsEventEmpty); epicsThreadCreate("callbackThread", epicsThreadPriorityMedium, @@ -106,7 +106,7 @@ asynStatus testOutputCallback::writeFloat64(asynUser *pasynUser, epicsFloat64 va setDoubleParam(function, value); if (function == P_Float64Value) { doFloat64Callbacks(); - } + } else if (function == P_SleepTime) { sleepTime_ = value; } diff --git a/testOutputCallbackApp/src/testOutputCallback.h b/testOutputCallbackApp/src/testOutputCallback.h index e6f1250..7ac4293 100644 --- a/testOutputCallbackApp/src/testOutputCallback.h +++ b/testOutputCallbackApp/src/testOutputCallback.h @@ -1,6 +1,6 @@ /* * testOutputCallback.h - * + * * Asyn driver that inherits from the asynPortDriver class to test output records using callbacks * @@ -8,7 +8,7 @@ * * Created November 9, 2017 */ - + #include #include diff --git a/testOutputCallbackApp/src/testOutputCallbackMain.cpp b/testOutputCallbackApp/src/testOutputCallbackMain.cpp index ae0ecb6..fe4f105 100644 --- a/testOutputCallbackApp/src/testOutputCallbackMain.cpp +++ b/testOutputCallbackApp/src/testOutputCallbackMain.cpp @@ -13,7 +13,7 @@ int main(int argc,char *argv[]) { - if(argc>=2) { + if(argc>=2) { iocsh(argv[1]); epicsThreadSleep(.2); } diff --git a/testOutputReadbackApp/src/testOutputReadback.cpp b/testOutputReadbackApp/src/testOutputReadback.cpp index c54cd61..daf6dad 100644 --- a/testOutputReadbackApp/src/testOutputReadback.cpp +++ b/testOutputReadbackApp/src/testOutputReadback.cpp @@ -1,6 +1,6 @@ /* * testOutputReadback.cpp - * + * * Asyn driver that inherits from the asynPortDriver class to test error handling in both normally scanned * and I/O Intr scanned records * @@ -22,9 +22,9 @@ /** Constructor for the testOutputReadback class. * Calls constructor for the asynPortDriver base class. * \param[in] portName The name of the asyn port driver to be created. */ -testOutputReadback::testOutputReadback(const char *portName, int initialReadStatus) - : asynPortDriver(portName, - 1, /* maxAddr */ +testOutputReadback::testOutputReadback(const char *portName, int initialReadStatus) + : asynPortDriver(portName, + 1, /* maxAddr */ /* Interface mask */ asynInt32Mask | asynFloat64Mask | asynUInt32DigitalMask | asynDrvUserMask, /* Interrupt mask */ @@ -33,7 +33,7 @@ testOutputReadback::testOutputReadback(const char *portName, int initialReadStat 1, /* Autoconnect */ 0, /* Default priority */ 0) /* Default stack size*/, - initialReadStatus_((asynStatus)initialReadStatus) + initialReadStatus_((asynStatus)initialReadStatus) { createParam(P_Int32ValueString, asynParamInt32, &P_Int32Value); createParam(P_BinaryInt32ValueString, asynParamInt32, &P_BinaryInt32Value); @@ -42,7 +42,7 @@ testOutputReadback::testOutputReadback(const char *portName, int initialReadStat createParam(P_UInt32DigitalValueString, asynParamUInt32Digital, &P_UInt32DigitalValue); createParam(P_BinaryUInt32DigitalValueString, asynParamUInt32Digital, &P_BinaryUInt32DigitalValue); createParam(P_MultibitUInt32DigitalValueString, asynParamUInt32Digital, &P_MultibitUInt32DigitalValue); - + setIntegerParam (P_Int32Value, 7); setParamStatus (P_Int32Value, asynSuccess); setIntegerParam (P_BinaryInt32Value, 1); @@ -57,12 +57,12 @@ testOutputReadback::testOutputReadback(const char *portName, int initialReadStat setParamStatus (P_BinaryUInt32DigitalValue, asynSuccess); setUIntDigitalParam(P_MultibitUInt32DigitalValue, (epicsUInt32)0x2, 0xFFFFFFFF, 0xFFFFFFFF); setParamStatus (P_BinaryUInt32DigitalValue, asynSuccess); - + } asynStatus testOutputReadback::readInt32(asynUser *pasynUser, epicsInt32 *value) { - if (initialReadStatus_) + if (initialReadStatus_) return initialReadStatus_; else return asynPortDriver::readInt32(pasynUser, value); @@ -70,7 +70,7 @@ asynStatus testOutputReadback::readInt32(asynUser *pasynUser, epicsInt32 *value) asynStatus testOutputReadback::readFloat64(asynUser *pasynUser, epicsFloat64 *value) { - if (initialReadStatus_) + if (initialReadStatus_) return initialReadStatus_; else return asynPortDriver::readFloat64(pasynUser, value); @@ -78,7 +78,7 @@ asynStatus testOutputReadback::readFloat64(asynUser *pasynUser, epicsFloat64 *va asynStatus testOutputReadback::readUInt32Digital(asynUser *pasynUser, epicsUInt32 *value, epicsUInt32 mask) { - if (initialReadStatus_) + if (initialReadStatus_) return initialReadStatus_; else return asynPortDriver::readUInt32Digital(pasynUser, value, mask); diff --git a/testOutputReadbackApp/src/testOutputReadback.h b/testOutputReadbackApp/src/testOutputReadback.h index 7232233..f68235a 100644 --- a/testOutputReadbackApp/src/testOutputReadback.h +++ b/testOutputReadbackApp/src/testOutputReadback.h @@ -1,6 +1,6 @@ /* * testOutputReadback.h - * + * * Asyn driver that inherits from the asynPortDriver class to test error handling in both normally scanned * and I/O Intr scanned records * @@ -38,7 +38,7 @@ class testOutputReadback : public asynPortDriver { int P_UInt32DigitalValue; int P_BinaryUInt32DigitalValue; int P_MultibitUInt32DigitalValue; - + private: /* Our data */ asynStatus initialReadStatus_; diff --git a/testOutputReadbackApp/src/testOutputReadbackMain.cpp b/testOutputReadbackApp/src/testOutputReadbackMain.cpp index ae0ecb6..fe4f105 100644 --- a/testOutputReadbackApp/src/testOutputReadbackMain.cpp +++ b/testOutputReadbackApp/src/testOutputReadbackMain.cpp @@ -13,7 +13,7 @@ int main(int argc,char *argv[]) { - if(argc>=2) { + if(argc>=2) { iocsh(argv[1]); epicsThreadSleep(.2); } diff --git a/testUsbtmcApp/src/Makefile b/testUsbtmcApp/src/Makefile index 1dc59ca..970021d 100644 --- a/testUsbtmcApp/src/Makefile +++ b/testUsbtmcApp/src/Makefile @@ -36,6 +36,7 @@ testUSBTMC_SRCS_vxWorks += -nil- # Finally link to the EPICS Base libraries testUSBTMC_LIBS += $(EPICS_BASE_IOC_LIBS) +testUSBTMC_SYS_LIBS += usb-1.0 endif diff --git a/testUsbtmcApp/src/testUSBTMCMain.cpp b/testUsbtmcApp/src/testUSBTMCMain.cpp index 1e8f7dd..39fe887 100644 --- a/testUsbtmcApp/src/testUSBTMCMain.cpp +++ b/testUsbtmcApp/src/testUSBTMCMain.cpp @@ -13,7 +13,7 @@ int main(int argc,char *argv[]) { - if(argc>=2) { + if(argc>=2) { iocsh(argv[1]); epicsThreadSleep(.2); }