Giter VIP home page Giter VIP logo

streamdevice's Introduction

StreamDevice

StreamDevice is a generic EPICS device support for devices with a "byte stream" based communication interface. That means devices that can be controlled by sending and receiving strings (in the broadest sense, including non-printable characters and even null-bytes). Examples for this type of communication interface are serial line (RS-232, RS-485, ...), IEEE-488 (also known as GPIB or HP-IB), and telnet-like TCP/IP.

StreamDevice is not limited to a specific device type or manufacturer nor is it necessary to re-compile anything to support a new device type. Instead, it can be configured for any device type with protocol files in plain ASCII text which describes the commands a device understands and the replies it sends.

For a full documentation see https://paulscherrerinstitute.github.io/StreamDevice.

Licensing

StreamDevice is free software: You can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

StreamDevice is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with StreamDevice. If not, see https://www.gnu.org/licenses/.

streamdevice's People

Contributors

bhill-slac avatar darcato avatar dirk-zimoch avatar dominicoram avatar freddieakeroyd avatar henrique-silva avatar huyong1979 avatar jeonghanlee avatar klemenv avatar krisztianloki avatar marciodo avatar markrivers avatar mdavidsaver avatar mesamike avatar ralphlange avatar shadowguy avatar slacer-garth avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

streamdevice's Issues

Improve checksum converters

  • Allow any type of CRC sum by simply giving the polynom code, init and xor value. Calculate lookup table at init instead of having it hard coded.
  • Allow any type of formatting of the result by specifying a format like %02x, %03d, etc.

Examples: %<crc 0x1021,0x1D0F,0xFFFF,%02X> %<xor %03d>

IOC lockRequest messages and inconsistent record scanning

Hi,
I'm in the early stages of characterising an issue I've been seeing but in case it's something obvious I thought I would raise it now. Our version of streamDevice is 2.8.18.

We have rolled this version of streamDevice out on a few IOCs and haven't had any issues except for on one IOC. The IOC in question monitors how long it takes to get a response from a device, it reports that some readback PVs aren't getting updated as fast as they were on an older version (2.5). The record in question and an "ai" record and has a scan rate of 0.2 seconds. By setting some asyn trace masks I was able to see exactly when the record was querying the hardware, below is the time in seconds between these queries:

2.8.18:
avg 0.458166666666666
max 1.569
stdev 0.385062690171769

2.5:
avg 0.342230769230769
max 0.777
stdev 0.220675811463744

As you can see there doesn't appear to be a big difference in the average but the max is double. It's also less consistent as shown in the stdev.

This particular IOC does also give the occasional error, on boot and during operation:

2021/03/24 14:26:57.778463 robot_serial BL04I-MO-ROBOT-01:CNTL_ERR_CODE lockRequest: status returned to normal 2021/03/24 14:26:56.867206 robot_serial BL04I-MO-ROBOT-01:DRYTMR lockRequest: status returned to normal 2021/03/24 14:26:56.867218 robot_serial BL04I-MO-ROBOT-01:DRY_SPEED lockRequest: status returned to normal 2021/03/24 14:26:56.867229 robot_serial BL04I-MO-ROBOT-01:DRY_TIME lockRequest: status returned to normal

I don't know if this is related.

It should be pointed out that i've seen this behaviour by only changing the streamDevice dependency.

I appreciate this isn't much to go on but I will investigate further, I just thought i'd raise the issue now in case you can see anything obvious.

Thanks

device support should set a non-zero status when startProtocol fails

bool Stream::process() initializes the status to NO_ALARM, then calls startProtocol, and if that fails sets recGblSetSevr(record, status, INVALID_ALARM). This means the record will have STAT=NO_ALARM and SEVR=INVALID which is a bit confusing.

Here is a fix, using the COMM_ALARM status instead.

diff --git a/src/StreamEpics.cc b/src/StreamEpics.cc
index 9117fd9..1f16e2d 100644
--- a/src/StreamEpics.cc
+++ b/src/StreamEpics.cc
@@ -732,7 +732,7 @@ process()
         return false;
     }
     debug("Stream::process(%s) start\n", name());
-    status = NO_ALARM;
+    status = COMM_ALARM;
     convert = OK;
     record->pact = true;
     if (!startProtocol(StreamCore::StartNormal))

An error occurred while installing StreamDevice

System: CentOS7--Linux
When installing StreamDevice, make an error when compiling:
/usr/bin/g++ -D_GNU_SOURCE -D_DEFAULT_SOURCE -D_X86_64_ -DUNIX -Dlinux -DUSE_TYPED_RSET -DSTREAM_INTERNAL -O3 -g -Wall -mtune=generic -m64 -fPIC -I. -I../O.Common -I. -I . -I.. -I../../include/compiler/gcc -I../../include/os/Linux -I../../include -I/home/lytt/local/epics /base/include/compiler/gcc -I/home/lytt/local/epics/base/include/os/Linux -I/home/lytt/local/epics/base/include -c ../AsynDriverInterface.cc
../AsynDriverInterface.cc:41:24: Fatal error: asynDriver.h: No such file or directory
#include "asynDriver.h"
Excuse me, where is the problem? How to solve it? Please guide me! Thank you!

stream is installing into $(TOP)/../lib rather than into $(TOP)/lib

This problem is described in this tech-talk thread: https://epics.anl.gov/tech-talk/2020/msg01372.php

I am running stream 2.8.14. I am having a problem that when I build it, the files get installed into $(TOP)/../lib, not into $(TOP)/lib.

This is the git diff of my files and the ones in 2.8.14. I have only commented out streamApp in the top-level Makefile, and modified configure/RELEASE for new locations.

corvette:~/devel/stream>git diff -w -b 2.8.14
diff --git a/Makefile b/Makefile
index 4e56eec..1312552 100644
--- a/Makefile
+++ b/Makefile
@@ -38,7 +38,7 @@ else
endif
DIRS += src
-DIRS += streamApp
+#DIRS += streamApp
streamApp_DEPEND_DIRS = src
include $(CONFIG)/RULES_TOP

diff --git a/configure/RELEASE b/configure/RELEASE
index 72efa75..5b80a63 100644
--- a/configure/RELEASE
+++ b/configure/RELEASE
@@ -14,15 +14,15 @@ TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
# define INSTALL_LOCATION_APP here
#INSTALL_LOCATION_APP=<fullpathname>

-SUPPORT=$(TOP)/..
+SUPPORT=/corvette/home/epics/devel
-include $(TOP)/../configure/SUPPORT.$(EPICS_HOST_ARCH)
-ASYN=$(SUPPORT)/asyn4-36
-CALC=$(SUPPORT)/calc-3-7
+ASYN=$(SUPPORT)/asyn-4-40
+CALC=$(SUPPORT)/calc-3-7-3
PCRE=$(SUPPORT)/pcre-7-2

 # EPICS_BASE usually appears last so other apps can override stuff:
-EPICS_BASE=/usr/local/epics/base-7.0.3
+EPICS_BASE=/corvette/usr/local/epics-devel/base-7.0.4

# These lines allow developers to override these RELEASE settings
# without having to modify this file directly.

I do a realclean realuninstall and do an ls in stream/ and in stream/../lib. There are no lib/ directories.

corvette:~/devel/stream>make -sj realclean realuninstall
If you are not using the PSI build environment, GNUmakefile can be removed.

corvette:~/devel/stream>ls
GNUmakefile  LICENSE  LICENSE.LESSER  Makefile  README.md  config  configure  docs  src  streamApp

corvette:~/devel/stream>ls ../lib
ls: cannot access ../lib: No such file or directory

I then do the build. After the build there is no stream/lib directory, but there is a stream/../lib/linux-x86_64 directory containing the stream libraries.

corvette:~/devel/stream>make -sj
If you are not using the PSI build environment, GNUmakefile can be removed.
Creating ../O.Common/StreamVersion.h from git tag

corvette:~/devel/stream>ls
GNUmakefile  LICENSE  LICENSE.LESSER  Makefile  README.md  config  configure  docs  src  streamApp

corvette:~/devel/stream>ls ../lib
linux-x86_64

corvette:~/devel/stream>ls ../lib/linux-x86_64/
libstream.a  libstream.so

If I search for INSTALL_LOCATION in stream/configure I don’t see the problem.

corvette:~/devel/stream/configure>grep INSTALL_LOCATION *
CONFIG_APP:INSTALL_LOCATION = $(TOP)
CONFIG_APP:ifdef INSTALL_LOCATION_APP
CONFIG_APP:INSTALL_LOCATION = $(INSTALL_LOCATION_APP)
grep: O.Common: Is a directory
grep: O.linux-x86_64: Is a directory
RELEASE:# define INSTALL_LOCATION_APP here
RELEASE:#INSTALL_LOCATION_APP=<fullpathname>

Am I doing something wrong, or why does the distribution version of stream install into $(TOP)/..?

StreamDevice 2.18.14 failed to compile with EPICS 7.0.4 on windows x64

