From b011c286aae1fddfcb3613c222a45da05926045f Mon Sep 17 00:00:00 2001
From: Dirk Zimoch
Date: Mon, 30 Jul 2018 16:47:17 +0200
Subject: [PATCH] add streamReinit function
---
GNUmakefile | 9 ++++--
documentation/processing.html | 51 ++++++++++++++++++++++------------
documentation/protocol.html | 9 +-----
src/AsynDriverInterface.cc | 52 +++++++++++++++++++++++++++++++++++
src/Makefile | 3 ++
5 files changed, 96 insertions(+), 28 deletions(-)
diff --git a/GNUmakefile b/GNUmakefile
index f829db0..43aedfb 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -9,10 +9,10 @@ BUILDCLASSES += Linux
DOCUDIR = documentation
-ifdef EPICSVERSION
-ifndef RECORDTYPES
PCRE=1
ASYN=1
+ifdef EPICSVERSION
+ifndef RECORDTYPES
include src/CONFIG_STREAM
export RECORDTYPES BUSSES FORMATS
endif
@@ -44,5 +44,10 @@ export DBDFILES = streamSup.dbd
streamSup.dbd:
@echo Creating $@ from $(RECORDTYPES)
$(PERL) ../src/makedbd.pl $(RECORDTYPES) > $@
+ifdef BASE_3_14
+ifdef ASYN
+ echo "registrar(AsynDriverInterfaceRegistrar)" >> $@
+endif
+endif
endif
diff --git a/documentation/processing.html b/documentation/processing.html
index 73362ba..5c27473 100644
--- a/documentation/processing.html
+++ b/documentation/processing.html
@@ -54,9 +54,9 @@ its SEVR
field set to INVALID
and its
TIMEOUT
-
- The device could not be locked (
LockTimeout
) or the
- device did not reply in time
- (ReplyTimeout
).
+ The device could not be locked (LockTimeout
) because
+ other records are keeping the device busy or the device did not reply
+ in time (ReplyTimeout
).
WRITE
-
@@ -96,13 +96,14 @@ will be set according to the original error.
2. Initialization
-Often, it is required to initialize records from the hardware after
+Often, it is useful to initialize records from the hardware after
booting the IOC, especially output records.
For this purpose, initialization is formally handled as an
exception.
The @init
handler is called as part of the
initRecord()
function during iocInit
-before any scan task starts.
+before any scan task starts and may be re-run
+later under circumstances listed below.
In contrast to normal processing, the protocol
@@ -120,7 +121,7 @@ If the handler fails, the record remains uninitialized:
The @init
handler has nothing to do with the
PINI
field.
The handler does not process the record nor does it trigger
-forward links or other PP links.
+forward links or any links with the PP
flag.
It runs before PINI
is handled.
If the record has PINI=YES
, the PINI
processing is a normal processing after the
@@ -147,19 +148,33 @@ read from a constant INP
or DOL
field,
or restored from a bump-less reboot system
(e.g. autosave from the synApps package).
-
-The @init
handler is called again in the following situations:
+
+ The @init
handler is called in the following situations:
+
+ - At startup by
iocInit
during record initialization
+ as described above.
+ - When the IOC is resumed with
iocRun
(after
+ beeing paused with iocPause
) before the scan tasks
+ restart and before records with PINI=RUN
are processed.
+ - When the protocol is
+ reloaded for example with
+
streamReload ["recordname"]
.
+ - When StreamDevice detects that the device has
+ reconnected (after being disconnected). This includes the case that
+ the device was disconnected when the IOC started.
+ Be aware that some drivers test the connection only periodically,
+ e.g. the asynIPPort driver tests it every few seconds.
+ Thus there may be a small delay between the device being online
+ and the record re-initializing.
+
- When
streamReinit
+ "asynPortname"[,addr]
is called
+ (if using an asynDriver port).
+ - When the "magic value"
2
is written to the
+ .PROC
field of the record.
+ In this case the record is processed and thus its FLNK
+ and links with the PP
flag are triggered.
+
-
-- The device driver informs StreamDevice that the device has
-reconnected after it had been disconnected. This is only detectable for
-some types of busses.
-
- The IOC is resumed with
iocRun
after it had
-been paused with iocPause
. This requires EPICS 3.14.11 or higher.
- - The record protocol has been reloaded
-using the shell function
streamReload
or the subroutine
-record funtion streamReloadSub
.
-
3. I/O Intr
diff --git a/documentation/protocol.html b/documentation/protocol.html
index 4a73ed7..b5e24e0 100644
--- a/documentation/protocol.html
+++ b/documentation/protocol.html
@@ -558,15 +558,8 @@ There is a fixed set of exception handler names starting with
Not really an exception but formally specified in the same syntax.
This handler can be used to initialize an output record with a value read from
the device.
- Also see chapter Record Processing.
+ See also chapter Record Processing.
- It is called at startup by iocInit
during record
- initialization and again whenever StreamDevice
- detects that the device has reconnected after a disconnect or when the
- IOC is resumed with iocRun
after beeing paused or
- when the protocol has been reloaded
- or when the "magic value" 2
is written to the .PROC
- field.
Example:
diff --git a/src/AsynDriverInterface.cc b/src/AsynDriverInterface.cc
index 1b1b325..87523c5 100644
--- a/src/AsynDriverInterface.cc
+++ b/src/AsynDriverInterface.cc
@@ -32,6 +32,8 @@ extern "C" {
#include "epicsAssert.h"
#include "epicsTime.h"
#include "epicsTimer.h"
+#include "epicsStdioRedirect.h"
+#include "iocsh.h"
#endif
#include "asynDriver.h"
@@ -1558,3 +1560,53 @@ handleTimeout()
clientName(), toStr(ioAction));
}
}
+
+extern "C" long streamReinit(const char* portname, int addr)
+{
+ if (!portname)
+ {
+ fprintf(stderr, "Usage: streamReinit \"portname\", [addr]\n");
+ return -1;
+ }
+ asynUser* pasynUser = pasynManager->createAsynUser(NULL, NULL);
+ if (!pasynUser)
+ {
+ fprintf(stderr, "Can't create asynUser\n");
+ return -1;
+ }
+ asynStatus status = pasynManager->connectDevice(pasynUser, portname, addr);
+ if (status == asynSuccess)
+ status = pasynManager->exceptionDisconnect(pasynUser);
+ if (status == asynSuccess)
+ status = pasynManager->exceptionConnect(pasynUser);
+ if (status != asynSuccess)
+ fprintf(stderr, "%s\n", pasynUser->errorMessage);
+ pasynManager->disconnect(pasynUser);
+ pasynManager->freeAsynUser(pasynUser);
+ return status;
+}
+
+#ifndef EPICS_3_13
+static const iocshArg streamReinitArg0 =
+ { "portname", iocshArgString };
+static const iocshArg streamReinitArg1 =
+ { "[addr]", iocshArgInt };
+static const iocshArg * const streamReinitArgs[] =
+ { &streamReinitArg0, &streamReinitArg1 };
+static const iocshFuncDef streamReinitDef =
+ { "streamReinit", 2, streamReinitArgs };
+
+void streamReinitFunc(const iocshArgBuf *args)
+{
+ streamReinit(args[0].sval, args[1].ival);
+}
+static void AsynDriverInterfaceRegistrar ()
+{
+ iocshRegister(&streamReinitDef, streamReinitFunc);
+}
+
+extern "C" {
+epicsExportRegistrar(AsynDriverInterfaceRegistrar);
+}
+
+#endif
diff --git a/src/Makefile b/src/Makefile
index 00e6b59..3d59f95 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -87,6 +87,9 @@ streamReferences: ../CONFIG_STREAM
# create stream.dbd from all RECORDTYPES
$(COMMON_DIR)/$(LIBRARY_DEFAULT).dbd: ../CONFIG_STREAM
$(PERL) ../makedbd.pl $(RECORDTYPES) > $@
+ifdef ASYN
+ echo "registrar(AsynDriverInterfaceRegistrar)" >> $@
+endif
$(LIBRARY_DEFAULT).dbd$(DEP): ../CONFIG_STREAM
echo $(LIBRARY_DEFAULT).dbd: $< > $@