Compare commits
27 Commits
stream_2_6
...
stream_2_6
Author | SHA1 | Date | |
---|---|---|---|
cc5948ad0b | |||
be1943a66d | |||
d9acb47afe | |||
b721d26fb8 | |||
7530c7c67d | |||
824cd4d283 | |||
2e30e7aee6 | |||
3a5a3e22b9 | |||
51bd766ba6 | |||
0ab0d6db07 | |||
a12de614d6 | |||
240abd2788 | |||
e131fcb32f | |||
f88f594e87 | |||
56ef0651f2 | |||
9b9726b800 | |||
b139221f0b | |||
b0ab8a7a8b | |||
ddac589676 | |||
5b380cdaad | |||
cc9adc77fa | |||
2b38f7bcfa | |||
0ceada70b5 | |||
7bf91b403d | |||
bf5c359649 | |||
c41ac44bd1 | |||
e36013d64e |
BIN
doc/PSI.gif
BIN
doc/PSI.gif
Binary file not shown.
Before Width: | Height: | Size: 1.6 KiB |
BIN
doc/PSI.png
Normal file
BIN
doc/PSI.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: aai Records</h1>
|
||||
<h1>aai Records</h1>
|
||||
<p>
|
||||
<b>Note:</b> aai record support is disabled per default.
|
||||
Enable it in <code>src/CONFIG_STREAM</code>.
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: aao Records</h1>
|
||||
<h1>aao Records</h1>
|
||||
<p>
|
||||
<b>Note:</b> aao record support is disabled per default.
|
||||
Enable it in <code>src/CONFIG_STREAM</code>.
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: ai Records</h1>
|
||||
<h1>ai Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: ao Records</h1>
|
||||
<h1>ao Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: bi Records</h1>
|
||||
<h1>bi Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: bo Records</h1>
|
||||
<h1>bo Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: calcout Records</h1>
|
||||
<h1>calcout Records</h1>
|
||||
|
||||
<p>
|
||||
<b>Note:</b> Device support for calcout records is only available for
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Using EPICS 3.13</h1>
|
||||
<h1>Using EPICS 3.13</h1>
|
||||
|
||||
<a name="pre"></a>
|
||||
<h2>1. Prerequisites</h2>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Format Converter API</h1>
|
||||
<h1>Format Converter API</h1>
|
||||
|
||||
<a name="class"></a>
|
||||
<h2>Converter Class</h2>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Format Converters</h1>
|
||||
<h1>Format Converters</h1>
|
||||
|
||||
<a name="syntax"></a>
|
||||
<h2>1. Format Syntax</h2>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: longin Records</h1>
|
||||
<h1>longin Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: longout Records</h1>
|
||||
<h1>longout Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
|
35
doc/makepdf
Executable file
35
doc/makepdf
Executable file
@ -0,0 +1,35 @@
|
||||
PAGES="
|
||||
index.html
|
||||
setup.html
|
||||
epics3_13.html
|
||||
protocol.html
|
||||
formats.html
|
||||
processing.html
|
||||
recordtypes.html
|
||||
aai.html
|
||||
aao.html
|
||||
ai.html
|
||||
ao.html
|
||||
bi.html
|
||||
bo.html
|
||||
mbbi.html
|
||||
mbbo.html
|
||||
mbbiDirect.html
|
||||
mbboDirect.html
|
||||
stringin.html
|
||||
stringout.html
|
||||
longin.html
|
||||
longout.html
|
||||
waveform.html
|
||||
calcout.html
|
||||
scalcout.html
|
||||
tipsandtricks.html
|
||||
recordinterface.html
|
||||
businterface.html
|
||||
formatconverter.html
|
||||
osinterface.html
|
||||
"
|
||||
|
||||
rm -f stream.pdf
|
||||
wkhtmltopdf --print-media-type --dpi 1200 --zoom 0.85 --page-size Letter \
|
||||
$PAGES stream.pdf
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: mbbi Records</h1>
|
||||
<h1>mbbi Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: mbbiDirect Records</h1>
|
||||
<h1>mbbiDirect Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: mbbo Records</h1>
|
||||
<h1>mbbo Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: mbboDirect Records</h1>
|
||||
<h1>mbboDirect Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Operating System API</h1>
|
||||
<h1>Operating System API</h1>
|
||||
|
||||
<h2>Sorry, this documentation is still missing.</h2>
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Record Processing</h1>
|
||||
<h1>Record Processing</h1>
|
||||
|
||||
<a name="proc"></a>
|
||||
<h2>1. Normal Processing</h2>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Protocol Files</h1>
|
||||
<h1>Protocol Files</h1>
|
||||
<a name="gen"></a>
|
||||
<h2>1. General Information</h2>
|
||||
<p>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Record API</h1>
|
||||
<h1>Record API</h1>
|
||||
|
||||
<h2>Sorry, this documentation is still missing.</h2>
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Record Types</h1>
|
||||
<h1>Record Types</h1>
|
||||
|
||||
<h2>Supported Record Types</h2>
|
||||
<p>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: scalcout Records</h1>
|
||||
<h1>scalcout Records</h1>
|
||||
|
||||
<p>
|
||||
<b>Note:</b> The scalcout record is part of the <i>calc</i> module of
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Setup</h1>
|
||||
<h1>Setup</h1>
|
||||
|
||||
<a name="pre"></a>
|
||||
<h2>1. Prerequisites</h2>
|
||||
|
@ -5,8 +5,9 @@ a:hover {color: #FF0000;}
|
||||
body {
|
||||
margin-right:1em;
|
||||
margin-left:15em;
|
||||
margin-top:11ex;
|
||||
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
||||
margin-top:70px;
|
||||
padding-top:1px;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-size:14px;
|
||||
background-color:#ffffff;
|
||||
}
|
||||
@ -30,26 +31,26 @@ dt {
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size:225%;
|
||||
font-size:250%;
|
||||
margin-top:0;
|
||||
font-style:italic;
|
||||
font-family:serif;
|
||||
font-weight:bold;
|
||||
font-family:"Times New Roman", serif;
|
||||
text-align:center;
|
||||
position:fixed;
|
||||
top:0;
|
||||
left:0;
|
||||
width:100%;
|
||||
min-height:60px;
|
||||
height: 4ex;
|
||||
line-height:190%;
|
||||
background-color:white;
|
||||
border-top:6px solid #1b4486;
|
||||
border-bottom:4px solid #1b4486;
|
||||
border-width:0;
|
||||
border-bottom:3px solid #1b4486;
|
||||
white-space:nowrap;
|
||||
background-image:url(PSI.gif);
|
||||
background-image:url(PSI.png);
|
||||
background-repeat:no-repeat;
|
||||
background-position:10px 2px;
|
||||
text-shadow: .1em .1em .1em lightgray;
|
||||
background-position:10px 5px;
|
||||
text-shadow:.1em .1em .1em darkgray;
|
||||
box-shadow:0 .3em .1em -.2em darkgray;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@ -91,7 +92,7 @@ code {
|
||||
position:fixed;
|
||||
left:0;
|
||||
top:0;
|
||||
padding-top:9ex;
|
||||
padding-top:70px;
|
||||
width:14em;
|
||||
height:100%;
|
||||
border-style:solid;
|
||||
@ -115,13 +116,9 @@ a[target=ex]:hover:after {
|
||||
}
|
||||
|
||||
@media print {
|
||||
a:link {color: black; text-decoration:none;}
|
||||
a:visited {color: black; text-decoration:none;}
|
||||
a:hover {color: black; text-decoration:none;}
|
||||
a[target=ex] {text-decoration:underline;}
|
||||
a:link {text-decoration:none;}
|
||||
a[target=ex]:after {content:" [" attr(href) "]";}
|
||||
code {color: black; }
|
||||
body {margin-left:10px;}
|
||||
h1 {position:absolute;}
|
||||
body {margin:0 4em;}
|
||||
h1 {position:relative; background-position:0 0;}
|
||||
#navleft {display:none;}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: stringin Records</h1>
|
||||
<h1>stringin Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: stringout Records</h1>
|
||||
<h1>stringout Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Tips and Tricks</h1>
|
||||
<h1>Tips and Tricks</h1>
|
||||
|
||||
<a name="argvar"></a>
|
||||
<h2>I have many almost identical protocols</h2>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: waveform Records</h1>
|
||||
<h1>waveform Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
|
14
makefile
14
makefile
@ -1,12 +1,10 @@
|
||||
include /ioc/tools/driver.makefile
|
||||
EXCLUDE_VERSIONS = 3.13.2
|
||||
PROJECT=stream2
|
||||
PROJECT=stream
|
||||
BUILDCLASSES += Linux
|
||||
|
||||
#DOCUDIR = doc
|
||||
|
||||
DBDS = stream.dbd
|
||||
|
||||
BUSSES += AsynDriver
|
||||
BUSSES += Dummy
|
||||
|
||||
@ -42,9 +40,9 @@ HEADERS += StreamBuffer.h
|
||||
HEADERS += StreamError.h
|
||||
|
||||
ifeq (${EPICS_BASETYPE},3.13)
|
||||
USR_INCLUDES += -include $(INSTALL_INCLUDE)/compat3_13.h
|
||||
endif
|
||||
ifeq (${EPICS_BASETYPE},3.14)
|
||||
# old gcc needs full path for -include
|
||||
CXXFLAGS += -include $(foreach d,${INCLUDES:-I%=%},$(wildcard $d/compat3_13.h))
|
||||
else
|
||||
RECORDTYPES += calcout
|
||||
endif
|
||||
|
||||
@ -54,5 +52,7 @@ streamReferences:
|
||||
perl ../src/makeref.pl Interface $(BUSSES) > $@
|
||||
perl ../src/makeref.pl Converter $(FORMATS) >> $@
|
||||
|
||||
stream.dbd:
|
||||
# have to hack a bit to work with both versions of driver.makefile
|
||||
DBDFILES = O.$${EPICSVERSION}_$${T_A}/streamSup.dbd
|
||||
../O.${EPICSVERSION}_${T_A}/streamSup.dbd:
|
||||
perl ../src/makedbd.pl $(RECORDTYPES) > $@
|
||||
|
@ -22,11 +22,6 @@
|
||||
#include "StreamError.h"
|
||||
#include "StreamBuffer.h"
|
||||
|
||||
#include <epicsVersion.h>
|
||||
#ifdef BASE_VERSION
|
||||
#define EPICS_3_13
|
||||
#endif
|
||||
|
||||
#ifdef EPICS_3_13
|
||||
#include <assert.h>
|
||||
#include <wdLib.h>
|
||||
@ -376,9 +371,11 @@ supportsEvent()
|
||||
intrCallbackInt32, this, &intrPvtInt32);
|
||||
return true;
|
||||
}
|
||||
error("%s: port does not allow to register for "
|
||||
const char *portname;
|
||||
pasynManager->getPortName(pasynUser, &portname);
|
||||
error("%s: port %s does not allow to register for "
|
||||
"Int32 interrupts: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
clientName(), portname, pasynUser->errorMessage);
|
||||
pasynInt32 = NULL;
|
||||
intrPvtInt32 = NULL;
|
||||
}
|
||||
@ -402,9 +399,11 @@ supportsEvent()
|
||||
intrCallbackUInt32, this, 0xFFFFFFFF, &intrPvtInt32);
|
||||
return true;
|
||||
}
|
||||
error("%s: port does not allow to register for "
|
||||
const char *portname;
|
||||
pasynManager->getPortName(pasynUser, &portname);
|
||||
error("%s: port %s does not allow to register for "
|
||||
"UInt32 interrupts: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
clientName(), portname, pasynUser->errorMessage);
|
||||
pasynUInt32 = NULL;
|
||||
intrPvtUInt32 = NULL;
|
||||
}
|
||||
@ -423,9 +422,15 @@ supportsAsyncRead()
|
||||
intrCallbackOctet, this, &intrPvtOctet) != asynSuccess)
|
||||
{
|
||||
const char *portname;
|
||||
int addr;
|
||||
pasynManager->getPortName(pasynUser, &portname);
|
||||
error("%s: asyn port %s does not support asynchronous input: %s\n",
|
||||
clientName(), portname, pasynUser->errorMessage);
|
||||
pasynManager->getAddr(pasynUser, &addr);
|
||||
if (addr >= 0)
|
||||
error("%s: asyn port %s addr %d does not support asynchronous input: %s\n",
|
||||
clientName(), portname, addr, pasynUser->errorMessage);
|
||||
else
|
||||
error("%s: asyn port %s does not support asynchronous input: %s\n",
|
||||
clientName(), portname, pasynUser->errorMessage);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -490,23 +495,14 @@ connectToBus(const char* portname, int addr)
|
||||
bool AsynDriverInterface::
|
||||
lockRequest(unsigned long lockTimeout_ms)
|
||||
{
|
||||
int connected;
|
||||
asynStatus status;
|
||||
|
||||
debug("AsynDriverInterface::lockRequest(%s, %ld msec)\n",
|
||||
clientName(), lockTimeout_ms);
|
||||
lockTimeout = lockTimeout_ms ? lockTimeout_ms*0.001 : -1.0;
|
||||
ioAction = Lock;
|
||||
status = pasynManager->isConnected(pasynUser, &connected);
|
||||
if (status != asynSuccess)
|
||||
{
|
||||
error("%s: pasynManager->isConnected() failed: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
return false;
|
||||
}
|
||||
status = pasynManager->queueRequest(pasynUser,
|
||||
connected ? priority() : asynQueuePriorityConnect,
|
||||
lockTimeout);
|
||||
priority(), lockTimeout);
|
||||
if (status != asynSuccess)
|
||||
{
|
||||
error("%s lockRequest: pasynManager->queueRequest() failed: %s\n",
|
||||
@ -534,7 +530,7 @@ connectToAsynPort()
|
||||
connected ? "yes" : "no");
|
||||
if (status != asynSuccess)
|
||||
{
|
||||
error("%s: pasynManager->isConnected() failed: %s\n",
|
||||
error("%s connectToAsynPort: pasynManager->isConnected() failed: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
return false;
|
||||
}
|
||||
@ -578,7 +574,7 @@ connectToAsynPort()
|
||||
clientName(), asynStatusStr[status]);
|
||||
if (status != asynSuccess)
|
||||
{
|
||||
error("%s: pasynCommon->connect() failed: %s\n",
|
||||
error("%s connectToAsynPort: pasynCommon->connect() failed: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
return false;
|
||||
}
|
||||
@ -597,25 +593,14 @@ void AsynDriverInterface::
|
||||
lockHandler()
|
||||
{
|
||||
asynStatus status;
|
||||
int connected;
|
||||
|
||||
debug("AsynDriverInterface::lockHandler(%s)\n",
|
||||
clientName());
|
||||
|
||||
status = pasynManager->isConnected(pasynUser, &connected);
|
||||
if (status != asynSuccess)
|
||||
{
|
||||
error("%s: pasynManager->isConnected() failed: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
lockCallback(StreamIoFault);
|
||||
return;
|
||||
}
|
||||
if (!connected) lockCallback(StreamIoFault);
|
||||
|
||||
status = pasynManager->blockProcessCallback(pasynUser, false);
|
||||
if (status != asynSuccess)
|
||||
{
|
||||
error("%s: pasynManager->blockProcessCallback() failed: %s\n",
|
||||
error("%s lockHandler: pasynManager->blockProcessCallback() failed: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
lockCallback(StreamIoFault);
|
||||
return;
|
||||
@ -634,9 +619,8 @@ unlock()
|
||||
status = pasynManager->unblockProcessCallback(pasynUser, false);
|
||||
if (status != asynSuccess)
|
||||
{
|
||||
error("%s: pasynManager->unblockProcessCallback() failed: %s\n",
|
||||
error("%s unlock: pasynManager->unblockProcessCallback() failed: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
lockCallback(StreamIoFault);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -682,23 +666,32 @@ writeHandler()
|
||||
size_t written = 0;
|
||||
|
||||
pasynUser->timeout = 0;
|
||||
if (pasynGpib)
|
||||
pasynOctet->flush(pvtOctet, pasynUser);
|
||||
else
|
||||
if (!pasynGpib)
|
||||
// discard any early input, but forward it to potential async records
|
||||
// thus do not use pasynOctet->flush()
|
||||
// unfortunately we cannot do this with GPIB because addressing a device as talker
|
||||
// when it has nothing to say is an error. Also timeout=0 does not help here (would need
|
||||
// a change in asynGPIB), thus use flush() for GPIB.
|
||||
do {
|
||||
char buffer [256];
|
||||
size_t received = 0;
|
||||
int eomReason = 0;
|
||||
debug("AsynDriverInterface::writeHandler(%s): reading old input\n",
|
||||
clientName());
|
||||
status = pasynOctet->read(pvtOctet, pasynUser,
|
||||
buffer, sizeof(buffer), &received, &eomReason);
|
||||
if (received == 0) break;
|
||||
if (status == asynError || received == 0) break;
|
||||
#ifndef NO_TEMPORARY
|
||||
if (received) debug("AsynDriverInterface::writeHandler(%s): flushing %ld bytes: \"%s\"\n",
|
||||
clientName(), (long)received, StreamBuffer(buffer, received).expand()());
|
||||
#endif
|
||||
} while (status == asynSuccess);
|
||||
else
|
||||
{
|
||||
debug("AsynDriverInterface::writeHandler(%s): flushing old input\n",
|
||||
clientName());
|
||||
pasynOctet->flush(pvtOctet, pasynUser);
|
||||
}
|
||||
|
||||
// discard any early events
|
||||
receivedEvent = 0;
|
||||
@ -733,6 +726,12 @@ writeHandler()
|
||||
clientName(), (long)outputSize, (long)written,
|
||||
pasynUser->timeout, asynStatusStr[status]);
|
||||
|
||||
if (oldeoslen >= 0) // restore asyn terminator
|
||||
{
|
||||
pasynOctet->setOutputEos(pvtOctet, pasynUser,
|
||||
oldeos, oldeoslen);
|
||||
}
|
||||
|
||||
// Up to asyn 4.17 I can't see when the server has disconnected. Why?
|
||||
int connected;
|
||||
pasynManager->isConnected(pasynUser, &connected);
|
||||
@ -740,17 +739,12 @@ writeHandler()
|
||||
"device is %sconnected\n",
|
||||
clientName(),connected?"":"dis");
|
||||
if (!connected) {
|
||||
error("%s: connection closed in write\n",
|
||||
error("%s: write failed because connection was closed by device\n",
|
||||
clientName());
|
||||
writeCallback(StreamIoFault);
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldeoslen >= 0) // restore asyn terminator
|
||||
{
|
||||
pasynOctet->setOutputEos(pvtOctet, pasynUser,
|
||||
oldeos, oldeoslen);
|
||||
}
|
||||
switch (status)
|
||||
{
|
||||
case asynSuccess:
|
||||
@ -775,32 +769,34 @@ writeHandler()
|
||||
writeCallback(StreamIoSuccess);
|
||||
return;
|
||||
case asynTimeout:
|
||||
error("%s: asynTimeout (%g sec) in write. Asyn says: %s\n",
|
||||
clientName(), pasynUser->timeout, pasynUser->errorMessage);
|
||||
writeCallback(StreamIoTimeout);
|
||||
return;
|
||||
case asynOverflow:
|
||||
error("%s: asynOverflow in write: %s\n",
|
||||
error("%s: asynOverflow in write. Asyn driver says: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
writeCallback(StreamIoFault);
|
||||
return;
|
||||
case asynError:
|
||||
error("%s: asynError in write: %s\n",
|
||||
error("%s: asynError in write. Asyn driver says: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
writeCallback(StreamIoFault);
|
||||
return;
|
||||
#ifdef ASYN_VERSION // asyn >= 4.14
|
||||
case asynDisconnected:
|
||||
error("%s: asynDisconnected in write: %s\n",
|
||||
error("%s: asynDisconnected in write. Asyn driver says: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
writeCallback(StreamIoFault);
|
||||
return;
|
||||
case asynDisabled:
|
||||
error("%s: asynDisconnected in write: %s\n",
|
||||
error("%s: asynDisconnected in write. Asyn driver says: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
writeCallback(StreamIoFault);
|
||||
return;
|
||||
#endif
|
||||
default:
|
||||
error("%s: unknown asyn error in write: %s\n",
|
||||
error("%s: unknown asyn error in write. Asyn driver says: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
writeCallback(StreamIoFault);
|
||||
return;
|
||||
@ -1098,29 +1094,29 @@ readHandler()
|
||||
}
|
||||
peeksize = inputBuffer.capacity();
|
||||
// deliver whatever we could save
|
||||
error("%s: asynOverflow in read: %s\n",
|
||||
error("%s: asynOverflow in read. Asyn driver says: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
readCallback(StreamIoFault, buffer, received);
|
||||
break;
|
||||
case asynError:
|
||||
error("%s: asynError in read: %s\n",
|
||||
error("%s: asynError in read. Asyn driver says: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
readCallback(StreamIoFault, buffer, received);
|
||||
break;
|
||||
#ifdef ASYN_VERSION // asyn >= 4.14
|
||||
case asynDisconnected:
|
||||
error("%s: asynDisconnected in read: %s\n",
|
||||
error("%s: asynDisconnected in read. Asyn driver says: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
readCallback(StreamIoFault);
|
||||
return;
|
||||
case asynDisabled:
|
||||
error("%s: asynDisconnected in read: %s\n",
|
||||
error("%s: asynDisconnected in read. Asyn driver says: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
readCallback(StreamIoFault);
|
||||
return;
|
||||
#endif
|
||||
default:
|
||||
error("%s: unknown asyn error in read: %s\n",
|
||||
error("%s: unknown asyn error in read. Asyn driver says: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
readCallback(StreamIoFault);
|
||||
return;
|
||||
|
@ -130,7 +130,7 @@ public:
|
||||
StreamBuffer& append(const StreamBuffer& s)
|
||||
{return append(s.buffer+s.offs, s.len);}
|
||||
|
||||
// operator += alias for set
|
||||
// operator += alias for append
|
||||
StreamBuffer& operator+=(char c)
|
||||
{return append(c);}
|
||||
|
||||
|
@ -20,13 +20,7 @@
|
||||
#include "StreamBusInterface.h"
|
||||
#include "StreamError.h"
|
||||
|
||||
const char* StreamIoStatusStr[] = {
|
||||
"StreamIoSuccess",
|
||||
"StreamIoTimeout",
|
||||
"StreamIoNoReply",
|
||||
"StreamIoEnd",
|
||||
"StreamIoFault"
|
||||
};
|
||||
StreamIoStatusStrClass StreamIoStatusStr;
|
||||
|
||||
StreamBusInterfaceRegistrarBase* StreamBusInterfaceRegistrarBase::first;
|
||||
|
||||
|
@ -21,13 +21,26 @@
|
||||
#define StreamBusInterface_h
|
||||
|
||||
#include <stddef.h>
|
||||
#include <StreamBuffer.h>
|
||||
|
||||
enum StreamIoStatus {
|
||||
StreamIoSuccess, StreamIoTimeout, StreamIoNoReply,
|
||||
StreamIoEnd, StreamIoFault
|
||||
};
|
||||
|
||||
extern const char* StreamIoStatusStr[];
|
||||
class StreamIoStatusStrClass {
|
||||
public:
|
||||
const char* operator [] (int index) {
|
||||
switch (index) {
|
||||
case StreamIoSuccess: return "StreamIoSuccess";
|
||||
case StreamIoTimeout: return "StreamIoTimeout";
|
||||
case StreamIoNoReply: return "StreamIoNoReply";
|
||||
case StreamIoEnd: return "StreamIoEnd";
|
||||
case StreamIoFault: return "StreamIoFault";
|
||||
default: return "illegal status";
|
||||
}
|
||||
}
|
||||
} extern StreamIoStatusStr;
|
||||
|
||||
class StreamBusInterface
|
||||
{
|
||||
@ -89,6 +102,9 @@ public:
|
||||
bool busDisconnect() {
|
||||
return businterface && businterface->disconnectRequest();
|
||||
}
|
||||
void busPrintStatus(StreamBuffer& buffer) {
|
||||
if (businterface) businterface->printStatus(buffer);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
@ -137,6 +153,7 @@ protected:
|
||||
virtual bool connectRequest(unsigned long connecttimeout_ms);
|
||||
virtual bool disconnectRequest();
|
||||
virtual void finish();
|
||||
virtual void printStatus(StreamBuffer& buffer) {};
|
||||
|
||||
// pure virtual
|
||||
virtual bool lockRequest(unsigned long timeout_ms) = 0;
|
||||
|
@ -59,7 +59,7 @@ static char* printCommands(StreamBuffer& buffer, const char* c)
|
||||
break;
|
||||
case wait_cmd:
|
||||
timeout = extract<unsigned long>(c);
|
||||
buffer.print(" wait %ld;\n # ms", timeout);
|
||||
buffer.print(" wait %ld; # ms\n", timeout);
|
||||
break;
|
||||
case event_cmd:
|
||||
eventnumber = extract<unsigned long>(c);
|
||||
@ -763,8 +763,8 @@ printValue(const StreamFormat& fmt, long value)
|
||||
name(), value);
|
||||
return false;
|
||||
}
|
||||
debug("StreamCore::printValue(%s, long): \"%s\"\n",
|
||||
name(), outputLine.expand()());
|
||||
debug("StreamCore::printValue %s %%%c long %ld (%lx): \"%s\"\n",
|
||||
name(), fmt.conv, value, value, outputLine.expand()());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -785,8 +785,8 @@ printValue(const StreamFormat& fmt, double value)
|
||||
name(), value);
|
||||
return false;
|
||||
}
|
||||
debug("StreamCore::printValue(%s, double): \"%s\"\n",
|
||||
name(), outputLine.expand()());
|
||||
debug("StreamCore::printValue %s %%%c double %#g: \"%s\"\n",
|
||||
name(), fmt.conv, value, outputLine.expand()());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -808,8 +808,8 @@ printValue(const StreamFormat& fmt, char* value)
|
||||
name(), buffer.expand()());
|
||||
return false;
|
||||
}
|
||||
debug("StreamCore::printValue(%s, char*): \"%s\"\n",
|
||||
name(), outputLine.expand()());
|
||||
debug("StreamCore::printValue %s %%%c char* \"%s\"): \"%s\"\n",
|
||||
name(), fmt.conv, value, outputLine.expand()());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -818,7 +818,7 @@ lockCallback(StreamIoStatus status)
|
||||
{
|
||||
MutexLock lock(this);
|
||||
debug("StreamCore::lockCallback(%s, status=%s)\n",
|
||||
name(), status ? "Timeout" : "Success");
|
||||
name(), StreamIoStatusStr[status]);
|
||||
if (!(flags & LockPending))
|
||||
{
|
||||
error("StreamCore::lockCallback(%s) called unexpectedly\n",
|
||||
@ -832,11 +832,21 @@ lockCallback(StreamIoStatus status)
|
||||
case StreamIoSuccess:
|
||||
break;
|
||||
case StreamIoTimeout:
|
||||
error("%s: Cannot lock device within %ld ms\n",
|
||||
error("%s: Cannot lock device within %ld ms, device seems to be busy\n",
|
||||
name(), lockTimeout);
|
||||
flags &= ~BusOwner;
|
||||
finishProtocol(LockTimeout);
|
||||
return;
|
||||
case StreamIoFault:
|
||||
error("%s: Locking failed because of a device fault\n",
|
||||
name());
|
||||
flags &= ~BusOwner;
|
||||
finishProtocol(LockTimeout);
|
||||
return;
|
||||
default:
|
||||
error("StreamCore::lockCallback(%s) unexpected status %s\n",
|
||||
name(), StreamIoStatusStr[status]);
|
||||
flags &= ~BusOwner;
|
||||
finishProtocol(Fault);
|
||||
return;
|
||||
}
|
||||
@ -1309,8 +1319,8 @@ normal_format:
|
||||
inputLine.length()-consumedInput > 20 ? "..." : "",
|
||||
formatstring());
|
||||
else
|
||||
error("%s: Format \"%%%s\" has data type %s which does not match variable \"%s\".\n",
|
||||
name(), formatstring(), StreamFormatTypeStr[fmt.type], fieldName);
|
||||
error("%s: Format \"%%%s\" has data type %s which does not match the type of \"%s\".\n",
|
||||
name(), formatstring(), StreamFormatTypeStr[fmt.type], fieldAddress ? fieldName : name());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1740,4 +1750,25 @@ disconnectCallback(StreamIoStatus status)
|
||||
}
|
||||
}
|
||||
|
||||
void StreamCore::
|
||||
printStatus(StreamBuffer& buffer)
|
||||
{
|
||||
buffer.print("active command=%s ",
|
||||
activeCommand ? commandName(*activeCommand) : "NULL");
|
||||
buffer.print("flags=0x%04lx ", flags);
|
||||
if (flags & IgnoreExtraInput) buffer.append("IgnoreExtraInput ");
|
||||
if (flags & InitRun) buffer.append("InitRun ");
|
||||
if (flags & AsyncMode) buffer.append("AsyncMode ");
|
||||
if (flags & GotValue) buffer.append("GotValue ");
|
||||
if (flags & BusOwner) buffer.append("BusOwner ");
|
||||
if (flags & Separator) buffer.append("Separator ");
|
||||
if (flags & ScanTried) buffer.append("ScanTried ");
|
||||
if (flags & AcceptInput) buffer.append("AcceptInput ");
|
||||
if (flags & AcceptEvent) buffer.append("AcceptEvent ");
|
||||
if (flags & LockPending) buffer.append("LockPending ");
|
||||
if (flags & WritePending) buffer.append("WritePending ");
|
||||
if (flags & WaitPending) buffer.append("WaitPending ");
|
||||
busPrintStatus(buffer);
|
||||
}
|
||||
|
||||
#include "streamReferences"
|
||||
|
@ -219,6 +219,7 @@ public:
|
||||
bool parse(const char* filename, const char* protocolname);
|
||||
void printProtocol();
|
||||
const char* name() { return streamname; }
|
||||
void printStatus(StreamBuffer& buffer);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -270,7 +270,7 @@ epicsExportRegistrar(streamRegistrar);
|
||||
struct stream_drvsup {
|
||||
long number;
|
||||
long (*report)(int);
|
||||
DRVSUPFUN init;
|
||||
long (*init)();
|
||||
} stream = {
|
||||
2,
|
||||
Stream::report,
|
||||
@ -350,6 +350,12 @@ report(int interest)
|
||||
{
|
||||
printf(" %s: %s\n", pstream->name(),
|
||||
pstream->ioLink->value.instio.string);
|
||||
if (interest == 3)
|
||||
{
|
||||
StreamBuffer buffer;
|
||||
pstream->printStatus(buffer);
|
||||
printf(" %s\n", buffer());
|
||||
}
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
@ -410,6 +416,7 @@ long streamInit(int after)
|
||||
long streamInitRecord(dbCommon* record, const struct link *ioLink,
|
||||
streamIoFunction readData, streamIoFunction writeData)
|
||||
{
|
||||
long status;
|
||||
char filename[80];
|
||||
char protocol[80];
|
||||
char busname[80];
|
||||
@ -435,13 +442,14 @@ long streamInitRecord(dbCommon* record, const struct link *ioLink,
|
||||
// scan the i/o link
|
||||
debug("streamInitRecord(%s): parse link \"%s\"\n",
|
||||
record->name, ioLink->value.instio.string);
|
||||
pstream->parseLink(ioLink, filename, protocol,
|
||||
status = pstream->parseLink(ioLink, filename, protocol,
|
||||
busname, &addr, busparam);
|
||||
// (re)initialize bus and protocol
|
||||
debug("streamInitRecord(%s): calling initRecord\n",
|
||||
record->name);
|
||||
long status = pstream->initRecord(filename, protocol,
|
||||
busname, addr, busparam);
|
||||
if (status == 0)
|
||||
status = pstream->initRecord(filename, protocol,
|
||||
busname, addr, busparam);
|
||||
if (status != OK && status != DO_NOT_CONVERT)
|
||||
{
|
||||
error("%s: Record initialization failed\n", record->name);
|
||||
@ -957,13 +965,13 @@ getFieldAddress(const char* fieldname, StreamBuffer& address)
|
||||
else
|
||||
{
|
||||
// FIELD in this record or VAL in other record
|
||||
char fullname[PVNAME_SZ + 1];
|
||||
sprintf(fullname, "%s.%s", name(), fieldname);
|
||||
if (dbNameToAddr(fullname, &dbaddr) != OK)
|
||||
StreamBuffer fullname;
|
||||
fullname.print("%s.%s", name(), fieldname);
|
||||
if (dbNameToAddr(fullname(), &dbaddr) != OK)
|
||||
{
|
||||
// VAL in other record
|
||||
sprintf(fullname, "%s.VAL", fieldname);
|
||||
if (dbNameToAddr(fullname, &dbaddr) != OK) return false;
|
||||
fullname.clear().print("%s.VAL", fieldname);
|
||||
if (dbNameToAddr(fullname(), &dbaddr) != OK) return false;
|
||||
}
|
||||
}
|
||||
address.append(&dbaddr, sizeof(dbaddr));
|
||||
@ -990,11 +998,8 @@ formatValue(const StreamFormat& format, const void* fieldaddress)
|
||||
// Format like "%([record.]field)..." has requested to get value
|
||||
// from field of this or other record.
|
||||
DBADDR* pdbaddr = (DBADDR*)fieldaddress;
|
||||
long i;
|
||||
long nelem = pdbaddr->no_elements;
|
||||
size_t size = nelem * typeSize[format.type];
|
||||
char* buffer = fieldBuffer.clear().reserve(size);
|
||||
|
||||
/* Handle time stamps special. %T converter takes double. */
|
||||
if (strcmp(((dbFldDes*)pdbaddr->pfldDes)->name, "TIME") == 0)
|
||||
{
|
||||
double time;
|
||||
@ -1010,6 +1015,8 @@ formatValue(const StreamFormat& format, const void* fieldaddress)
|
||||
/* if getting time from own record, update timestamp first */
|
||||
recGblGetTimeStamp(record);
|
||||
}
|
||||
/* convert EPICS epoch (1990) to unix epoch (1970) */
|
||||
/* we are losing about 3 digits precision here */
|
||||
time = pdbaddr->precord->time.secPastEpoch +
|
||||
631152000u + pdbaddr->precord->time.nsec * 1e-9;
|
||||
debug("Stream::formatValue(%s): read %f from TIME field\n",
|
||||
@ -1017,7 +1024,29 @@ formatValue(const StreamFormat& format, const void* fieldaddress)
|
||||
return printValue(format, time);
|
||||
}
|
||||
|
||||
if (dbGet(pdbaddr, dbfMapping[format.type], buffer,
|
||||
/* convert type to LONG, ENUM, DOUBLE, or STRING */
|
||||
int type = dbfMapping[format.type];
|
||||
long nelem = pdbaddr->no_elements;
|
||||
size_t size = nelem * typeSize[format.type];
|
||||
|
||||
/* print (U)CHAR arrays as string */
|
||||
if (format.type == string_format &&
|
||||
(pdbaddr->field_type == DBF_CHAR || pdbaddr->field_type == DBF_UCHAR))
|
||||
{
|
||||
debug("Stream::formatValue(%s): format %s.%s array[%ld] size %d of %s as string\n",
|
||||
name(),
|
||||
pdbaddr->precord->name,
|
||||
((dbFldDes*)pdbaddr->pfldDes)->name,
|
||||
nelem,
|
||||
pdbaddr->field_size,
|
||||
pamapdbfType[pdbaddr->field_type].strvalue);
|
||||
type = DBF_CHAR;
|
||||
size = nelem;
|
||||
}
|
||||
|
||||
char* buffer = fieldBuffer.clear().reserve(size);
|
||||
|
||||
if (dbGet(pdbaddr, type, buffer,
|
||||
NULL, &nelem, NULL) != 0)
|
||||
{
|
||||
error("%s: dbGet(%s.%s, %s) failed\n",
|
||||
@ -1027,6 +1056,18 @@ formatValue(const StreamFormat& format, const void* fieldaddress)
|
||||
pamapdbfType[dbfMapping[format.type]].strvalue);
|
||||
return false;
|
||||
}
|
||||
debug("Stream::formatValue(%s): got %ld elements\n",
|
||||
name(),nelem);
|
||||
|
||||
/* terminate CHAR array as string */
|
||||
if (type == DBF_CHAR)
|
||||
{
|
||||
if (nelem >= pdbaddr->no_elements) nelem = pdbaddr->no_elements-1;
|
||||
buffer[nelem] = 0;
|
||||
nelem = 1; /* array is only 1 string */
|
||||
}
|
||||
|
||||
long i;
|
||||
for (i = 0; i < nelem; i++)
|
||||
{
|
||||
switch (format.type)
|
||||
@ -1054,6 +1095,7 @@ formatValue(const StreamFormat& format, const void* fieldaddress)
|
||||
error("%s: %%(FIELD) syntax not allowed "
|
||||
"with pseudo formats\n",
|
||||
name());
|
||||
return false;
|
||||
default:
|
||||
error("INTERNAL ERROR %s: Illegal format.type=%d\n",
|
||||
name(), format.type);
|
||||
|
@ -26,6 +26,24 @@
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* timezone in UNIX contains the seconds between UTC and local time,
|
||||
but not in Free-BSD! Here timezone() is a function delivering
|
||||
the time zone abbreviation (e.g. CET). Alternatively, the timezone
|
||||
value can also be gained from tm_gmtoff of the tm-structure.
|
||||
HJK, 4.4.14 */
|
||||
/* The same seems to be true for other BSDs. DZ. */
|
||||
|
||||
#if defined(__FreeBSD__) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__bsdi__ ) || \
|
||||
defined(__DragonFly__)
|
||||
static int timezone_bsd=0;
|
||||
#define timezone timezone_bsd
|
||||
#define tzset() { struct tm tm; time_t timet; tzset(); time(&timet); \
|
||||
localtime_r(&timet, &tm); timezone=tm.tm_gmtoff; }
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define tzset() _tzset()
|
||||
#define timezone _timezone
|
||||
@ -46,6 +64,13 @@ int timezone = 0;
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
/* MinGW has no re-entrant localtime. How about other environments? */
|
||||
/* Just let's hope for the best */
|
||||
#undef localtime_r
|
||||
#define localtime_r(timet,tm) (*(tm)=*localtime(timet))
|
||||
#endif
|
||||
|
||||
class TimestampConverter : public StreamFormatConverter
|
||||
{
|
||||
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||
@ -366,7 +391,7 @@ startover:
|
||||
debug ("TimestampConverter::scantime: %s hour = %d\n", pm?"PM":"AM", tm->tm_hour);
|
||||
break;
|
||||
case 'M': /* minute */
|
||||
i = nummatch(input, 1, 59);
|
||||
i = nummatch(input, 0, 59);
|
||||
if (i < 0)
|
||||
{
|
||||
error ("error parsing minute: '%.20s'\n", input);
|
||||
@ -376,7 +401,7 @@ startover:
|
||||
debug ("TimestampConverter::scantime: min = %d\n", tm->tm_min);
|
||||
break;
|
||||
case 'S': /* second */
|
||||
i = nummatch(input, 1, 60);
|
||||
i = nummatch(input, 0, 60);
|
||||
if (i < 0)
|
||||
{
|
||||
error ("error parsing week second: '%.20s'\n", input);
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
#define STREAM_MAJOR 2
|
||||
#define STREAM_MINOR 6
|
||||
#define STREAM_PATCHLEVEL 3
|
||||
#define STREAM_PATCHLEVEL 6
|
||||
|
||||
#if defined(__vxworks) || defined(vxWorks)
|
||||
#include <vxWorks.h>
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "devStream.h"
|
||||
#include <aiRecord.h>
|
||||
#include <menuConvert.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
static long readData (dbCommon *record, format_t *format)
|
||||
@ -45,6 +46,11 @@ static long readData (dbCommon *record, format_t *format)
|
||||
{
|
||||
long rval;
|
||||
if (streamScanf (record, format, &rval)) return ERROR;
|
||||
if (ai->linr == menuConvertNO_CONVERSION)
|
||||
{
|
||||
ai->val = (double) rval;
|
||||
return DO_NOT_CONVERT;
|
||||
}
|
||||
ai->rval = rval;
|
||||
return OK;
|
||||
}
|
||||
@ -67,6 +73,10 @@ static long writeData (dbCommon *record, format_t *format)
|
||||
}
|
||||
case DBF_LONG:
|
||||
{
|
||||
if (ai->linr == menuConvertNO_CONVERSION)
|
||||
{
|
||||
return streamPrintf (record, format, (long) ai->val);
|
||||
}
|
||||
return streamPrintf (record, format, (long) ai->rval);
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ proc receiveHandler {sock} {
|
||||
"start" {
|
||||
set wait [checkNum [lindex $l 1]]
|
||||
set ::counter 0
|
||||
after $wait sendAsync $wait [list [lrange $l 2 end-1]]
|
||||
after $wait [list sendAsync $wait "[string range $a [string wordend $a 7] end]"]
|
||||
sendReply $sock "Started\n"
|
||||
}
|
||||
"stop" {
|
||||
@ -133,7 +133,7 @@ proc receiveHandler {sock} {
|
||||
proc sendAsync {wait message} {
|
||||
if {$::counter < 0} return
|
||||
foreach term [array names ::socket] {
|
||||
sendReply $::socket($term) "Message number [incr ::counter] $message\n";
|
||||
sendReply $::socket($term) "Message number [incr ::counter]$message";
|
||||
}
|
||||
after $wait sendAsync $wait [list $message]
|
||||
}
|
||||
|
Reference in New Issue
Block a user