2.8.13 compiled fine, but 2.18.14 gives me the following error: (windows 10 x64):
cl -nologo -FC -D__STDC__=0 -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -DUSE_TYPED_RSET -DSTREAM_INTERNAL -Ox -GL -Oy- -W3 -MD -DEPICS_BUILD_DLL -DEPICS_CALL_DLL -I. -I../O.Common -I. -I. -I.. -I../../../include/compiler/msvc -I../../../include/os/WIN32 -I../../../include -IC:\epics\modules\synApps_6_1_epics7\support/include -IC:\epics\base-7.0.4/include/compiler/msvc -IC:\epics\base-7.0.4/include/os/WIN32 -IC:\epics\base-7.0.4/include -IC:\epics\modules\synApps_6_1_epics7\support/alive-R1-1-1/include -IC:\epics\modules\synApps_6_1_epics7\support/asyn-R4-38/include -IC:\epics\modules\synApps_6_1_epics7\support/autosave-R5-10/include/os/WIN32 -IC:\epics\modules\synApps_6_1_epics7\support/autosave-R5-10/include -IC:\epics\modules\synApps_6_1_epics7\support/busy-R1-7-2/include -IC:\epics\modules\synApps_6_1_epics7\support/calc-R3-7-4/include -IC:\epics\modules\synApps_6_1_epics7\support/camac-R2-7-1/include -IC:\epics\modules\synApps_6_1_epics7\support/dxp-R6-0/include -IC:\epics\modules\synApps_6_1_epics7\support/dxpSITORO-R1-2/include -IC:\epics\modules\synApps_6_1_epics7\support/iocStats-3-1-16/include/os/WIN32 -IC:\epics\modules\synApps_6_1_epics7\support/iocStats-3-1-16/include -IC:\epics\modules\synApps_6_1_epics7\support/ipac-2-15/include -IC:\epics\modules\synApps_6_1_epics7\support/ip330-R2-9/include -IC:\epics\modules\synApps_6_1_epics7\support/lua-R2-0/include -IC:\epics\modules\synApps_6_1_epics7\support/mca-R7-8/include/os/WIN32 -IC:\epics\modules\synApps_6_1_epics7\support/mca-R7-8/include -IC:\epics\modules\synApps_6_1_epics7\support/measComp-R2-3/include -IC:\epics\modules\synApps_6_1_epics7\support/modbus-R3-0/include -IC:\epics\modules\synApps_6_1_epics7\support/motor-R7-2-1/include -IC:\epics\modules\synApps_6_1_epics7\support/optics-R2-13-3/include -IC:\epics\modules\synApps_6_1_epics7\support/quadEM-R9-2-1/include -IC:\epics\modules\synApps_6_1_epics7\support/softGlue-R2-8-2/include -IC:\epics\modules\synApps_6_1_epics7\support/softGlueZynq-R2-0-2/include -IC:\epics\modules\synApps_6_1_epics7\support/sscan-R2-11-3/include -IC:\epics\modules\synApps_6_1_epics7\support/std-R3-6-1/include -IC:\epics\modules\synApps_6_1_epics7\support/vac-R1-9/include -IC:\epics\modules\synApps_6_1_epics7\support/vme-R2-9-2/include -IC:\epics\modules\synApps_6_1_epics7\support/areaDetector-R3-7/ADCore/include -IC:\epics\modules\synApps_6_1_epics7\support/areaDetector-R3-7/ADSupport/include/os/WIN32 -IC:\epics\modules\synApps_6_1_epics7\support/areaDetector-R3-7/ADSupport/include -IC:\epics\modules\synApps_6_1_epics7\support/areaDetector-R3-7/ADSimDetector/include -IC:\epics\modules\synApps_6_1_epics7\support/seq-2-2-6/include -IC:\epics\modules\synApps_6_1_epics7\support/allenBradley-2-3/include -c ../StreamVersion.c
StreamVersion.c
C:\epics\modules\synApps_6_1_epics7\support\StreamDevice-2-8-14\src\StreamVersion.c(31): error C2146: syntax error: missing ';' before identifier 'STREAM_DEV'
C:\epics\modules\synApps_6_1_epics7\support\StreamDevice-2-8-14\src\StreamVersion.c(32): error C2143: syntax error: missing '{' before 'string'
C:\epics\modules\synApps_6_1_epics7\support\StreamDevice-2-8-14\src\StreamVersion.c(32): error C2059: syntax error: 'string'
gmake[2]: *** [C:\epics\base-7.0.4/configure/RULES_BUILD:241: StreamVersion.obj] Error 2
gmake[2]: Leaving directory 'C:/epics/modules/synApps_6_1_epics7/support/StreamDevice-2-8-14/src/O.windows-x64'
gmake[1]: *** [C:\epics\base-7.0.4/configure/RULES_ARCHS:58: install.windows-x64] Error 2
gmake[1]: Leaving directory 'C:/epics/modules/synApps_6_1_epics7/support/StreamDevice-2-8-14/src'
gmake: *** [C:\epics\base-7.0.4/configure/RULES_DIRS:85: src.install] Error 2

2.8.16 not on branch

Hi,
I would like to merge the latest release onto our master branch but I see that this tag wasn't made on a branch that currently exists (or perhaps it's a local one). Was this intentional?
Thanks
Lee

Latest release is almost 2 years old

I noticed that the latest release is almost 2 years old and the project has received some commits since. Should the latest commit be used or the latest release? Maybe it's time for a new release?

Comma separated strings not separating correctly

Hi,

We are trying to accept a comma-separated response into a waveform of FTVL type STRING, but the strings are not separating correctly. The first 40 characters of the raw response are still being placed in element 0 of our record. If we modify our test server to use spaces, the waveform behaves correctly.
I have a test case for this here.

Below is our use case -- maybe we're doing something wrong?

Not-working protocol:
Terminator = LF;
ReplyTimeout = 20000;
Separator = ",";
getVersions {
out "GET VALUE VERSION AMP $1";
in "VALUE VERION AMP $1 %s";
}

Server:
received "GET VALUE VERSION AMP 1"
sending response "VALUE VERSION AMP 1 1000,1.2.3,1010,4.5.6,1011,7.8.9,1012,10.11.12,1013,13.14.15,1020,2.4.6,1021,4.6.8,1022,6.8.10,1023,10.12.14\n"

IOC:
epics>dbgf _FS1_CH01:RFA_D2137:FVSN_RD_ALL
DBR_STRING: "1000,1.2.3,1010,4.5.6,1011,7.8.9,1012,1"

Working protocol:
Terminator = LF;
ReplyTimeout = 20000;
Separator = "\_";
getVersions {
out "GET VALUE VERSION AMP $1";
in "VALUE VERION AMP $1 %s";
}

Server:
received "GET VALUE VERSION AMP 1"
sending response "VALUE VERSION AMP 1 1000 1.2.3 1010 4.5.6 1011 7.8.9 1012 10.11.12 1013 13.14.15 1020 2.4.6 1021 4.6.8 1022 6.8.10 1023 10.12.14\n"

IOC:
epics>dbgf _FS1_CH01:RFA_D2137:FVSN_RD_ALL
DBR_STRING[20]: "1000" "1.2.3" "1010" "4.5.6" "1011" "7.8.9"
"1012" "10.11.12" "1013" "13.14.15" "1020" "2.4.6"
"1021" "4.6.8" "1022" "6.8.10" "1023" "10.12.14"

StreamDevice resets asynTraceMask during init

Commit 8679dd5 introduced a reset of the asynTraceMask to 0 to avoid flooding. I don't think StreamDevice should alter the options set for another module (asyn). Normally the TraceMask should be 0 anyway if not set explicitly. In my case I set it directly after setting up the asyn port for development and debugging purpose. You can re-enable it after iocInit as stated in the comment, but this prevents messages send and received with @init to be printed.

Another similar thing is the newly introduced streamError variable which can be used to avoid message flooding. I really appreciate the possibility to disable these messages, but during normal operation you want to see them and they are very useful for analysis. My suggestion would be, to the the default value for streamError to 1, which equals to the behavior of older versions.

compile error from StreamVersion.c

I'm updating my docker image for synApps with EPICS base 7.0.4 and am
running into this compiler error. Do you know what can be the problem?

root@006b1d9d277b:/opt/synApps/support/StreamDevice-2-8-14# make
If you are not using the PSI build environment, GNUmakefile can be removed.
make -C ./src install
make[1]: Entering directory '/opt/synApps/support/StreamDevice-2-8-14/src'
make -C O.linux-x86_64 -f ../Makefile TOP=../../.. \
     T_A=linux-x86_64 install
make[2]: Entering directory 
'/opt/synApps/support/StreamDevice-2-8-14/src/O.linux-x86_64'
/usr/bin/gcc  -D_GNU_SOURCE -D_DEFAULT_SOURCE           -D_X86_64_ 
-DUNIX  -Dlinux    -DUSE_TYPED_RSET -DSTREAM_INTERNAL   -O3   -Wall 
-mtune=generic      -m64 -fPIC -I. -I../O.Common -I. -I. -I.. 
-I../../../include/compiler/gcc -I../../../include/os/Linux 
-I../../../include   -I/opt/synApps/support/include 
-I/opt/base/include/compiler/gcc -I/opt/base/include/os/Linux 
-I/opt/base/include   -I/opt/synApps/support/alive-master/include 
-I/opt/synApps/support/asyn-master/include 
-I/opt/synApps/support/autosave-master/include/os/Linux 
-I/opt/synApps/support/autosave-master/include 
-I/opt/synApps/support/busy-master/include 
-I/opt/synApps/support/calc-master/include 
-I/opt/synApps/support/iocStats-master/include/os/Linux 
-I/opt/synApps/support/iocStats-master/include 
-I/opt/synApps/support/ipac-master/include 
-I/opt/synApps/support/lua-master/include 
-I/opt/synApps/support/modbus-master/include 
-I/opt/synApps/support/motor-master/include 
-I/opt/synApps/support/optics-master/include 
-I/opt/synApps/support/sscan-master/include 
-I/opt/synApps/support/std-master/include 
-I/opt/synApps/support/areaDetector-master/ADCore/include 
-I/opt/synApps/support/areaDetector-master/ADSupport/include/os/Linux 
-I/opt/synApps/support/areaDetector-master/ADSupport/include 
-I/opt/synApps/support/seq-2-2-6/include        -c ../StreamVersion.c
../StreamVersion.c:31:5: error: expected ',' or ';' before 'STREAM_DEV'
    31 |     STREAM_DEV
       |     ^~~~~~~~~~
make[2]: *** [/opt/base/configure/RULES_BUILD:241: StreamVersion.o] Error 1
make[2]: Leaving directory 
'/opt/synApps/support/StreamDevice-2-8-14/src/O.linux-x86_64'
make[1]: *** [/opt/base/configure/RULES_ARCHS:58: install.linux-x86_64] 
Error 2
make[1]: Leaving directory '/opt/synApps/support/StreamDevice-2-8-14/src'
make: *** [/opt/base/configure/RULES_DIRS:85: src.install] Error 2
root@006b1d9d277b:/opt/synApps/support/StreamDevice-2-8-14#

The build is in Ubuntu 20.04 OS, 64-bit.

version compiles?
master fails
2.1.14 fails
2.1.12 compiles

testTimeStamp question

Hi,
I'm trying to get the tests in this module working and i'm stuck on testTimeStamp. Can someone tell me anything about the "Epics" package that's required by this test? Is it a TCL package? If so do you know where I can get it from?

Bogus "no EOS support" warning

I get bogus "no EOS support" warning messages even if no terminator is defined in the protocol (but asyn EOS processing is disabled). There are two issues with this warning:

  • As far as I can see StreamCore::compile() is called after AsynDriverInterface::connectToBus() so getInTerminator() will never* return non-NULL and the warning will never be printed.

*Except:

  • StreamCore does not initialize inTerminatorDefined so it can happen that getInTerminator() returns non-NULL (even if no terminator is defined in the protocol) and if noProcessEos was specified during asyn configuration AsynDriverInterface::connectToBus() will print this warning message

I will follow-up with a PR to fix the second issue.

Name collision in StreamCore.cc

There is a bug in StreamDevice 2.8.8 when compiling on macOS (10.13.6). The compiler reports the following problem when compiling StreamCore.cc:

../StreamCore.cc:29:19: error: redefinition of 'wait'
    end, in, out, wait, event, exec, connect, disconnect);
                  ^
/usr/include/sys/wait.h:248:7: note: previous definition is here
pid_t   wait(int *) __DARWIN_ALIAS_C(wait);
        ^
../StreamCore.cc:29:19: error: expression is not an integral constant expression
    end, in, out, wait, event, exec, connect, disconnect);
                  ^~~~
../MacroMagic.h:61:83: note: expanded from macro 'ENUM'
  ...type##ToStr(int x) {switch(x){MACRO_FOR_EACH(_CASE_LINE,__VA_ARGS__) def...
                                                             ^~~~~~~~~~~
../MacroMagic.h:55:15: note: expanded from macro 'MACRO_FOR_EACH'
        (x, ##__VA_ARGS__)
              ^~~~~~~~~~~

This problem is caused by the fact that on macOS stdlib.h includes wait.h which declares the wait function. This behavior can be avoided by passing -D_ANSI_SOURCE to the compiler, but doing that causes problems in other places, because it also leads to strncasecmp (and most likely some other functions) to be skipped.

A fix that worked for me is moving the enum definition into a private namespace and then only importing the symbols that do not collide, as implemented by the following patch:

diff -Naur stream-2.8.8.orig/src/StreamCore.cc stream-2.8.8/src/StreamCore.cc
--- stream-2.8.8.orig/src/StreamCore.cc	2018-11-27 13:45:27.000000000 +0100
+++ stream-2.8.8/src/StreamCore.cc	2018-12-11 19:25:13.000000000 +0100
@@ -25,8 +25,21 @@
 
 #define Z PRINTF_SIZE_T_PREFIX
 
+namespace streamDeviceEnum {
 ENUM (Commands,
     end, in, out, wait, event, exec, connect, disconnect);
+}
+
+using streamDeviceEnum::Commands;
+using streamDeviceEnum::CommandsToStr;
+using streamDeviceEnum::toStr;
+using streamDeviceEnum::end;
+using streamDeviceEnum::in;
+using streamDeviceEnum::out;
+using streamDeviceEnum::event;
+using streamDeviceEnum::exec;
+using streamDeviceEnum::connect;
+using streamDeviceEnum::disconnect;
 
 /// debug functions /////////////////////////////////////////////
 
@@ -50,7 +63,7 @@
                 c = StreamProtocolParser::printString(buffer, c);
                 buffer.append("\";\n");
                 break;
-            case wait:
+            case streamDeviceEnum::wait:
                 timeout = extract<unsigned long>(c);
                 buffer.print("    wait %ld; # ms\n", timeout);
                 break;
@@ -312,7 +325,7 @@
     }
     if (strcmp(command, "wait") == 0)
     {
-        buffer.append(wait);
+        buffer.append(streamDeviceEnum::wait);
         if (!protocol->compileNumber(timeout, args))
         {
             return false;
@@ -553,7 +566,7 @@
         case in:
             //// flags &= ~AcceptEvent;
             return evalIn();
-        case wait:
+        case streamDeviceEnum::wait:
             //// flags &= ~(AcceptInput|AcceptEvent);
             return evalWait();
         case event:

A more elegant solution would be to put the whole code into a namespace, but in this case we would also have to touch all the other files, so that everything belonging to StreamDevice is in the same namespace.

If you would like a PR for the patch included above, or for the alternate solution suggested by me, please let me know.

Stream device 2.8.20 builds failure in Windows x86

Building Stream device 2.8.20 on win32-x86 fails with the error

[2021-07-28T04:49:20.198Z] StreamEpics.cc
[2021-07-28T04:49:20.198Z] c:\instrument\apps\epics32\support\streamdevice\master\src\streamepics.cc(467) : error C2440: '=' : cannot convert from 'const char *(__stdcall *)(void)' to 'const char *(__cdecl *)(void)'
[2021-07-28T04:49:20.198Z]         This conversion requires a reinterpret_cast, a C-style cast or function-style cast

building on windows-x64 works fine.

The relevant line is

StreamGetThreadNameFunction = epicsThreadGetNameSelf;

The issue is caused by epicsThreadGetNameSelf being defined as epicsShareAPI resulting in it using the stdcall rather than default cdecl calling convention on x86, on x64 Microsoft removed stdcall and it was aliased to cdecl hence all compiles OK.

There are two options to fix this:

  • modify StreamGetThreadNameFunction signature to include epicsShareAPI, however any user defined alternative functions would also need to be declared epicsShareAPI too
  • create and assign a streamGetThreadNameDefaultFunction() wrapper function that just calls epicsThreadGetNameSelf()

@dirk-zimoch I am happy to submit a PR, I just wanted to check which your preference was

STREAM_PROTOCOL_PATH is incorrectly parsed on Windows

StreamProtocol.cc contains this code:

#ifdef windows
     const char pathseparator = ';';
     const char dirseparator = '\\';
 #else

The problem is that "windows" is not defined when building the code, at least not with Visual Studio 2017 and base 7.0.4. This means that it is using the incorrect pathseparator and dirseparator.

This tech-talk issue https://epics.anl.gov/tech-talk/2020/msg01400.php shows how in spite of this it actually works in some cases, which may be why the problem has not been previously reported.

This patch fixes the problem.

diff --git a/src/StreamProtocol.cc b/src/StreamProtocol.cc
index 77741b9..a60b6b0 100644
--- a/src/StreamProtocol.cc
+++ b/src/StreamProtocol.cc
@@ -157,7 +157,7 @@ StreamProtocolParser* StreamProtocolParser::
 readFile(const char* filename)
 {
     FILE* file;
-#ifdef windows
+#ifdef _WIN32
     const char pathseparator = ';';
     const char dirseparator = '\\';
 #else

Conflicting types for 'write' at devmbboDirectStream.c

Compiling stream_2_7_7 for RTEMS and receiving the following error:

/afs/slac/package/rtems/4.9.4//host/i386_linux2x//bin/powerpc-rtems-gcc --pipe -B/afs/slac/package/rtems/4.9.4//target/rtems_p0/powerpc-rtems/beatnik/lib/ -specs bsp_specs -qrtems   -fasm   -mcpu=powerpc -D__ppc_generic -mmultiple -mstring                        -O2 -g -g -g   -Wall       -DMY_DO_BOOTP=NULL -DHAVE_MOTLOAD -DRTEMS_NETWORK_CONFIG_MBUF_SPACE=2048 -DRTEMS_NETWORK_CONFIG_CLUSTER_SPACE=5120     -I. -I../O.Common -I. -I. -I.. -I../../include/compiler/gcc -I../../include/os/RTEMS -I../../include                        -I/afs/slac/g/lcls/epics/R3.15.5-1.0/modules/asyn/R4.30-1.1.1/include -I/afs/slac/g/lcls/epics/base/R3.15.5-1.0/include/compiler/gcc -I/afs/slac/g/lcls/epics/base/R3.15.5-1.0/include/os/RTEMS -I/afs/slac/g/lcls/epics/base/R3.15.5-1.0/include       -I/afs/slac/package/rtems/4.9.4//host/i386_linux2x//powerpc-rtems/include -I/afs/slac/package/rtems/4.9.4//target/rtems_p0/ssrlApps_p3/powerpc-rtems/beatnik//include -I/afs/slac/package/rtems/4.9.4//target/rtems_p0/ssrlApps_p3/powerpc-rtems/beatnik//include -c ../devmbboDirectStream.c
../devmbboDirectStream.c:84: error: conflicting types for 'write'
/afs/slac.stanford.edu/package/rtems/vol16/host/i386_linux2x/bin/../lib/gcc/powerpc-rtems/4.3.2/../../../../../i386_linux26/powerpc-rtems/include/sys/unistd.h:166: error: previous declaration of 'write' was here
make[1]: *** [devmbboDirectStream.o] Error 1
make[1]: Leaving directory `/afs/slac.stanford.edu/g/lcls/vol8/epics/iocTop/users/slepicka/sandbox/git/streamdevice-git/src/O.RTEMS-beatnik'
make: *** [install.RTEMS-beatnik] Error 2

echo in Makefile breaks build on Windows

This echo statement breaks builds on Windows:

echo "registrar(AsynDriverInterfaceRegistrar)" >> $@

The resulting stream.dbd file includes the quotes and an extra space:

variable(streamDebug, int)
variable(streamError, int)
registrar(streamRegistrar)
driver(stream)
device(ao,INST_IO,devaoStream,"stream")
device(ai,INST_IO,devaiStream,"stream")
device(bo,INST_IO,devboStream,"stream")
device(bi,INST_IO,devbiStream,"stream")
device(mbbo,INST_IO,devmbboStream,"stream")
device(mbbi,INST_IO,devmbbiStream,"stream")
device(mbboDirect,INST_IO,devmbboDirectStream,"stream")
device(mbbiDirect,INST_IO,devmbbiDirectStream,"stream")
device(longout,INST_IO,devlongoutStream,"stream")
device(longin,INST_IO,devlonginStream,"stream")
device(stringout,INST_IO,devstringoutStream,"stream")
device(stringin,INST_IO,devstringinStream,"stream")
device(waveform,INST_IO,devwaveformStream,"stream")
device(aai,INST_IO,devaaiStream,"stream")
device(aao,INST_IO,devaaoStream,"stream")
device(calcout,INST_IO,devcalcoutStream,"stream")
device(lsi,INST_IO,devlsiStream,"stream")
device(lso,INST_IO,devlsoStream,"stream")
device(scalcout,INST_IO,devscalcoutStream,"stream")
"registrar(AsynDriverInterfaceRegistrar)"

And the build fails with the following error while creating streamApp.dbd:

dbdExpand.pl: Syntax error in '"registrar(AsynDriverInterfaceRegistrar)" '
Context: file '../../../dbd/stream.dbd'
  while reading 'stream.dbd' to create 'streamApp.dbd'
dbdExpand.pl: Exiting due to errors

Release 2.8.8 does not build with Visual Studio 2010

When I try to build 2.8.8 with Visual Studio 2010 I get this error:

make[3]: Entering directory 'J:/epics/devel/stream/StreamDevice/src/O.windows-x64-vs2010'
cl -EHsc -GR               -nologo -FC -D__STDC__=0 -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -DUSE_TYPED_RSET   -Ox -GL -Oy-   -W3 -w44355 -w44344 -w44251     -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING    -MD -DEPICS_BUILD_DLL -DEPICS_CALL_DLL -TP  -I. -I../O.Common -I. -I. -I.. -I../../../include/compiler/msvc -I../../../include/os/WIN32 -I../../../include      -IJ:/epics/devel/asyn-4-33/include   -IJ:/epics/devel/calc-3-7/include   -IJ:/epics/devel/sscan-2-11-1/include -IH:/epics-devel/base-7.0.2/include/compiler/msvc -IH:/epics-devel/base-7.0.2/include/os/WIN32 -IH:/epics-devel/base-7.0.2/include        -c ../DebugInterface.cc
DebugInterface.cc
j:\epics\devel\stream\streamdevice\src\streambusinterface.h(29) : error C2051: case expression not constant
j:\epics\devel\stream\streamdevice\src\streambusinterface.h(29) : warning C4065: switch statement contains 'default' but no 'case' labels
make[3]: *** [H:/epics-devel/base-7.0.2/configure/RULES_BUILD:239: DebugInterface.obj] Error 2
make[3]: Leaving directory 'J:/epics/devel/stream/StreamDevice/src/O.windows-x64-vs2010'
make[2]: *** [H:/epics-devel/base-7.0.2/configure/RULES_ARCHS:58: install.windows-x64-vs2010] Error 2
make[2]: Leaving directory 'J:/epics/devel/stream/StreamDevice/src'
make[1]: *** [H:/epics-devel/base-7.0.2/configure/RULES_DIRS:84: src.install] Error 2
make[1]: Leaving directory 'J:/epics/devel/stream/StreamDevice'
make: *** [configure/RULES_DIRS:88: StreamDevice.install] Error 2

It builds OK with Visual Studio 2015 and Visual Studio 2017.

Packaging as a standalone EPICS module

Is there a specific reason why this must be put inside the application top folder? All the other epics modules are distributed as standalone support library to be linked by the application.
Can this be done here? I know it can easily be done by the user, but this change would help to standardize the way a user installs an epics module.

IOC hangs on exit

Mail from Mark Rivers:

It looks like the problem is these 2 threads:

Thread 5 (Thread 0x7fffedfe9700 (LWP 30806)):
#0 0x00007ffff5be38ed in connect () from /lib64/libc.so.6
#1 0x00007ffff76dddb4 in connectIt (pasynUser=0x713308, drvPvt=0x71def0) at ../../asyn/drvAsynSerial/drvAsynIPPort.c:476
#2 asynCommonConnect (drvPvt=0x71def0, pasynUser=0x713308) at ../../asyn/drvAsynSerial/drvAsynIPPort.c:520
#3 0x00007ffff76d08fb in portConnectProcessCallback (pasynUser=0x713308) at ../../asyn/asynDriver/asynManager.c:3076
#4 0x00007ffff76d39c7 in portThread (pport=0x711ed0) at ../../asyn/asynDriver/asynManager.c:820
#5 0x00007ffff67128ec in start_routine (arg=0x712f10) at ../../../src/libCom/osi/os/posix/osdThread.c:403
#6 0x00007ffff5698e25 in start_thread () from /lib64/libpthread.so.0
#7 0x00007ffff5be2bad in clone () from /lib64/libc.so.6

Thread 1 (Thread 0x7ffff7fd9740 (LWP 30798)):
#0 0x00007ffff569f51d in __lll_lock_wait () from /lib64/libpthread.so.0
#1 0x00007ffff569ae36 in _L_lock_870 () from /lib64/libpthread.so.0
#2 0x00007ffff569ad2f in pthread_mutex_lock () from /lib64/libpthread.so.0
#3 0x00007ffff6714b66 in mutexLock (id=0x712150) at ../../../src/libCom/osi/os/posix/osdMutex.c:46
#4 epicsMutexOsdLock (pmutex=0x712150) at ../../../src/libCom/osi/os/posix/osdMutex.c:130
#5 0x00007ffff76cf38b in lockPort (pasynUser=0x714d08) at ../../asyn/asynDriver/asynManager.c:1741
#6 0x00007ffff76dcd66 in cleanup (arg=0x71def0) at ../../asyn/drvAsynSerial/drvAsynIPPort.c:246
#7 0x00007ffff6708dd3 in epicsExitCallAtExitsPvt (pep=) at ../../../src/libCom/misc/epicsExit.c:95
#8 epicsExitCallAtExits () at ../../../src/libCom/misc/epicsExit.c:113
#9 0x00007ffff6709178 in epicsExit (status=0) at ../../../src/libCom/misc/epicsExit.c:181
#10 0x0000000000405d0d in main (argc=, argv=) at ../srMain.cpp:21

Thread 1 is drvAsynIPPort trying to close the socket. It is hanging on the call to pasynManager->lockPort(), which tries to lock pport->synchronousLock. The reason is that thread 5 is the asyn port thread trying to connect to the device, and it has the mutex pport->synchronousLock locked. I suspect that thread 5 is trying to connect frequently because many records are talking to the device, and the device has Autoconnect=Yes. If that thread never unlocks the mutex for long then this problem will occur.

I need to try to reproduce this and see if there is a solution.

Next time it happens before you type "exit" please type "epicsMutexShowAll 1".

Mark

Parsing input with %g into ai record

I have an ai record:

# SOURce1:CCURrent:AMPLitude
record(ai, "$(P)$(R)SOUR:CCUR_R")
{
    field(DESC, "Get current amplitude")
    field(DTYP, "stream")
    field(INP,  "@tldc2200.proto getG(SOUR:CCUR:AMPL) $(PORT) 0")
    field(EGU,  "A")
    field(PREC, "3")
}

The protocol entry for getG() is:

getG {
    out "\$1?";
    in "%g[^\r\n]";
    ExtraInput = Ignore;
}

I get this in the IOC shell when I do dbpf $(ACQ_PREFIX)SOUR:CCUR_R.PROC 1:

2019/04/10 14:30:56.007607 _main_ StreamEpics.cc:735: Stream::process(PBILAB:DC1:SOUR:CCUR_R) start
2019/04/10 14:30:56.007669 _main_ StreamCore.cc:413: StreamCore::startProtocol(PBILAB:DC1:SOUR:CCUR_R, startMode=StartNormal)
2019/04/10 14:30:56.007709 _main_ StreamCore.cc:555: StreamCore::evalCommand(PBILAB:DC1:SOUR:CCUR_R): activeCommand = out
2019/04/10 14:30:56.007746 _main_ StreamCore.cc:603: StreamCore::evalOut: outputLine = "SOUR:CCUR:AMPL?"
2019/04/10 14:30:56.007783 _main_ StreamCore.cc:614: StreamCore::evalOut(PBILAB:DC1:SOUR:CCUR_R): lockRequest(5000)
2019/04/10 14:30:56.007816 _main_ AsynDriverInterface.cc:500: AsynDriverInterface::lockRequest(PBILAB:DC1:SOUR:CCUR_R, 5000 msec)
2019/04/10 14:30:56.007887 _main_ StreamEpics.cc:747: Stream::process(PBILAB:DC1:SOUR:CCUR_R): protocol started
DBR_UCHAR:          1         0x1                 
2019/04/10 14:30:56.007918 DET.DC1 AsynDriverInterface.cc:1511: AsynDriverInterface::handleRequest(PBILAB:DC1:SOUR:CCUR_R) Lock
2019/04/10 14:30:56.007982 DET.DC1 AsynDriverInterface.cc:591: AsynDriverInterface::lockHandler(PBILAB:DC1:SOUR:CCUR_R)
2019/04/10 14:30:56.008011 DET.DC1 StreamCore.cc:820: epics> StreamCore::lockCallback(PBILAB:DC1:SOUR:CCUR_R, status=StreamIoSuccess)
2019/04/10 14:30:56.008048 DET.DC1 AsynDriverInterface.cc:629: AsynDriverInterface::writeRequest(PBILAB:DC1:SOUR:CCUR_R, "SOUR:CCUR:AMPL?", 100 msec)
2019/04/10 14:30:56.008086 DET.DC1 AsynDriverInterface.cc:1511: AsynDriverInterface::handleRequest(PBILAB:DC1:SOUR:CCUR_R) Write
2019/04/10 14:30:56.008110 DET.DC1 AsynDriverInterface.cc:657: AsynDriverInterface::writeHandler(PBILAB:DC1:SOUR:CCUR_R)
2019/04/10 14:30:56.008140 DET.DC1 AsynDriverInterface.cc:673: AsynDriverInterface::writeHandler(PBILAB:DC1:SOUR:CCUR_R): reading old input
2019/04/10 14:30:56.008320 DET.DC1 AsynDriverInterface.cc:719: AsynDriverInterface::writeHandler(PBILAB:DC1:SOUR:CCUR_R): write(..., "SOUR:CCUR:AMPL?", outputSize=15, written=15) [timeout=0.1 sec] = asynSuccess ()
2019/04/10 14:30:56.008390 DET.DC1 AsynDriverInterface.cc:738: AsynDriverInterface::writeHandler(PBILAB:DC1:SOUR:CCUR_R): device is connected
2019/04/10 14:30:56.008415 DET.DC1 StreamCore.cc:864: StreamCore::writeCallback(PBILAB:DC1:SOUR:CCUR_R, status=Success)
2019/04/10 14:30:56.008438 DET.DC1 StreamCore.cc:555: StreamCore::evalCommand(PBILAB:DC1:SOUR:CCUR_R): activeCommand = in
2019/04/10 14:30:56.008460 DET.DC1 AsynDriverInterface.cc:811: AsynDriverInterface::readRequest(PBILAB:DC1:SOUR:CCUR_R, 1000 msec reply, 100 msec read, expect 0 bytes, async=no)
2019/04/10 14:30:56.008495 DET.DC1 AsynDriverInterface.cc:836: AsynDriverInterface::readRequest PBILAB:DC1:SOUR:CCUR_R: queueRequest(..., priority=0, queueTimeout=1 sec) = asynSuccess [async=false] 
2019/04/10 14:30:56.008537 DET.DC1 AsynDriverInterface.cc:1511: AsynDriverInterface::handleRequest(PBILAB:DC1:SOUR:CCUR_R) Read
2019/04/10 14:30:56.008565 DET.DC1 AsynDriverInterface.cc:962: AsynDriverInterface::readHandler(PBILAB:DC1:SOUR:CCUR_R): ioAction=Read read(..., bytesToRead=1, ...) [timeout=1 sec]
2019/04/10 14:30:56.010363 DET.DC1 AsynDriverInterface.cc:970: AsynDriverInterface::readHandler(PBILAB:DC1:SOUR:CCUR_R): read returned asynSuccess: ioAction=Read received=1, eomReason=CNT, buffer="1"
2019/04/10 14:30:56.010392 DET.DC1 AsynDriverInterface.cc:977: AsynDriverInterface::readHandler(PBILAB:DC1:SOUR:CCUR_R): device is now connected
2019/04/10 14:30:56.010409 DET.DC1 AsynDriverInterface.cc:1015: AsynDriverInterface::readHandler(PBILAB:DC1:SOUR:CCUR_R): received 1 of 1 bytes "1" eomReason=CNT
2019/04/10 14:30:56.010427 DET.DC1 StreamCore.cc:953: StreamCore::readCallback(PBILAB:DC1:SOUR:CCUR_R, status=StreamIoSuccess input="1", size=1)
2019/04/10 14:30:56.010448 DET.DC1 StreamCore.cc:1009: StreamCore::readCallback(PBILAB:DC1:SOUR:CCUR_R) inputBuffer="1", size 1
2019/04/10 14:30:56.010471 DET.DC1 StreamCore.cc:1090: StreamCore::readCallback(PBILAB:DC1:SOUR:CCUR_R) wait for more input
2019/04/10 14:30:56.010498 DET.DC1 AsynDriverInterface.cc:1141: AsynDriverInterface::readHandler(PBILAB:DC1:SOUR:CCUR_R) readMore=-1 bytesToRead=63
2019/04/10 14:30:56.010521 DET.DC1 AsynDriverInterface.cc:962: AsynDriverInterface::readHandler(PBILAB:DC1:SOUR:CCUR_R): ioAction=Read read(..., bytesToRead=63, ...) [timeout=0.1 sec]
2019/04/10 14:30:56.010550 DET.DC1 AsynDriverInterface.cc:970: AsynDriverInterface::readHandler(PBILAB:DC1:SOUR:CCUR_R): read returned asynSuccess: ioAction=Read received=12, eomReason=END, buffer=".000000E-02<0a>"
2019/04/10 14:30:56.010573 DET.DC1 AsynDriverInterface.cc:977: AsynDriverInterface::readHandler(PBILAB:DC1:SOUR:CCUR_R): device is now connected
2019/04/10 14:30:56.010595 DET.DC1 AsynDriverInterface.cc:1015: AsynDriverInterface::readHandler(PBILAB:DC1:SOUR:CCUR_R): received 12 of 63 bytes ".000000E-02<0a>" eomReason=END
2019/04/10 14:30:56.010618 DET.DC1 StreamCore.cc:953: StreamCore::readCallback(PBILAB:DC1:SOUR:CCUR_R, status=StreamIoEnd input=".000000E-02<0a>", size=12)
2019/04/10 14:30:56.010641 DET.DC1 StreamCore.cc:1009: StreamCore::readCallback(PBILAB:DC1:SOUR:CCUR_R) inputBuffer="1.000000E-02<0a>", size 13
2019/04/10 14:30:56.010662 DET.DC1 StreamCore.cc:1061: StreamCore::readCallback(PBILAB:DC1:SOUR:CCUR_R) end flag received
2019/04/10 14:30:56.010683 DET.DC1 StreamCore.cc:1119: StreamCore::readCallback(PBILAB:DC1:SOUR:CCUR_R) input line: "1.000000E-02<0a>"
2019/04/10 14:30:56.010705 DET.DC1 StreamCore.cc:1209: StreamCore::matchInput(PBILAB:DC1:SOUR:CCUR_R): format = "%g"
2019/04/10 14:30:56.010727 DET.DC1 StreamEpics.cc:523: streamScanfN(PBILAB:DC1:SOUR:CCUR_R,format=%g,maxStringSize=40)
2019/04/10 14:30:56.010767 DET.DC1 StreamCore.cc:1503: StreamCore::scanValue(PBILAB:DC1:SOUR:CCUR_R, format=%g, double) input="1.000000E-02<0a>"
2019/04/10 14:30:56.010790 DET.DC1 StreamCore.cc:1516: StreamCore::scanValue(PBILAB:DC1:SOUR:CCUR_R) scanned 0.0100000
2019/04/10 14:30:56.010815 DET.DC1 StreamEpics.cc:532: streamScanfN(PBILAB:DC1:SOUR:CCUR_R) success, value="{<14><ae>G<e1>z<84>?"
2019/04/10 14:30:56.010842 DET.DC1 StreamCore.cc:1149: StreamCore::readCallback(PBILAB:DC1:SOUR:CCUR_R) match failure
2019/04/10 14:30:56.010863 DET.DC1 StreamCore.cc:513: starting exception handler
2019/04/10 14:30:56.010883 DET.DC1 StreamCore.cc:555: StreamCore::evalCommand(PBILAB:DC1:SOUR:CCUR_R): activeCommand = disconnect
2019/04/10 14:30:56.010906 DET.DC1 AsynDriverInterface.cc:1449: AsynDriverInterface::disconnectRequest PBILAB:DC1:SOUR:CCUR_R
2019/04/10 14:30:56.010932 DET.DC1 AsynDriverInterface.cc:1511: AsynDriverInterface::handleRequest(PBILAB:DC1:SOUR:CCUR_R) Disconnect
2019/04/10 14:30:56.010953 DET.DC1 AsynDriverInterface.cc:1471: AsynDriverInterface::disconnectHandler PBILAB:DC1:SOUR:CCUR_R is not yet disconnected
2019/04/10 14:30:56.011115 DET.DC1 StreamCore.cc:555: StreamCore::evalCommand(PBILAB:DC1:SOUR:CCUR_R): activeCommand = end
2019/04/10 14:30:56.011144 DET.DC1 StreamCore.cc:520: StreamCore::finishProtocol(PBILAB:DC1:SOUR:CCUR_R, status=ScanError) bus owner
2019/04/10 14:30:56.011167 DET.DC1 AsynDriverInterface.cc:611: AsynDriverInterface::unlock(PBILAB:DC1:SOUR:CCUR_R)
2019/04/10 14:30:56.011188 DET.DC1 AsynDriverInterface.cc:1490: AsynDriverInterface::finish(PBILAB:DC1:SOUR:CCUR_R) start
2019/04/10 14:30:56.011209 DET.DC1 AsynDriverInterface.cc:1500: AsynDriverInterface::finish(PBILAB:DC1:SOUR:CCUR_R) done
2019/04/10 14:30:56.011267 cbLow StreamEpics.cc:910: streamRecordProcessCallback(PBILAB:DC1:SOUR:CCUR_R) processing record
2019/04/10 14:30:56.011317 cbLow StreamEpics.cc:715: Stream::process(PBILAB:DC1:SOUR:CCUR_R) error status=CALC (12)
2019/04/10 14:30:56.011368 cbLow StreamEpics.cc:915: streamRecordProcessCallback(PBILAB:DC1:SOUR:CCUR_R) processing record done

I'm especially worried about these lines, from above:

...
2019/04/10 14:30:56.010790 DET.DC1 StreamCore.cc:1516: StreamCore::scanValue(PBILAB:DC1:SOUR:CCUR_R) scanned 0.0100000
2019/04/10 14:30:56.010815 DET.DC1 StreamEpics.cc:532: streamScanfN(PBILAB:DC1:SOUR:CCUR_R) success, value="{<14><ae>G<e1>z<84>?"
2019/04/10 14:30:56.010842 DET.DC1 StreamCore.cc:1149: StreamCore::readCallback(PBILAB:DC1:SOUR:CCUR_R) match failure

...

Why did scanned value of 0.0100000 turn into {<14><ae>G<e1>z<84>??

Implement toupper and tolower (or general char translation?) in regsub

Mybe use PowerGrep syntax: \U1 = toupper(\1), \L1 (tolower), \F1 (first char upper rest lower) \I1 (first char of each word upper rest lower)
Also allow more than 9 sub-expressions. \{4}2 vs \42 vs to substitute 4th match followed by 2 instead of 42nd match.
Separate translate format? Example %|[a-z]|[A-Z]|

Reduce logging the same error from the same record

As a developer at multiple facilities I would like StreamDevice to reduce the amount of repeated log messages so that they don't take up unnecessary disk space/network usage. This is particularly bad when a timeout happens due to a disconnected device but can happen in various cases.

After discussion with @dirk-zimoch and @marciodo the following psuedocode solution was proposed:

  • If the record previously had no error then the error is printed and the error type and timestamp is saved for this record
  • If the record is still in the same error type and a user specified dead_time has not yet elapsed do not print and keep track of the number of errors
  • If the record is still in the same error type and the dead_time has elapsed print the error again, with how many errors were supressed in the dead_time
  • If the record comes out of error print how many errors were supressed and reset the error type to none

Note that this is very similar to the work done in #39 but with the aim to:

  • Do it on a per record basis
  • Reduce the complexity as much as possible

Connection redundancy (Feature)

I'd like to know if there is a feature (or a plan to add it in the future) on StreamDevice that permits "falling back" to a secondary connection natively, in order to avoid "doubling" over already existing work.

As an example, imagining we have two clients reading voltage information (which is mirrored on both devices), is there a way to open a connection to both on startup (or later on, by demand) and alternate between these two connections/IP addresses in case one fails, automatically returning to the first one?

Thanks in advance

STREAM_PROTOCOL_PATH separator

In 98fa595 the default separator for STREAM_PROTOCOL_PATH was changed to be ; on windows. This is more correct and avoids issues with referring to other drives like d: etc. but does mean that STREAM_PROTOCOL_PATH is no longer OS independent. I was wondering if a command to build a path in the right format could be added, so the st.cmd could then be

streamProtocolPath("dir1","dir2")

which would do an epicsEnvSet of STREAM_PROTOCOL_PATH with the appropriate OS separator

streamApp/Makefile issue

streamApp/Makefile contains these lines:

# older calc versions require sscan
#PROD_LIBS += sscan

This is not correct. Current versions of calc can still require sscan. If SSCAN is defined when calc is built then it includes swaitRecord.c, which requires sscan for recDynLink.

Brackets in parameter no longer work

Hi,
I'm in the process of updating our version of streamDevice to your latest release. I have a module that no longer works. The IOC seems to be unhappy about the following record field:

record(ai, "BL99I-LCH-LPP-01:STREAM_BREAKER")
{
field(INP, "@laserPuckPointer.proto readVariable(M_SSPD(10)) LPORT")
}

The bit in particular appears to be "M_SSPD(10)". It doesn't like the brackets in the parameter:

main Cannot find a bus named ')' for 'BL99I-LCH-LPP-01:STREAM_BREAKER'

Do I need to add some kind of escape characters? The method definition in the protocol file looks like this:

readVariable { out "1;9;VAL$1" ; in "Qo%*c$1=%f" ; }

I would expect the following string to get written to the device when the record is processed:

1;9;VALM_SSPD(10)

This used to work with streamDevice 2_5.
Thanks

deprecation warnings in vxWorks 6.9

../src/StreamEpics.cc: In static member function 'static long int Stream::drvInit()':
../src/StreamEpics.cc:450: warning: 'STATUS symFindByName(symtab*, char*, char**, SYM_TYPE*)' is deprecated (declared at /afs/psi.ch/project/vxworks/VxWorks6.9/vxworks-6.9/target/h/symLib.h:181)
../src/StreamEpics.cc:451: warning: deprecated conversion from string constant to 'char*'
../src/StreamEpics.cc:451: warning: 'STATUS symFindByName(symtab*, char*, char**, SYM_TYPE*)' is deprecated (declared at /afs/psi.ch/project/vxworks/VxWorks6.9/vxworks-6.9/target/h/symLib.h:181)
../src/StreamEpics.cc:454: warning: 'STATUS symFindByName(symtab*, char*, char**, SYM_TYPE*)' is deprecated (declared at /afs/psi.ch/project/vxworks/VxWorks6.9/vxworks-6.9/target/h/symLib.h:181)
../src/StreamEpics.cc:455: warning: deprecated conversion from string constant to 'char*'
../src/StreamEpics.cc:455: warning: 'STATUS symFindByName(symtab*, char*, char**, SYM_TYPE*)' is deprecated (declared at /afs/psi.ch/project/vxworks/VxWorks6.9/vxworks-6.9/target/h/symLib.h:181)

symFindByName should be replaced with symFind for vxWorks 6.9.

Dynamic compiling on Windows gives unresolved symbols

Dynamic build of StreamDevice on Windows (win32-x86, Visual Studio 2015) results in the following unresolved external symbols:

devaoStream.obj has unresolved symbol interruptAccept
devwaveformStream.obj has unresolved symbol pamapdbfType
StreamEpics.obj has unresolved symbol pdbbase

This is not encountered when I built against commit 76115ae (previous version I was building against)

Release Notes?

I don't see anything obvious in the documentation for StreamDevice that looks like a set of Release Notes, did I just miss them?

We currently have 2.8.8 installed. How can I find out what's changed between that and the latest release?

configure/RELEASE SUPPORT definition

synApps generally doesn't use full path names for referencing each module, instead defining module paths in reference to the macro SUPPORT. The use of the command 'make release' with StreamDevice ends up writing ASYN et al. as $(SUPPORT)/-, but since configure/RELEASE doesn't have the SUPPORT macro, when trying to build, the modules aren't able to be found.

Even just adding "SUPPORT=" alongside the EPICS_BASE definition would be enough to get things to work with make release, even if you don't define it as anything or use said macro.

Datatype on vxWorks causing checksum failure

Hi,
I'm not that familiar with the workings of StreamDevice but I have encountered an issue when trying to use this module at diamond light source. For years we've had a very old version so I recently pulled in the latest version. I see there is a commit where some data types were changed (6f4383c) in ChecksumConverter.cc, the part that seems to be causing the issue is the "inchar" variable which has changed from an unsigned int to a uint_fast8_t.

I see that the preprocessor substitutes uint_fast8_t for uint8_t if the target is vxWorks but it looks like on our version of vxWorks it should be 32bit (uint32_t). we are using vxWorks 5.5.1 running on a motorola MVME550.

If I change the preprocessor to use uint32_t and the sscanf calls to the old formatting it seems to work:

//sscanf(input(cursor+2*i), "%2" SCNx8, (int8_t *) &inchar);
sscanf(input(cursor+2*i), "%2X", &inchar);

I'll try and get some more details tomorrow but I thought the cause of this may be more obvious to someone who knows the history.

Allow default values for protocol parameters

If protocols could set default values for parameters, it would be easier to extend protocols without breaking their database API.

Use case (happened today):
For an "intelligent" modular measurement device, modules may have one or multiple inputs ("subchannels").
The existing protocol supported a module type with one input, so the "select subchannel" command was hard-coded to 1.

An upgrade to support a module with multiple inputs made the subchannel a second parameter, which requires to change all existing databases.
If the protocol were able set a default value for parameter 2, such upgrades could keep compatibilty.

Problems building 2.8.9 and master on Windows

I am trying to build stream on base with 7.0.3.1.

stream 2.8.9 fails to build on Windows static (windows-x64-static) with this error:

echo stream-scalcout.dbd: ../CONFIG_STREAM > stream-scalcout.dbd.d
echo stream-base.dbd: ../CONFIG_STREAM > stream-base.dbd.d
echo "stream.dbd: stream-base.dbd stream-scalcout.dbd" > stream.dbd.d
H:/epics-devel/base-7.0.3.1/configure/RULES_BUILD:177: target '../../../db' given more than once in the same rule
perl -CSD ../makedbd.pl --with-asyn  ao ai bo bi mbbo mbbi mbboDirect mbbiDirect longout longin stringout stringin waveform aai aao calcout lsi lso int64in int64out > ../O.Common/stream-base.dbd
perl -CSD ../makedbd.pl --with-asyn  scalcout > ../O.Common/stream-scalcout.dbd
cat ../O.Common/stream-base.dbd ../O.Common/stream-scalcout.dbd > ../O.Common/stream.dbd
'cat' is not recognized as an internal or external command,
operable program or batch file.
make[2]: *** [../Makefile:113: ../O.Common/stream.dbd] Error 1
make[2]: Leaving directory 'J:/epics/devel/stream/src/O.windows-x64-static'
make[1]: *** [H:/epics-devel/base-7.0.3.1/configure/RULES_ARCHS:58: install.windows-x64-static] Error 2
make[1]: Leaving directory 'J:/epics/devel/stream/src'
make: *** [H:/epics-devel/base-7.0.3.1/configure/RULES_DIRS:84: src.install] Error 2

2.8.9 builds on Linux with these warnings:

corvette:~/devel/stream>make -sj
/corvette/usr/local/epics-devel/base-7.0.3.1/configure/RULES_BUILD:177: target `../../../db' given more than once in the same rule.
/corvette/usr/local/epics-devel/base-7.0.3.1/configure/RULES_BUILD:177: target `../../../db' given more than once in the same rule.
/corvette/usr/local/epics-devel/base-7.0.3.1/configure/RULES_BUILD:177: target `../../../db' given more than once in the same rule.

On both Linux and Windows the library files do not get installed into stream/lib, they get installed into stream/../lib. Is this intentional?

The master branch fails to build on Windows with this error:

link -nologo   -incremental:no -opt:ref -release  -MACHINE:X64              -out:streamApp.exe    streamApp_registerRecordDeviceDriver.obj streamAppMain.obj     ../../../lib/windows-x64-static/stream.lib  J:/epics/devel/asyn-4-37/lib/windows-x64-static/asyn.lib  J:/epics/devel/calc-3-7-3/lib/windows-x64-static/calc.lib  J:/epics/devel/sscan-2-11-3/lib/windows-x64-static/sscan.lib  H:/epics-devel/base-7.0.3.1/lib/windows-x64-static/dbRecStd.lib  H:/epics-devel/base-7.0.3.1/lib/windows-x64-static/dbCore.lib  H:/epics-devel/base-7.0.3.1/lib/windows-x64-static/ca.lib  H:/epics-devel/base-7.0.3.1/lib/windows-x64-static/Com.lib netapi32.lib ws2_32.lib advapi32.lib user32.lib kernel32.lib winmm.lib dbghelp.lib
   Creating library streamApp.lib and object streamApp.exp
stream.lib(StreamEpics.obj) : error LNK2019: unresolved external symbol "struct _iobuf * StreamDebugFile" (?StreamDebugFile@@3PEAU_iobuf@@EA) referenced in function "long __cdecl streamSetLogfile(char const *)" (?streamSetLogfile@@YAJPEBD@Z)
stream.lib(StreamEpics.obj) : error LNK2019: unresolved external symbol "char const * const StreamVersion" (?StreamVersion@@3QBDB) referenced in function "private: static void __cdecl Stream::initHook(enum initHookState)" (?initHook@Stream@@CAXW4initHookState@@@Z)
streamApp.exe : fatal error LNK1120: 2 unresolved externals
make[2]: *** [H:/epics-devel/base-7.0.3.1/configure/RULES_BUILD:213: streamApp.exe] Error 1120
make[2]: Leaving directory 'J:/epics/devel/stream/streamApp/O.windows-x64-static'
make[1]: *** [H:/epics-devel/base-7.0.3.1/configure/RULES_ARCHS:58: install.windows-x64-static] Error 2
make[1]: Leaving directory 'J:/epics/devel/stream/streamApp'
make: *** [H:/epics-devel/base-7.0.3.1/configure/RULES_DIRS:84: streamApp.install] Error 2

I can eliminate the error on StreamDebugFile with this change, removing the __declspec(dllexport), which should not be used for static builds.

corvette:~/devel/stream/src>git diff StreamError.cc
diff --git a/src/StreamError.cc b/src/StreamError.cc
index 29757c5..10371da 100644
--- a/src/StreamError.cc
+++ b/src/StreamError.cc
@@ -27,12 +27,9 @@

 int streamDebug = 0;
 int streamError = 1;
-extern "C" {
-#ifdef _WIN32
-__declspec(dllexport)
-#endif
+
 FILE *StreamDebugFile = NULL;
-}
+

 #ifndef va_copy
 #ifdef __va_copy

However, I have not figured out how to eliminate the error on StreamVersion.

When building dynamically on Windows (windows-x64) the error shows up earlier, which building stream.lib, rather than streamApp.

link -nologo -subsystem:windows -dll -LTCG -incremental:no -opt:ref -release  -MACHINE:X64      -out:stream.dll -implib:stream.lib     DebugInterface.obj DummyInterface.obj AsynDriverInterface.obj EnumConverter.obj BCDConverter.obj RawConverter.obj RawFloatConverter.obj BinaryConverter.obj ChecksumConverter.obj MantissaExponentConverter.obj TimestampConverter.obj devaoStream.obj devaiStream.obj devboStream.obj devbiStream.obj devmbboStream.obj devmbbiStream.obj devmbboDirectStream.obj devmbbiDirectStream.obj devlongoutStream.obj devlonginStream.obj devstringoutStream.obj devstringinStream.obj devwaveformStream.obj devaaiStream.obj devaaoStream.obj devcalcoutStream.obj devlsiStream.obj devlsoStream.obj devint64inStream.obj devint64outStream.obj devscalcoutStream.obj StreamVersion.obj StreamBuffer.obj StreamError.obj StreamProtocol.obj StreamFormatConverter.obj StreamCore.obj StreamBusInterface.obj StreamEpics.obj      J:/epics/devel/asyn-4-37/lib/windows-x64/asyn.lib  H:/epics-devel/base-7.0.3.1/lib/windows-x64/dbRecStd.lib  H:/epics-devel/base-7.0.3.1/lib/windows-x64/dbCore.lib  H:/epics-devel/base-7.0.3.1/lib/windows-x64/ca.lib  H:/epics-devel/base-7.0.3.1/lib/windows-x64/Com.lib
   Creating library stream.lib and object stream.exp
StreamEpics.obj : error LNK2001: unresolved external symbol "char const * const StreamVersion" (?StreamVersion@@3QBDB)
stream.dll : fatal error LNK1120: 1 unresolved externals
make[2]: *** [H:/epics-devel/base-7.0.3.1/configure/RULES_BUILD:298: stream.dll] Error 1120
make[2]: Leaving directory 'J:/epics/devel/stream/src/O.windows-x64'
make[1]: *** [H:/epics-devel/base-7.0.3.1/configure/RULES_ARCHS:58: install.windows-x64] Error 2
make[1]: Leaving directory 'J:/epics/devel/stream/src'
make: *** [H:/epics-devel/base-7.0.3.1/configure/RULES_DIRS:84: src.install] Error 2

k

crash, probably due to stack overflow

We have a situation where our IOC crashes inside libstream.so. There are lots of communication errors right from the start. The protocol file is:

Terminator = 0x03;
ReadTimeout = 100;   
ReplyTimeout = 1000;
ExtraInput = Ignore;

readSonde {
 in "%*/\|0062\|2\|\$1\|\$2\|\$3\|\$4\|/%f";
}

The core dump suggests that it runs into a stack overflow due to an endless recursion between StreamCore::readCallback and StreamCore::evalIn:

Program terminated with signal SIGSEGV, Segmentation fault.
(gdb) bt
#0  0x00007f65a07d7a8a in StreamCore::readCallback (this=0x0, status=StreamIoSuccess, 
    input=0x0, size=0) at ../StreamCore.cc:932
#1  0x00007f65a07d78cc in StreamCore::evalIn (this=0x56230f60e890)
    at ../StreamCore.cc:903
#2  0x00007f65a07d7e81 in StreamCore::readCallback (this=0x56230f60e890, 
    status=StreamIoNoReply, input=0x0, size=0) at ../StreamCore.cc:975
#3  0x00007f65a07d78cc in StreamCore::evalIn (this=0x56230f60e890)
    at ../StreamCore.cc:903
#4  0x00007f65a07d7e81 in StreamCore::readCallback (this=0x56230f60e890, 
    status=StreamIoNoReply, input=0x0, size=0) at ../StreamCore.cc:975
#5  0x00007f65a07d78cc in StreamCore::evalIn (this=0x56230f60e890)
    at ../StreamCore.cc:903

and so on and so on (> 1300 stack entries). The StreamDevice version is 2.8.10.

'include, lib, dbd, bin' folders placed in directory higher than stream.

Current Makefiles place 'include, lib, dbd, bin' folders in directory higher than stream folder because support folder contains configure folder as well!

pi@raspberrypi:/epics/support/stream $ ls -ltr ..
total 116
-rw-r--r--  1 pi pi  3526 Apr 10 06:31 README
-rw-r--r--  1 pi pi  3718 Apr 10 06:31 LICENSE
-rw-r--r--  1 pi pi   541 Apr 10 06:31 README.md
-rw-r--r--  1 pi pi  4540 Apr 10 06:31 Makefile
-rwxr-xr-x  1 pi pi 11872 Apr 10 06:31 assemble_synApps.sh
drwxr-xr-x  3 pi pi  4096 Apr 10 06:31 documentation
drwxr-xr-x 10 pi pi  4096 Apr 10 06:31 utils
drwxr-xr-x  7 pi pi  4096 Apr 10 06:31 modbus
drwxr-xr-x  9 pi pi  4096 Apr 10 06:31 motor
drwxr-xr-x 13 pi pi  4096 Apr 10 09:34 seq
drwxr-xr-x 12 pi pi  4096 Apr 10 09:44 sscan
drwxr-xr-x 14 pi pi  4096 Apr 10 10:23 calc
drwxr-xr-x 33 pi pi  4096 Apr 10 10:23 asyn
drwxr-xr-x 17 pi pi  4096 Apr 10 10:36 iocStats
drwxr-xr-x 14 pi pi  4096 Apr 10 10:54 std
drwxr-xr-x 14 pi pi  4096 Apr 10 10:56 autosave
drwxr-xr-x 13 pi pi  4096 Apr 10 10:57 busy
drwxr-xr-x  6 pi pi  4096 Apr 24 15:46 configure
drwxr-xr-x  9 pi pi  4096 Apr 24 15:46 caputRecorder
drwxr-xr-x 12 pi pi  4096 Apr 24 15:46 delaygen
drwxr-xr-x 12 pi pi  4096 Apr 24 16:08 mca
drwxr-xr-x  8 pi pi  4096 Apr 24 16:49 stream
drwxr-xr-x  2 pi pi  4096 Apr 24 16:51 include
drwxr-xr-x  3 pi pi  4096 Apr 24 16:51 lib
drwxr-xr-x  2 pi pi  4096 Apr 24 16:52 dbd
drwxr-xr-x  3 pi pi  4096 Apr 24 16:52 bin

I made quick fix in

  • stream/Makefile
TOP = .
ifneq ($(wildcard ../configure),)
  # We are in an EPICS R3.14+ <TOP> location
  include $(TOP)/configure/CONFIG
else ifneq ($(wildcard ../config),)
  # We are in an EPICS R3.13 <TOP> location
  CONFIG = $(TOP)/config
  include $(TOP)/config/CONFIG_APP
else
  # Using our own local configuration
  TOP = .
  DIRS = configure
  src_DEPEND_DIRS := $(DIRS)
  include $(TOP)/configure/CONFIG
#endif
  • stream/src/Makefile
#TOP = ../..
TOP = ..
ifneq ($(wildcard ../../configure),)
  include $(TOP)/configure/CONFIG
else ifneq ($(wildcard ../../config),)
  include $(TOP)/config/CONFIG_APP
  include $(TOP)/config/RULES_ARCHS
else
  TOP= ..
  include $(TOP)/configure/CONFIG
endif
  • stream/streamApp/Makefile
#TOP = ../..
TOP = ..
ifneq ($(wildcard ../../configure),)
  include $(TOP)/configure/CONFIG
else ifneq ($(wildcard ../../config),)
  include $(TOP)/config/CONFIG_APP
  include $(TOP)/config/RULES_ARCHS
else
  TOP= ..
  include $(TOP)/configure/CONFIG
endif

After above changes

pi@raspberrypi:/epics/support/stream $ ls -ltr
total 92
-rw-r--r-- 1 pi pi  1211 Apr 10 06:31 GNUmakefile
-rw-r--r-- 1 pi pi  1509 Apr 24 16:20 README.md
-rw-r--r-- 1 pi pi  7652 Apr 24 16:20 LICENSE.LESSER
-rw-r--r-- 1 pi pi 35149 Apr 24 16:20 LICENSE
drwxr-xr-x 2 pi pi  4096 Apr 24 16:20 config
drwxr-xr-x 2 pi pi  4096 Apr 24 16:20 docs
drwxr-xr-x 5 pi pi  4096 Apr 24 17:03 configure
drwxr-xr-x 4 pi pi  4096 Apr 24 17:03 src
drwxr-xr-x 2 pi pi  4096 Apr 24 17:03 include
drwxr-xr-x 3 pi pi  4096 Apr 24 17:03 lib
drwxr-xr-x 5 pi pi  4096 Apr 24 17:03 streamApp
drwxr-xr-x 2 pi pi  4096 Apr 24 17:03 dbd
drwxr-xr-x 3 pi pi  4096 Apr 24 17:03 bin
-rw-r--r-- 1 pi pi  1573 Apr 24 17:11 Makefile

I can refine this logic further, and create a pull request.

TOP = .
ifneq ($(wildcard ./configure),)
include $(TOP)/configure/CONFIG
else ifneq ($(wildcard ../config),)
include $(TOP)/config/CONFIG_APP
include $(TOP)/config/RULES_ARCHS
else # Redundant
TOP= .
include $(TOP)/configure/CONFIG
endif

Bad init_rec return value <PVname> ao: init_record

I have these two PVs:

# test1
record(ao, "$(P)$(R)SOUR:CURR:LIM1")
{
#    field(DTYP, "stream")
}

record(ao, "$(P)$(R)SOUR:CURR:LIM")
{
    field(DTYP, "stream")
}

After starting of the IOC I get the line:

Bad init_rec return value  PV: PBILAB:DC1:SOUR:CURR:LIM ao: init_record

I do not get the line for the first record, only for the second (DTYP=stream).

On 64-bit Linux, epics base 3.15.5, streamDevice 2.7.11, asyn R4-33.

Add a new checksum method

StreamDevice has many checksum functions, but i have some devices which need LRC checksum, so i write a function about LRC checksum.
example:
:010310040002E6 here E6 is LRC checksum. Calculation process: 01+03+10+04+00+02=1A(hex), negative of sum is E5, then add 1 is E6.
/////add a new checksum function/////
//This function is to implement LRC verification
//static unsigned int lrcsum(const unsigned char* data,unsigned int len,unsigned int sum)
static ulong lrcsum(const uchar* data,ulong len,ulong sum)
{
//Add all hex digits,ignore all other bytes.
unsigned int d;
while(len--)
{
d=toupper(*data++);
if(isxdigit(d))
{
if(isdigit(d))
d -= '0';
else
d -= 'A'-0x0A;
if(len%2)
d *= 16;
sum += d;
}
}
return sum;
}
static checksum checksumMap[] =
// You may add your own checksum functions to this map.
{
// name func init xorout bytes chk("123456789")
{"sum", sum, 0x00, 0x00, 1}, // 0xDD
{"sum8", sum, 0x00, 0x00, 1}, // 0xDD
...
{"adler32", adler32, 0x00000001, 0x00000000, 4}, // 0x091E01DE
{"hexsum8", hexsum, 0x00, 0x00, 1}, // 0x2D
{"lrcsum8", lrcsum, 0x00, 0x00, 1},//add lrcsum8
{"-lrcsum8",lrcsum, 0xFF, 0xFF, 1}//add -lrcsum8
};

redirection-to-records fails when PV name starts with a number

I wrote stream support for a pyrometer. The protocol file, Metis_M322.proto, contains a function that reads in three temperatures:

getBuff01Data
{
  out "\$1bup";
  in "%04x%(\$2:temp2Raw)04x%(\$2:temp2cRaw)04x";
}

This is the relevant portion of Metis_M322.db:

record(ai, "$(P)$(R):temp1:01") {
  field(DTYP, "stream")
  field(INP,  "@Metis_M322.proto getBuff01Data($(A),$(P)$(R)) $(PORT)")
  field(SCAN, "Passive")
  field(LINR, "SLOPE")
  field(ESLO, "0.1")
  field(EOFF, "0.0")
  field(PREC, "3")
  field(FLNK, "$(P)$(R):temp1")
}
record(longout, "$(P)$(R):temp2Raw") {}
record(longout, "$(P)$(R):temp2cRaw") {}

If P=kmp3:, then temp2Raw and temp2cRaw update each time temp1:01 processes.
If P=3kmp:, then temp2Raw and temp2cRaw fail to update when temp1:01 processes.

I can recreate the problem the following versions of EPICS modules:

  • the master branch of streamDevice (commit cb4d490)
  • EPICS base-3.14.12.5
  • asyn-4-26
  • calc-3-4-2-1
  • seq-2-2-1

Not interpreted format conversions

There are cases when the format conversion is not interpreted as a format conversion. For example the following protocol will not match "@001ACKparseme" but will match "@001ACK%s".

wont_work {
prefix = "@" "%3c" "ACK";
in $prefix "%s";
}

The "%s" will be interpreted as literal '%' followed by 's'.

I will create a pull request with a proposed fix.

Protocol hangs after trying to read on a disconnected port

A protocol seems to hang, if a StreamDevice 'in' command is initiated on a disconnected port. Something like this might happen if the target server / device is offline.
Here some simplified example:

sendTest {
    out "%#s";
}

rbkTest {
    in "%#s";
}
record(stringout, "DIODETEST2:sendTest") {
    field(DTYP, "stream")
    field(OUT,  "@test.proto sendTest() DIODETEST2 -1")
    field(FLNK, "DIODETEST2:rbkTest")
}

record(stringin, "DIODETEST2:rbkTest") {
    field(DTYP, "stream")
    field(INP,  "@test.proto rbkTest() DIODETEST2 -1")
}

To reproduce this I simulated a disconnected device by deactivating autoConnect and disconnecting the asyn port:

2018/11/26 16:08:17.709256 CAS-client DIODETEST2:sendTest lockRequest: pasynManager->queueRequest: port DIODETEST2 not connected
2018/11/26 16:08:17.709281 CAS-client DIODETEST2:rbkTest readRequest: pasynManager->queueRequest: port DIODETEST2 not connected

This is expected, but after I reconnected the port and send another command, I only got a recovery message for the output record:

2018/11/26 16:08:24.893359 CAS-client DIODETEST2:sendTest lockRequest: pasynManager->queueRequest: status returned to normal

I could see the answer being read by asyn though asyn debug, but it did not appear in the input record.
A recovery of the record could be done with streamReload:

epics> streamReload('DIODETEST2:rbkTest')
2018/11/26 16:09:39.328291 main DIODETEST2:rbkTest: Protocol aborted

This seems to point out, that the protocol was hanging all the time without running into a timeout. Initially I discovered the same problem while using waveform records. I used stringin and stringout for simplification. I couldn't reproduce the same behavior for a pair of ao and ai, so it might be something only related to strings / arrays.

The test was done with version 2.7.7 and 2.8.7

Global @mismatch {} handler not called?

For a complex binary protocol I needed an index counter that increments after each message to the device. Implemented as a calcRecord with a matching command in the protocol that steps it.

incr {
    exec "dbpf "$R_Index".PROC 1";
}

The command is being called from the protocols as:

SuperComplexBinaryMessage {
    out 0xAA 0x00 0x07 $4 $4 0x00 0x00 "%("$R_Index")r" 0x42 $5 $crc;
    in  0xAA 0x00 0x09 0x00 0x00 $4 0x00 "%("$R_Index")=r" 0x42 "%("$R_StatusRBK")r" $5 0x00 $crc;
    incr;
}

Global handlers exist:

@mismatch { incr; }
@readTimeout { incr; }
@replyTimeout { incr; }

While debugging, I found the global handler not being called at a format mismatch.

2021/07/23 09:03:26.566608 SCI0303 VV-VVOI-SCHR-DISP:MDR1511-ASTRT: mismatch after 2 bytes "<aa><00>"
2021/07/23 09:03:26.566616 SCI0303 VV-VVOI-SCHR-DISP:MDR1511-ASTRT: got "<09><00><00><01><00><05>E<07><00><00>..." where "<0f>" was expected
2021/07/23 09:03:26.566624 SCI0303 StreamCore.cc:1133: StreamCore::readCallback(VV-VVOI-SCHR-DISP:MDR1511-ASTRT) match failure
2021/07/23 09:03:26.566634 SCI0303 StreamCore.cc:447: StreamCore::finishProtocol(VV-VVOI-SCHR-DISP:MDR1511-ASTRT, ScanError) bus owner
2021/07/23 09:03:26.566643 SCI0303 StreamCore.cc:514: starting exception handler
2021/07/23 09:03:26.566654 SCI0303 StreamCore.cc:544: StreamCore::evalCommand(VV-VVOI-SCHR-DISP:MDR1511-ASTRT): activeCommand = end
2021/07/23 09:03:26.566664 SCI0303 StreamCore.cc:447: StreamCore::finishProtocol(VV-VVOI-SCHR-DISP:MDR1511-ASTRT, Success) bus owner
2021/07/23 09:03:26.566674 SCI0303 AsynDriverInterface.cc:609: AsynDriverInterface::unlock(VV-VVOI-SCHR-DISP:MDR1511-ASTRT)
2021/07/23 09:03:26.566685 SCI0303 AsynDriverInterface.cc:1473: AsynDriverInterface::finish(VV-VVOI-SCHR-DISP:MDR1511-ASTRT) start
2021/07/23 09:03:26.566692 SCI0303 AsynDriverInterface.cc:1483: AsynDriverInterface::finish(VV-VVOI-SCHR-DISP:MDR1511-ASTRT) done
2021/07/23 09:03:26.566698 SCI0303 StreamEpics.cc:969: Stream::protocolFinishHook(VV-VVOI-SCHR-DISP:MDR1511-ASTRT, ScanError)
2021/07/23 09:03:26.566715 cbLow-0 StreamEpics.cc:1047: recordProcessCallback(VV-VVOI-SCHR-DISP:MDR1511-ASTRT) processing record
2021/07/23 09:03:26.566731 cbLow-0 StreamEpics.cc:843: Stream::process(VV-VVOI-SCHR-DISP:MDR1511-ASTRT)
2021/07/23 09:03:26.566738 cbLow-0 StreamEpics.cc:849: Stream::process(VV-VVOI-SCHR-DISP:MDR1511-ASTRT) error status=CALC (12)

StreamDevice 2.8.10
EPICS Asyn 4.37
EPICS Base 7.0.3.1
RHEL 7.4

New syntax needed for interlaced arrays (aka tables)

At the moment, there is no good way to parse interlaced arrays:
a[0],b[0],c[0];a[1],b[1],c[1];a[2],b[2],b[3];...
And there is not even a bad way to print them.
How should the syntax look like?
I am inclined to this:
in "possible prefix" [ "%f,%(recB)f,%(recC)f;" ] "possible postfix";
having [ outside of quotes.
Or escaped: "[...]" ?
When to stop if the array records differ in capacity (NELM)? First record to fill up and leave the remaining input in the input buffer? Last record to fill up and drop overflow elements? End of matching input and drop overflow elements?

%d, %X, %04X result in error

I have a record that used to work fine, but when I updated StreamDevice I now get "Cannot format value with '%04X'" when I write to it.

The full entry from the protocol file is:

WritePID {
        out "*\$1W\$2%04X";
        out "*\$1Z02";
        wait 5000;
}

The record type was originally ao, so I tried changing the type to longout, but the problem persists. Right now the record looks like:

record(longout, "$(Sys)$(Dev)Gain:PB$(N_GAIN)-SP")
{
        field(DTYP, "stream")
        field(DESC, "Proportional Band 1")
        field(OUT, "@omega-CNi32.proto WritePID($(Chan),17) $(PORT)")
        field(EGU,  "Counts")
        field(PINI, "YES")
        field(VAL, "20")

        info(autosaveFields_pass0, "VAL")
}

The only thing I can do is to get the message to go away is changing the %04X to %lf. I also tried %d and %d does not work. Any ideas for why %lf works but not %04X or %d?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.