Compare commits
74 Commits
stream_2_4
...
stream_2_5
Author | SHA1 | Date | |
---|---|---|---|
9049baf730 | |||
050a165a82 | |||
1428b85a34 | |||
e4f8a6ed40 | |||
5a5b42cb67 | |||
e62553eca6 | |||
0846c1dd5b | |||
774e88241a | |||
03a04a51b6 | |||
103e74be03 | |||
129cc61759 | |||
70073e1b69 | |||
c94c1a1e70 | |||
07026b03ae | |||
5a6d293a5f | |||
d51d6648e0 | |||
f521da8606 | |||
b64d486925 | |||
7f1f1c1e65 | |||
2dc0918926 | |||
37d412108a | |||
f03af416eb | |||
82066af0e0 | |||
9c18afb178 | |||
04c6cb50d7 | |||
382784526c | |||
a91496884c | |||
7cdec03dcb | |||
3e5e4b8375 | |||
f8b944f325 | |||
c7e7878d9e | |||
5717dd6345 | |||
2fe3b5c68d | |||
db88081fd7 | |||
1230c01646 | |||
8142dd27eb | |||
19279b208a | |||
9619c359c1 | |||
6b948abc2d | |||
2c7391602a | |||
fd0fccda46 | |||
1164413bd2 | |||
7e1e038ecd | |||
2a8b0aed56 | |||
c856dec6dd | |||
53bb235ff1 | |||
29ac760f0e | |||
7836af6423 | |||
1af9c6ea55 | |||
8c619d3350 | |||
0155d5ab69 | |||
8252b629f5 | |||
494661c0e7 | |||
5b652abd25 | |||
a3e68d7f7d | |||
7cc19d2614 | |||
318d0e389b | |||
8dbe3abcdb | |||
649d775cd3 | |||
a941061a29 | |||
100b7d4543 | |||
1eb8a25432 | |||
9b6f8b3386 | |||
cc1bb004f2 | |||
ab6a6b730d | |||
3d928c49a0 | |||
8fe70f2e39 | |||
862686aeef | |||
2fa54cdfb1 | |||
d987a9abb9 | |||
d37c142d36 | |||
35768cbfbb | |||
5494aae1ba | |||
18ba904d6c |
83
Makefile
83
Makefile
@ -1,70 +1,21 @@
|
||||
include /ioc/tools/driver.makefile
|
||||
EXCLUDE_VERSIONS = 3.13.2
|
||||
PROJECT=stream2
|
||||
BUILDCLASSES += Linux
|
||||
TOP = ..
|
||||
|
||||
#DOCUDIR = doc
|
||||
DIRS = src
|
||||
|
||||
DBDS = stream.dbd
|
||||
|
||||
BUSSES += AsynDriver
|
||||
FORMATS += Enum
|
||||
FORMATS += BCD
|
||||
FORMATS += Raw
|
||||
FORMATS += RawFloat
|
||||
FORMATS += Binary
|
||||
FORMATS += Checksum
|
||||
FORMATS += Regexp
|
||||
FORMATS += MantissaExponent
|
||||
RECORDTYPES += aai aao
|
||||
RECORDTYPES += ao ai
|
||||
RECORDTYPES += bo bi
|
||||
RECORDTYPES += mbbo mbbi
|
||||
RECORDTYPES += mbboDirect mbbiDirect
|
||||
RECORDTYPES += longout longin
|
||||
RECORDTYPES += stringout stringin
|
||||
RECORDTYPES += waveform
|
||||
|
||||
SOURCES += $(RECORDTYPES:%=src/dev%Stream.c)
|
||||
SOURCES += $(FORMATS:%=src/%Converter.cc)
|
||||
SOURCES += $(BUSSES:%=src/%Interface.cc)
|
||||
SOURCES += $(wildcard src/Stream*.cc)
|
||||
SOURCES += src/StreamVersion.c
|
||||
SOURCES_3.14 += src/devcalcoutStream.c
|
||||
|
||||
HEADERS += StreamFormat.h
|
||||
HEADERS += StreamFormatConverter.h
|
||||
HEADERS += StreamBuffer.h
|
||||
HEADERS += StreamError.h
|
||||
|
||||
ifeq (${EPICS_BASETYPE},3.13)
|
||||
USR_INCLUDES += -include $(INSTALL_INCLUDE)/compat3_13.h
|
||||
endif
|
||||
|
||||
StreamCore.o: streamReferences
|
||||
|
||||
streamReferences:
|
||||
@for i in $(BUSSES); \
|
||||
do echo "extern void* ref_$${i}Interface;"; \
|
||||
echo "void* p$$i = ref_$${i}Interface;"; \
|
||||
done > $@
|
||||
@for i in $(FORMATS); \
|
||||
do echo "extern void* ref_$${i}Converter;"; \
|
||||
echo "void* p$$i = ref_$${i}Converter;"; \
|
||||
done >> $@
|
||||
|
||||
ifeq (${EPICS_BASETYPE},3.13)
|
||||
stream.dbd:
|
||||
@for r in $(RECORDTYPES); \
|
||||
do echo "device($$r,INST_IO,dev$${r}Stream,\"stream\")"; \
|
||||
done > $@
|
||||
@echo "driver(stream)" >> $@
|
||||
# Look if we have EPICS R3.13 or R3.14
|
||||
ifeq ($(wildcard $(TOP)/configure),)
|
||||
# EPICS R3.13
|
||||
include $(TOP)/config/CONFIG_APP
|
||||
CONFIG = $(TOP)/config
|
||||
else
|
||||
stream.dbd:
|
||||
@for r in $(RECORDTYPES) calcout; \
|
||||
do echo "device($$r,INST_IO,dev$${r}Stream,\"stream\")"; \
|
||||
done > $@
|
||||
@echo "driver(stream)" >> $@
|
||||
@echo "variable(streamDebug, int)" >> $@
|
||||
@echo "registrar(streamRegistrar)" >> $@
|
||||
# EPICS R3.14
|
||||
include $(TOP)/configure/CONFIG
|
||||
ifneq ($(words $(CALC) $(SYNAPPS)), 0)
|
||||
# with synApps calc module (contains scalcout)
|
||||
DIRS += srcSynApps
|
||||
endif
|
||||
endif
|
||||
|
||||
DIRS += streamApp
|
||||
|
||||
include $(CONFIG)/RULES_DIRS
|
||||
|
72
makefile
Normal file
72
makefile
Normal file
@ -0,0 +1,72 @@
|
||||
include /ioc/tools/driver.makefile
|
||||
EXCLUDE_VERSIONS = 3.13.2
|
||||
PROJECT=stream2
|
||||
BUILDCLASSES += Linux
|
||||
|
||||
#DOCUDIR = doc
|
||||
|
||||
DBDS = stream.dbd
|
||||
|
||||
BUSSES += AsynDriver
|
||||
FORMATS += Enum
|
||||
FORMATS += BCD
|
||||
FORMATS += Raw
|
||||
FORMATS += RawFloat
|
||||
FORMATS += Binary
|
||||
FORMATS += Checksum
|
||||
FORMATS += Regexp
|
||||
FORMATS += MantissaExponent
|
||||
FORMATS += Timestamp
|
||||
|
||||
RECORDTYPES += aai aao
|
||||
RECORDTYPES += ao ai
|
||||
RECORDTYPES += bo bi
|
||||
RECORDTYPES += mbbo mbbi
|
||||
RECORDTYPES += mbboDirect mbbiDirect
|
||||
RECORDTYPES += longout longin
|
||||
RECORDTYPES += stringout stringin
|
||||
RECORDTYPES += waveform
|
||||
|
||||
SOURCES += $(RECORDTYPES:%=src/dev%Stream.c)
|
||||
SOURCES += $(FORMATS:%=src/%Converter.cc)
|
||||
SOURCES += $(BUSSES:%=src/%Interface.cc)
|
||||
SOURCES += $(wildcard src/Stream*.cc)
|
||||
SOURCES += src/StreamVersion.c
|
||||
SOURCES_3.14 += src/devcalcoutStream.c
|
||||
|
||||
HEADERS += StreamFormat.h
|
||||
HEADERS += StreamFormatConverter.h
|
||||
HEADERS += StreamBuffer.h
|
||||
HEADERS += StreamError.h
|
||||
|
||||
ifeq (${EPICS_BASETYPE},3.13)
|
||||
USR_INCLUDES += -include $(INSTALL_INCLUDE)/compat3_13.h
|
||||
endif
|
||||
|
||||
StreamCore.o: streamReferences
|
||||
|
||||
streamReferences:
|
||||
@for i in $(BUSSES); \
|
||||
do echo "extern void* ref_$${i}Interface;"; \
|
||||
echo "void* p$$i = ref_$${i}Interface;"; \
|
||||
done > $@
|
||||
@for i in $(FORMATS); \
|
||||
do echo "extern void* ref_$${i}Converter;"; \
|
||||
echo "void* p$$i = ref_$${i}Converter;"; \
|
||||
done >> $@
|
||||
|
||||
ifeq (${EPICS_BASETYPE},3.13)
|
||||
stream.dbd:
|
||||
@for r in $(RECORDTYPES); \
|
||||
do echo "device($$r,INST_IO,dev$${r}Stream,\"stream\")"; \
|
||||
done > $@
|
||||
@echo "driver(stream)" >> $@
|
||||
else
|
||||
stream.dbd:
|
||||
@for r in $(RECORDTYPES) calcout; \
|
||||
do echo "device($$r,INST_IO,dev$${r}Stream,\"stream\")"; \
|
||||
done > $@
|
||||
@echo "driver(stream)" >> $@
|
||||
@echo "variable(streamDebug, int)" >> $@
|
||||
@echo "registrar(streamRegistrar)" >> $@
|
||||
endif
|
@ -663,6 +663,23 @@ writeHandler()
|
||||
clientName(), pasynUser->errorMessage);
|
||||
writeCallback(StreamIoFault);
|
||||
return;
|
||||
#ifdef ASYN_VERSION // asyn >= 4.14
|
||||
case asynDisconnected:
|
||||
error("%s: asynDisconnected in write: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
writeCallback(StreamIoFault);
|
||||
return;
|
||||
case asynDisabled:
|
||||
error("%s: asynDisconnected in write: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
writeCallback(StreamIoFault);
|
||||
return;
|
||||
#endif
|
||||
default:
|
||||
error("%s: unknown asyn error in write: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
writeCallback(StreamIoFault);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -722,38 +739,44 @@ readHandler()
|
||||
streameos = getInTerminator(streameoslen);
|
||||
deveos = streameos;
|
||||
deveoslen = streameoslen;
|
||||
if (streameos) do // streameos == NULL means: don't change eos
|
||||
if (streameos) // streameos == NULL means: don't change eos
|
||||
{
|
||||
asynStatus status;
|
||||
status = pasynOctet->getInputEos(pvtOctet,
|
||||
pasynUser, oldeos, sizeof(oldeos)-1, &oldeoslen);
|
||||
if (status != asynSuccess)
|
||||
{
|
||||
oldeoslen = -1;
|
||||
// No EOS support?
|
||||
}
|
||||
// device (e.g. GPIB) might not accept full eos length
|
||||
if (pasynOctet->setInputEos(pvtOctet, pasynUser,
|
||||
deveos, deveoslen) == asynSuccess)
|
||||
{
|
||||
#ifndef NO_TEMPORARY
|
||||
if (ioAction != AsyncRead)
|
||||
if (streameos[0])
|
||||
{
|
||||
debug("AsynDriverInterface::readHandler(%s) "
|
||||
"input EOS set to %s\n",
|
||||
clientName(),
|
||||
StreamBuffer(deveos, deveoslen).expand()());
|
||||
error("%s: warning: No input EOS support.\n",
|
||||
clientName());
|
||||
}
|
||||
oldeoslen = -1;
|
||||
} else do {
|
||||
// device (e.g. GPIB) might not accept full eos length
|
||||
if (pasynOctet->setInputEos(pvtOctet, pasynUser,
|
||||
deveos, deveoslen) == asynSuccess)
|
||||
{
|
||||
#ifndef NO_TEMPORARY
|
||||
if (ioAction != AsyncRead)
|
||||
{
|
||||
debug("AsynDriverInterface::readHandler(%s) "
|
||||
"input EOS set to %s\n",
|
||||
clientName(),
|
||||
StreamBuffer(deveos, deveoslen).expand()());
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
deveos++; deveoslen--;
|
||||
if (!deveoslen)
|
||||
{
|
||||
error("%s: warning: pasynOctet->setInputEos() failed: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
}
|
||||
} while (deveoslen);
|
||||
break;
|
||||
}
|
||||
deveos++; deveoslen--;
|
||||
if (!deveoslen)
|
||||
{
|
||||
error("%s: warning: pasynOctet->setInputEos() failed: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
}
|
||||
} while (deveoslen);
|
||||
}
|
||||
|
||||
int bytesToRead = peeksize;
|
||||
long buffersize;
|
||||
@ -806,6 +829,16 @@ readHandler()
|
||||
asynStatusStr[status]);
|
||||
}
|
||||
// pasynOctet->read() has already cut off terminator.
|
||||
|
||||
if (status == asynTimeout &&
|
||||
pasynUser->timeout == 0.0 &&
|
||||
received > 0)
|
||||
{
|
||||
// Jens Eden (PTB) pointed out that polling asynInterposeEos
|
||||
// with timeout = 0.0 returns asynTimeout even when bytes
|
||||
// have been received, but not yet the terminator.
|
||||
status = asynSuccess;
|
||||
}
|
||||
|
||||
switch (status)
|
||||
{
|
||||
@ -887,8 +920,8 @@ readHandler()
|
||||
// read timeout
|
||||
#ifndef NO_TEMPORARY
|
||||
debug("AsynDriverInterface::readHandler(%s): "
|
||||
"ioAction=%s, timeout after %d of %d bytes \"%s\"\n",
|
||||
clientName(), ioActionStr[ioAction],
|
||||
"ioAction=%s, timeout [%f seconds] after %d of %d bytes \"%s\"\n",
|
||||
clientName(), ioActionStr[ioAction], pasynUser->timeout,
|
||||
(int)received, bytesToRead,
|
||||
StreamBuffer(buffer, received).expand()());
|
||||
#endif
|
||||
@ -922,6 +955,23 @@ readHandler()
|
||||
clientName(), pasynUser->errorMessage);
|
||||
readCallback(StreamIoFault, buffer, received);
|
||||
break;
|
||||
#ifdef ASYN_VERSION // asyn >= 4.14
|
||||
case asynDisconnected:
|
||||
error("%s: asynDisconnected in read: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
writeCallback(StreamIoFault);
|
||||
return;
|
||||
case asynDisabled:
|
||||
error("%s: asynDisconnected in read: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
writeCallback(StreamIoFault);
|
||||
return;
|
||||
#endif
|
||||
default:
|
||||
error("%s: unknown asyn error in read: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
writeCallback(StreamIoFault);
|
||||
return;
|
||||
}
|
||||
if (!readMore) break;
|
||||
if (readMore > 0)
|
||||
|
@ -30,6 +30,8 @@ SYNAPPS_RECORDS += scalcout
|
||||
# asynDriver interface is added automatically
|
||||
# if ASYN is defined in your RELEASE file.
|
||||
# BUSSES += Debug
|
||||
BUSSES += Debug
|
||||
BUSSES += Dummy
|
||||
|
||||
# You may add more format converters
|
||||
# This requires the naming convention
|
||||
@ -42,6 +44,7 @@ FORMATS += RawFloat
|
||||
FORMATS += Binary
|
||||
FORMATS += Checksum
|
||||
FORMATS += MantissaExponent
|
||||
FORMATS += Timestamp
|
||||
|
||||
# Want Perl regular expression matching?
|
||||
# If PCRE is installed at the same location for all
|
||||
@ -66,10 +69,6 @@ endif
|
||||
# by "static IoccrfReg iocshReg;"
|
||||
# LOADABLE_MODULE = YES
|
||||
|
||||
# Want to add some memory tracing
|
||||
# to find memory leaks?
|
||||
# USE_MEMGUARD = YES
|
||||
|
||||
# Sources of Stream Kernel
|
||||
# Do not modify
|
||||
|
||||
|
@ -488,6 +488,9 @@ static checksum checksumMap[] =
|
||||
{"crc16r", crc_0x8005_r, 0x0000, 0x0000, 2}, // 0xBB3D
|
||||
{"ccitt16", crc_0x1021, 0xFFFF, 0x0000, 2}, // 0x29B1
|
||||
{"ccitt16a",crc_0x1021, 0x1D0F, 0x0000, 2}, // 0xE5CC
|
||||
{"ccitt16x",crc_0x1021, 0x0000, 0x0000, 2}, // 0x31C3
|
||||
{"crc16c", crc_0x1021, 0x0000, 0x0000, 2}, // 0x31C3
|
||||
{"xmodem", crc_0x1021, 0x0000, 0x0000, 2}, // 0x31C3
|
||||
{"crc32", crc_0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, 4}, // 0xFC891918
|
||||
{"crc32r", crc_0x04C11DB7_r, 0xFFFFFFFF, 0xFFFFFFFF, 4}, // 0xCBF43926
|
||||
{"jamcrc", crc_0x04C11DB7_r, 0xFFFFFFFF, 0x00000000, 4}, // 0x340BC6D9
|
||||
|
76
src/DummyInterface.cc
Normal file
76
src/DummyInterface.cc
Normal file
@ -0,0 +1,76 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 2011 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is the interface to a "dummy" bus driver for *
|
||||
* StreamDevice. It does not provide any I/O functionality. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
|
||||
#include "StreamBusInterface.h"
|
||||
#include "StreamError.h"
|
||||
#include "StreamBuffer.h"
|
||||
|
||||
class DummyInterface : StreamBusInterface
|
||||
{
|
||||
DummyInterface(Client* client);
|
||||
|
||||
// StreamBusInterface methods
|
||||
bool lockRequest(unsigned long lockTimeout_ms);
|
||||
bool unlock();
|
||||
|
||||
protected:
|
||||
~DummyInterface();
|
||||
|
||||
public:
|
||||
// static creator method
|
||||
static StreamBusInterface* getBusInterface(Client* client,
|
||||
const char* busname, int addr, const char* param);
|
||||
};
|
||||
|
||||
RegisterStreamBusInterface(DummyInterface);
|
||||
|
||||
DummyInterface::
|
||||
DummyInterface(Client* client) : StreamBusInterface(client)
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
DummyInterface::
|
||||
~DummyInterface()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
StreamBusInterface* DummyInterface::
|
||||
getBusInterface(Client* client,
|
||||
const char* busname, int addr, const char*)
|
||||
{
|
||||
if (strcmp(busname, "dummy") == 0)
|
||||
{
|
||||
DummyInterface* interface = new DummyInterface(client);
|
||||
return interface;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool DummyInterface::
|
||||
lockRequest(unsigned long lockTimeout_ms)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DummyInterface::
|
||||
unlock()
|
||||
{
|
||||
return false;
|
||||
}
|
26
src/Makefile
26
src/Makefile
@ -65,19 +65,14 @@ ifdef PCRE
|
||||
LIB_LIBS += pcre
|
||||
else
|
||||
ifneq ($(words $(PCRE_LIB) $(PCRE_INCLUDE)),0)
|
||||
LIB_SYS_LIBS += pcre
|
||||
LIB_SYS_LIBS_DEFAULT += pcre
|
||||
LIB_SYS_LIBS_WIN32 += $(PCRE_LIB)\\pcre
|
||||
SHRLIB_DEPLIB_DIRS += $(PCRE_LIB)
|
||||
endif
|
||||
endif
|
||||
|
||||
LIB_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
ifeq ($(USE_MEMGUARD),YES)
|
||||
# memguard looks for memory leaks (gcc only)
|
||||
CPPFLAGS += -include ../memguard.h
|
||||
LIB_SRCS += memguard.cc
|
||||
endif
|
||||
|
||||
INC += devStream.h
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
@ -92,22 +87,11 @@ FORCE:
|
||||
StreamCore$(OBJ): streamReferences
|
||||
|
||||
streamReferences: ../CONFIG_STREAM
|
||||
@for i in $(BUSSES); \
|
||||
do echo "extern void* ref_$${i}Interface;"; \
|
||||
echo "void* p$$i = ref_$${i}Interface;"; \
|
||||
done > $@
|
||||
@for i in $(FORMATS); \
|
||||
do echo "extern void* ref_$${i}Converter;"; \
|
||||
echo "void* p$$i = ref_$${i}Converter;"; \
|
||||
done >> $@
|
||||
$(PERL) ../makeref.pl Interface $(BUSSES) > $@
|
||||
$(PERL) ../makeref.pl Converter $(FORMATS) >> $@
|
||||
|
||||
# create stream.dbd from all RECORDS
|
||||
$(COMMON_DIR)/$(LIBRARY_DEFAULT).dbd: ../CONFIG_STREAM
|
||||
@for r in $(RECORDS); \
|
||||
do echo "device($$r,INST_IO,dev$${r}Stream,\"stream\")"; \
|
||||
done > $@
|
||||
@echo "driver(stream)" >> $@
|
||||
@echo "variable(streamDebug, int)" >> $@
|
||||
@echo "registrar(streamRegistrar)" >> $@
|
||||
$(PERL) ../makedbd.pl $(RECORDS) > $@
|
||||
|
||||
endif
|
||||
|
@ -44,8 +44,8 @@ class MantissaExponentConverter : public StreamFormatConverter
|
||||
};
|
||||
|
||||
int MantissaExponentConverter::
|
||||
parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
const char*& source, bool scanFormat)
|
||||
parse(const StreamFormat&, StreamBuffer&,
|
||||
const char*&, bool)
|
||||
{
|
||||
return double_format;
|
||||
}
|
||||
|
@ -40,10 +40,10 @@ parse(const StreamFormat& format, StreamBuffer&,
|
||||
if (!endian) {
|
||||
union {long l; char c [sizeof(long)];} u;
|
||||
u.l=1;
|
||||
if (u.c[0]) { endian = 1234;} // little endian
|
||||
else if (u.c[sizeof(long)-1]) { endian = 4321;} // big endian
|
||||
if (u.c[0]) { endian = 1234;} // little endian
|
||||
else if (u.c[sizeof(long)-1]) { endian = 4321;} // big endian
|
||||
else {
|
||||
error ("Cannot find out byte order for %%R format.\n");
|
||||
error ("Cannot find out byte order for %%R format.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -64,16 +64,16 @@ printDouble(const StreamFormat& format, StreamBuffer& output, double value)
|
||||
float fval;
|
||||
char bytes[8];
|
||||
} buffer;
|
||||
|
||||
|
||||
nbOfBytes = format.width;
|
||||
if (nbOfBytes == 0)
|
||||
nbOfBytes = 4;
|
||||
|
||||
if (nbOfBytes == 4)
|
||||
buffer.fval = value;
|
||||
else
|
||||
buffer.fval = (float)value;
|
||||
else
|
||||
buffer.dval = value;
|
||||
|
||||
|
||||
if (!(format.flags & alt_flag) ^ (endian == 4321))
|
||||
{
|
||||
// swap if byte orders differ
|
||||
@ -86,7 +86,7 @@ printDouble(const StreamFormat& format, StreamBuffer& output, double value)
|
||||
{
|
||||
output.append(buffer.bytes[n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ scanDouble(const StreamFormat& format, const char* input, double& value)
|
||||
float fval;
|
||||
char bytes[8];
|
||||
} buffer;
|
||||
|
||||
|
||||
nbOfBytes = format.width;
|
||||
if (nbOfBytes == 0)
|
||||
nbOfBytes = 4;
|
||||
@ -110,7 +110,7 @@ scanDouble(const StreamFormat& format, const char* input, double& value)
|
||||
{
|
||||
return(nbOfBytes); // just skip input
|
||||
}
|
||||
|
||||
|
||||
if (!(format.flags & alt_flag) ^ (endian == 4321))
|
||||
{
|
||||
// swap if byte orders differ
|
||||
@ -127,7 +127,7 @@ scanDouble(const StreamFormat& format, const char* input, double& value)
|
||||
|
||||
if (nbOfBytes == 4)
|
||||
value = buffer.fval;
|
||||
else
|
||||
else
|
||||
value = buffer.dval;
|
||||
|
||||
return nbOfBytes;
|
||||
|
@ -46,7 +46,7 @@ init(const void* s, long minsize)
|
||||
else
|
||||
{
|
||||
// clear local buffer
|
||||
memset(buffer+minsize, 0, cap-minsize);
|
||||
memset(buffer, 0, cap);
|
||||
}
|
||||
if (s) {
|
||||
len = minsize;
|
||||
@ -54,6 +54,13 @@ init(const void* s, long minsize)
|
||||
}
|
||||
}
|
||||
|
||||
// How the buffer looks like:
|
||||
// |----free-----|####used####|-------free-------|
|
||||
///|<--- offs -->|<-- len --->|<- cap-offs-len ->|
|
||||
// 0 offs offs+len cap
|
||||
// |<-------------- minsize --------------->
|
||||
|
||||
|
||||
void StreamBuffer::
|
||||
grow(long minsize)
|
||||
{
|
||||
@ -266,9 +273,18 @@ StreamBuffer StreamBuffer::expand(long start, long length) const
|
||||
if (start < 0)
|
||||
{
|
||||
start += len;
|
||||
if (start < 0) start = 0;
|
||||
}
|
||||
end = length >= 0 ? start+length : len;
|
||||
if (length < 0)
|
||||
{
|
||||
start += length;
|
||||
length = -length;
|
||||
}
|
||||
if (start < 0)
|
||||
{
|
||||
length += start;
|
||||
start = 0;
|
||||
}
|
||||
end = start+length;
|
||||
if (end > len) end = len;
|
||||
StreamBuffer result((end-start)*2);
|
||||
start += offs;
|
||||
|
@ -35,26 +35,30 @@ class StreamBuffer
|
||||
long offs;
|
||||
char* buffer;
|
||||
|
||||
void grow(long);
|
||||
void init(const void*, long);
|
||||
void init(const void* s, long minsize);
|
||||
|
||||
void check(long size)
|
||||
{if (len+offs+size >= cap) grow(len+size);}
|
||||
|
||||
void grow(long minsize);
|
||||
|
||||
public:
|
||||
// Hints:
|
||||
// * Any index parameter (long) can be negative
|
||||
// meaning "count from end" (-1 is the last byte)
|
||||
// * Appending negative count deletes from end
|
||||
// * Any returned char* pointer becomes invalid when
|
||||
// the StreamBuffer is modified.
|
||||
// * End of StreamBuffer always contains 0x00 bytes
|
||||
// * Deleting from start and clearing is fast
|
||||
|
||||
StreamBuffer()
|
||||
{init(NULL, 0);}
|
||||
|
||||
StreamBuffer(const void*s, long size)
|
||||
StreamBuffer(const void* s, long size)
|
||||
{init(s, size);}
|
||||
|
||||
StreamBuffer(const char*s)
|
||||
StreamBuffer(const char* s)
|
||||
{init(s, s?strlen(s):0);}
|
||||
|
||||
StreamBuffer(const StreamBuffer& s)
|
||||
@ -68,10 +72,10 @@ public:
|
||||
|
||||
// operator (): get char* pointing to index
|
||||
const char* operator()(long index=0) const
|
||||
{buffer[offs+len]=0; return buffer+offs+(index<0?index+len:index);}
|
||||
{return buffer+offs+(index<0?index+len:index);}
|
||||
|
||||
char* operator()(long index=0)
|
||||
{buffer[offs+len]=0; return buffer+offs+(index<0?index+len:index);}
|
||||
{return buffer+offs+(index<0?index+len:index);}
|
||||
|
||||
// operator []: get byte at index
|
||||
char operator[](long index) const
|
||||
@ -103,11 +107,16 @@ public:
|
||||
// reserve: reserve size bytes of memory and return
|
||||
// pointer to that memory (for copying something to it)
|
||||
char* reserve(long size)
|
||||
{grow(size); char* p=buffer+len; len+=size; return p;}
|
||||
{check(size); char* p=buffer+offs+len; len+=size; return p;}
|
||||
|
||||
// append: append data at the end of the buffer
|
||||
StreamBuffer& append(char c, long count=1)
|
||||
{check(count); while(count-->0) buffer[offs+len++]=c; return *this;}
|
||||
StreamBuffer& append(char c)
|
||||
{check(1); buffer[offs+len++]=c; return *this;}
|
||||
|
||||
StreamBuffer& append(char c, long count)
|
||||
{if (count < 0) truncate(count);
|
||||
else {check(count); memset(buffer+offs+len, c, count); len+=count;}
|
||||
return *this;}
|
||||
|
||||
StreamBuffer& append(const void* s, long size);
|
||||
|
||||
@ -116,6 +125,16 @@ public:
|
||||
|
||||
StreamBuffer& append(const StreamBuffer& s)
|
||||
{return append(s.buffer+s.offs, s.len);}
|
||||
|
||||
// operator += alias for set
|
||||
StreamBuffer& operator+=(char c)
|
||||
{return append(c);}
|
||||
|
||||
StreamBuffer& operator+=(const char* s)
|
||||
{return append(s);}
|
||||
|
||||
StreamBuffer& operator+=(const StreamBuffer& s)
|
||||
{return append(s);}
|
||||
|
||||
// set: clear buffer and fill with new data
|
||||
StreamBuffer& set(const void* s, long size)
|
||||
@ -127,7 +146,7 @@ public:
|
||||
StreamBuffer& set(const StreamBuffer& s)
|
||||
{clear(); return append(s.buffer+s.offs, s.len);}
|
||||
|
||||
// operator =: alias for set
|
||||
// operator = alias for set
|
||||
StreamBuffer& operator=(const char* s)
|
||||
{return set(s);}
|
||||
|
||||
@ -148,6 +167,7 @@ public:
|
||||
StreamBuffer& remove(long pos, long length)
|
||||
{return replace(pos, length, NULL, 0);}
|
||||
|
||||
// remove from start: no memset, no function call, fast!
|
||||
StreamBuffer& remove(long length)
|
||||
{if (length>len) length=len;
|
||||
offs+=length; len-=length; return *this;}
|
||||
@ -188,17 +208,20 @@ public:
|
||||
long int find(const StreamBuffer& s, long start=0) const
|
||||
{return find(s.buffer+s.offs, s.len, start);}
|
||||
|
||||
// equals: returns true if first size bytes are equal
|
||||
bool equals(const void* s, long size) const
|
||||
// startswith: returns true if first size bytes are equal
|
||||
bool startswith(const void* s, long size) const
|
||||
{return len>=size ? memcmp(buffer+offs, s, size) == 0 : false;}
|
||||
|
||||
// equals: returns true if first string is equal (empty string match)
|
||||
bool equals(const char* s) const
|
||||
// startswith: returns true if first string is equal (empty string matches)
|
||||
bool startswith(const char* s) const
|
||||
{return len ? strcmp(buffer+offs, s) == 0 : !s || !*s;}
|
||||
|
||||
// expand: create copy of StreamBuffer where all nonprintable characters
|
||||
// are replaced by <xx> with xx being the hex code of the characters
|
||||
StreamBuffer expand(long start=0, long length=-1) const;
|
||||
StreamBuffer expand(long start, long length) const;
|
||||
|
||||
StreamBuffer expand(long start=0) const
|
||||
{return expand(start, len);}
|
||||
|
||||
// dump: debug function, like expand but also show the 'hidden' memory
|
||||
// before and after the real data. Uses colours.
|
||||
|
@ -39,7 +39,6 @@ static char* printCommands(StreamBuffer& buffer, const char* c)
|
||||
{
|
||||
unsigned long timeout;
|
||||
unsigned long eventnumber;
|
||||
unsigned short cmdlen;
|
||||
while (1)
|
||||
{
|
||||
switch(*c++)
|
||||
@ -67,7 +66,6 @@ static char* printCommands(StreamBuffer& buffer, const char* c)
|
||||
break;
|
||||
case exec_cmd:
|
||||
buffer.append(" exec \"");
|
||||
cmdlen = extract<unsigned short>(c);
|
||||
c = StreamProtocolParser::printString(buffer, c);
|
||||
buffer.append("\";\n");
|
||||
break;
|
||||
@ -325,7 +323,7 @@ compileCommand(StreamProtocolParser::Protocol* protocol,
|
||||
{
|
||||
if (!busSupportsEvent())
|
||||
{
|
||||
protocol->errorMsg(getLineNumber(command),
|
||||
error(getLineNumber(command), protocol->filename(),
|
||||
"Events not supported by businterface.\n");
|
||||
return false;
|
||||
}
|
||||
@ -339,7 +337,7 @@ compileCommand(StreamProtocolParser::Protocol* protocol,
|
||||
}
|
||||
if (*args != ')')
|
||||
{
|
||||
protocol->errorMsg(getLineNumber(command),
|
||||
error(getLineNumber(command), protocol->filename(),
|
||||
"Expect ')' instead of: '%s'\n", args);
|
||||
return false;
|
||||
}
|
||||
@ -383,7 +381,7 @@ compileCommand(StreamProtocolParser::Protocol* protocol,
|
||||
return true;
|
||||
}
|
||||
|
||||
protocol->errorMsg(getLineNumber(command),
|
||||
error(getLineNumber(command), protocol->filename(),
|
||||
"Unknown command name '%s'\n", command);
|
||||
return false;
|
||||
}
|
||||
@ -504,6 +502,7 @@ finishProtocol(ProtocolResult status)
|
||||
break;
|
||||
default:
|
||||
// get rid of all the rubbish whe might have collected
|
||||
unparsedInput = false;
|
||||
inputBuffer.clear();
|
||||
handler = NULL;
|
||||
}
|
||||
@ -590,9 +589,9 @@ evalCommand()
|
||||
bool StreamCore::
|
||||
evalOut()
|
||||
{
|
||||
inputBuffer.clear(); // flush all unread input
|
||||
// flush all unread input
|
||||
unparsedInput = false;
|
||||
outputLine.clear();
|
||||
inputBuffer.clear();
|
||||
if (!formatOutput())
|
||||
{
|
||||
finishProtocol(FormatError);
|
||||
@ -634,13 +633,15 @@ formatOutput()
|
||||
const char* fieldName = NULL;
|
||||
const char* formatstring;
|
||||
int formatstringlen;
|
||||
|
||||
outputLine.clear();
|
||||
while ((command = *commandIndex++) != StreamProtocolParser::eos)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case StreamProtocolParser::format_field:
|
||||
{
|
||||
debug("StreamCore::formatOutput(%s): StreamProtocolParser::format_field\n",
|
||||
debug("StreamCore::formatOutput(%s): StreamProtocolParser::redirect_format\n",
|
||||
name());
|
||||
// code layout:
|
||||
// field <eos> addrlen AddressStructure formatstring <eos> StreamFormat [info]
|
||||
@ -649,9 +650,12 @@ formatOutput()
|
||||
unsigned short addrlen = extract<unsigned short>(commandIndex);
|
||||
fieldAddress.set(commandIndex, addrlen);
|
||||
commandIndex += addrlen;
|
||||
goto normal_format;
|
||||
}
|
||||
case StreamProtocolParser::format:
|
||||
{
|
||||
fieldAddress.clear();
|
||||
normal_format:
|
||||
// code layout:
|
||||
// formatstring <eos> StreamFormat [info]
|
||||
formatstring = commandIndex;
|
||||
@ -663,6 +667,7 @@ formatOutput()
|
||||
}
|
||||
formatstringlen = commandIndex-formatstring;
|
||||
commandIndex++;
|
||||
|
||||
StreamFormat fmt = extract<StreamFormat>(commandIndex);
|
||||
fmt.info = commandIndex; // point to info string
|
||||
commandIndex += fmt.infolen;
|
||||
@ -670,6 +675,7 @@ formatOutput()
|
||||
debug("StreamCore::formatOutput(%s): format = %%%s\n",
|
||||
name(), StreamBuffer(formatstring, formatstringlen).expand()());
|
||||
#endif
|
||||
|
||||
if (fmt.type == pseudo_format)
|
||||
{
|
||||
if (!StreamFormatConverter::find(fmt.conv)->
|
||||
@ -685,7 +691,7 @@ formatOutput()
|
||||
if (!formatValue(fmt, fieldAddress ? fieldAddress() : NULL))
|
||||
{
|
||||
StreamBuffer formatstr(formatstring, formatstringlen);
|
||||
if (fieldName)
|
||||
if (fieldAddress)
|
||||
error("%s: Cannot format field '%s' with '%%%s'\n",
|
||||
name(), fieldName, formatstr.expand()());
|
||||
else
|
||||
@ -693,10 +699,12 @@ formatOutput()
|
||||
name(), formatstr.expand()());
|
||||
return false;
|
||||
}
|
||||
fieldAddress.clear();
|
||||
fieldName = NULL;
|
||||
continue;
|
||||
}
|
||||
case StreamProtocolParser::whitespace:
|
||||
outputLine.append(' ');
|
||||
case StreamProtocolParser::skip:
|
||||
continue;
|
||||
case esc:
|
||||
// escaped literal byte
|
||||
command = *commandIndex++;
|
||||
@ -718,12 +726,21 @@ printSeparator()
|
||||
}
|
||||
if (!separator) return;
|
||||
long i = 0;
|
||||
if (separator[0] == ' ') i++; // ignore leading space
|
||||
for (; i < separator.length(); i++)
|
||||
{
|
||||
if (separator[i] == StreamProtocolParser::skip) continue; // wildcard
|
||||
if (separator[i] == esc) i++; // escaped literal byte
|
||||
outputLine.append(separator[i]);
|
||||
switch (separator[i])
|
||||
{
|
||||
case StreamProtocolParser::whitespace:
|
||||
outputLine.append(' '); // print single space
|
||||
case StreamProtocolParser::skip:
|
||||
continue;
|
||||
case esc:
|
||||
// escaped literal byte
|
||||
i++;
|
||||
default:
|
||||
// literal byte
|
||||
outputLine.append(separator[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -744,6 +761,8 @@ printValue(const StreamFormat& fmt, long value)
|
||||
name(), value);
|
||||
return false;
|
||||
}
|
||||
debug("StreamCore::printValue(%s, long): \"%s\"\n",
|
||||
name(), outputLine.expand()());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -764,6 +783,8 @@ printValue(const StreamFormat& fmt, double value)
|
||||
name(), value);
|
||||
return false;
|
||||
}
|
||||
debug("StreamCore::printValue(%s, double): \"%s\"\n",
|
||||
name(), outputLine.expand()());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -785,6 +806,8 @@ printValue(const StreamFormat& fmt, char* value)
|
||||
name(), buffer.expand()());
|
||||
return false;
|
||||
}
|
||||
debug("StreamCore::printValue(%s, char*): \"%s\"\n",
|
||||
name(), outputLine.expand()());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -804,8 +827,6 @@ lockCallback(StreamIoStatus status)
|
||||
flags |= BusOwner;
|
||||
if (status != StreamIoSuccess)
|
||||
{
|
||||
error("%s: Lock timeout\n",
|
||||
name());
|
||||
finishProtocol(LockTimeout);
|
||||
return;
|
||||
}
|
||||
@ -927,7 +948,6 @@ readCallback(StreamIoStatus status,
|
||||
return 0;
|
||||
}
|
||||
//// flags &= ~AcceptInput;
|
||||
unparsedInput = false;
|
||||
switch (status)
|
||||
{
|
||||
case StreamIoTimeout:
|
||||
@ -984,7 +1004,27 @@ readCallback(StreamIoStatus status,
|
||||
if (inTerminator)
|
||||
{
|
||||
// look for terminator
|
||||
end = inputBuffer.find(inTerminator);
|
||||
// performance issue for long inputs that come in chunks:
|
||||
// do not parse old chunks again or performance decreases to O(n^2)
|
||||
// but make sure to get all terminators in multi-line input
|
||||
|
||||
long start;
|
||||
if (unparsedInput)
|
||||
{
|
||||
// multi-line input sets 'unparsedInput' and removes the line
|
||||
// remaining unparsed lines are left at start of inputBuffer
|
||||
start = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// long line does not set 'unparsedInput' but keeps
|
||||
// already parsed chunks in inputBuffer
|
||||
// start parsing at beginning of new data
|
||||
// but beware of split terminators
|
||||
start = inputBuffer.length() - size - inTerminator.length();
|
||||
if (start < 0) start = 0;
|
||||
}
|
||||
end = inputBuffer.find(inTerminator, start);
|
||||
if (end >= 0)
|
||||
{
|
||||
termlen = inTerminator.length();
|
||||
@ -1041,6 +1081,7 @@ readCallback(StreamIoStatus status,
|
||||
{
|
||||
debug("StreamCore::readCallback(%s) async timeout: just restart\n",
|
||||
name());
|
||||
unparsedInput = false;
|
||||
inputBuffer.clear();
|
||||
commandIndex = commandStart;
|
||||
evalIn();
|
||||
@ -1065,6 +1106,10 @@ readCallback(StreamIoStatus status,
|
||||
name(), inputBuffer.expand()());
|
||||
unparsedInput = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
unparsedInput = false;
|
||||
}
|
||||
if (!matches)
|
||||
{
|
||||
if (status == StreamIoTimeout)
|
||||
@ -1107,7 +1152,9 @@ matchInput()
|
||||
is installed and starts with 'in' (then we reparse the input).
|
||||
*/
|
||||
char command;
|
||||
const char* fieldName = NULL;
|
||||
const char* formatstring;
|
||||
int formatstringlen;
|
||||
|
||||
consumedInput = 0;
|
||||
|
||||
@ -1119,22 +1166,38 @@ matchInput()
|
||||
{
|
||||
// code layout:
|
||||
// field <StreamProtocolParser::eos> addrlen AddressStructure formatstring <StreamProtocolParser::eos> StreamFormat [info]
|
||||
fieldName = commandIndex;
|
||||
commandIndex += strlen(commandIndex)+1;
|
||||
unsigned short addrlen = extract<unsigned short>(commandIndex);
|
||||
fieldAddress.set(commandIndex, addrlen);
|
||||
commandIndex += addrlen;
|
||||
goto normal_format;
|
||||
}
|
||||
case StreamProtocolParser::format:
|
||||
{
|
||||
fieldAddress.clear();
|
||||
normal_format:
|
||||
int consumed;
|
||||
// code layout:
|
||||
// formatstring <eos> StreamFormat [info]
|
||||
formatstring = commandIndex;
|
||||
while (*commandIndex++ != StreamProtocolParser::eos); // jump after <eos>
|
||||
// jump after <eos>
|
||||
while (*commandIndex)
|
||||
{
|
||||
if (*commandIndex == esc) commandIndex++;
|
||||
commandIndex++;
|
||||
}
|
||||
formatstringlen = commandIndex-formatstring;
|
||||
commandIndex++;
|
||||
|
||||
StreamFormat fmt = extract<StreamFormat>(commandIndex);
|
||||
fmt.info = commandIndex;
|
||||
fmt.info = commandIndex; // point to info string
|
||||
commandIndex += fmt.infolen;
|
||||
#ifndef NO_TEMPORARY
|
||||
debug("StreamCore::matchInput(%s): format = %%%s\n",
|
||||
name(), StreamBuffer(formatstring, formatstringlen).expand()());
|
||||
#endif
|
||||
|
||||
if (fmt.flags & skip_flag || fmt.type == pseudo_format)
|
||||
{
|
||||
long ldummy;
|
||||
@ -1185,6 +1248,56 @@ matchInput()
|
||||
consumedInput += consumed;
|
||||
break;
|
||||
}
|
||||
if (fmt.flags & compare_flag)
|
||||
{
|
||||
outputLine.clear();
|
||||
flags &= ~Separator;
|
||||
if (!formatValue(fmt, fieldAddress ? fieldAddress() : NULL))
|
||||
{
|
||||
StreamBuffer formatstr(formatstring, formatstringlen);
|
||||
if (fieldAddress)
|
||||
error("%s: Cannot format field '%s' with '%%%s'\n",
|
||||
name(), fieldName, formatstr.expand()());
|
||||
else
|
||||
error("%s: Cannot format value with '%%%s'\n",
|
||||
name(), formatstr.expand()());
|
||||
return false;
|
||||
}
|
||||
#ifndef NO_TEMPORARY
|
||||
debug("StreamCore::matchInput(%s): compare \"%s\" with \"%s\"\n",
|
||||
name(), inputLine.expand(consumedInput,
|
||||
outputLine.length())(), outputLine.expand()());
|
||||
#endif
|
||||
if (inputLine.length() - consumedInput < outputLine.length())
|
||||
{
|
||||
if (!(flags & AsyncMode) && onMismatch[0] != in_cmd)
|
||||
{
|
||||
error("%s: Input \"%s%s\" too short."
|
||||
" No match for format %%%s (\"%s\")\n",
|
||||
name(),
|
||||
inputLine.length() > 20 ? "..." : "",
|
||||
inputLine.expand(-20)(),
|
||||
formatstring,
|
||||
outputLine.expand()());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!outputLine.startswith(inputLine(consumedInput),outputLine.length()))
|
||||
{
|
||||
if (!(flags & AsyncMode) && onMismatch[0] != in_cmd)
|
||||
{
|
||||
error("%s: Input \"%s%s\" does not match"
|
||||
" format %%%s (\"%s\")\n",
|
||||
name(), inputLine.expand(consumedInput, 20)(),
|
||||
inputLine.length()-consumedInput > 20 ? "..." : "",
|
||||
formatstring,
|
||||
outputLine.expand()());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
consumedInput += outputLine.length();
|
||||
break;
|
||||
}
|
||||
flags &= ~Separator;
|
||||
if (!matchValue(fmt, fieldAddress ? fieldAddress() : NULL))
|
||||
{
|
||||
@ -1196,19 +1309,22 @@ matchInput()
|
||||
inputLine.length()-consumedInput > 20 ? "..." : "",
|
||||
formatstring);
|
||||
else
|
||||
error("%s: Can't scan value with format %%%s\n",
|
||||
name(), formatstring);
|
||||
error("%s: Format %%%s has data type %s which does not match this variable.\n",
|
||||
name(), formatstring, StreamFormatTypeStr[fmt.type] );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// matchValue() has already removed consumed bytes from inputBuffer
|
||||
fieldAddress = NULL;
|
||||
break;
|
||||
}
|
||||
case StreamProtocolParser::skip:
|
||||
// ignore next input byte
|
||||
consumedInput++;
|
||||
break;
|
||||
case StreamProtocolParser::whitespace:
|
||||
// any number of whitespace (including 0)
|
||||
while (isspace(inputLine[consumedInput])) consumedInput++;
|
||||
break;
|
||||
case esc:
|
||||
// escaped literal byte
|
||||
command = *commandIndex++;
|
||||
@ -1220,12 +1336,14 @@ matchInput()
|
||||
while (commandIndex[i] >= ' ') i++;
|
||||
if (!(flags & AsyncMode) && onMismatch[0] != in_cmd)
|
||||
{
|
||||
error("%s: Input \"%s%s\" too short."
|
||||
" No match for \"%s\"\n",
|
||||
error("%s: Input \"%s%s\" too short.\n",
|
||||
name(),
|
||||
inputLine.length() > 20 ? "..." : "",
|
||||
inputLine.expand(-20)(),
|
||||
inputLine.expand(-20)());
|
||||
#ifndef NO_TEMPORARY
|
||||
error("No match for \"%s\"\n",
|
||||
StreamBuffer(commandIndex-1,i+1).expand()());
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1243,10 +1361,12 @@ matchInput()
|
||||
consumedInput,
|
||||
consumedInput==1 ? "" : "s");
|
||||
|
||||
#ifndef NO_TEMPORARY
|
||||
error("%s: got \"%s\" where \"%s\" was expected\n",
|
||||
name(),
|
||||
inputLine.expand(consumedInput, 20)(),
|
||||
StreamBuffer(commandIndex-1,i+1).expand()());
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1282,36 +1402,45 @@ matchInput()
|
||||
bool StreamCore::
|
||||
matchSeparator()
|
||||
{
|
||||
// called before value is read, first value has Separator flag cleared
|
||||
// for second and next value set Separator flag
|
||||
|
||||
if (!separator) {
|
||||
// empty separator matches
|
||||
return true;
|
||||
}
|
||||
if (!(flags & Separator))
|
||||
{
|
||||
// before first element, don't expect separator yet
|
||||
flags |= Separator;
|
||||
return true;
|
||||
}
|
||||
if (!separator) return true;
|
||||
long i = 0;
|
||||
if (separator[0] == ' ')
|
||||
long i;
|
||||
long j = consumedInput;
|
||||
for (i = 0; i < separator.length(); i++)
|
||||
{
|
||||
i++;
|
||||
// skip leading whitespaces
|
||||
while (isspace(inputLine[consumedInput++]));
|
||||
switch (separator[i])
|
||||
{
|
||||
case StreamProtocolParser::skip:
|
||||
j++;
|
||||
continue;
|
||||
case StreamProtocolParser::whitespace:
|
||||
while (isspace(inputLine[j])) j++;
|
||||
continue;
|
||||
case esc:
|
||||
i++;
|
||||
default:
|
||||
if (separator[i] != inputLine[j])
|
||||
{
|
||||
// no match
|
||||
// don't complain here, just return false
|
||||
return false;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
for (; i < separator.length(); i++,consumedInput++)
|
||||
{
|
||||
if (!inputLine[consumedInput]) return false;
|
||||
if (separator[i] == StreamProtocolParser::skip) continue; // wildcard
|
||||
if (separator[i] == esc) i++; // escaped literal byte
|
||||
if (separator[i] != inputLine[consumedInput]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StreamCore::
|
||||
scanSeparator()
|
||||
{
|
||||
// for compatibility only
|
||||
// read and remove separator
|
||||
if (!matchSeparator()) return false;
|
||||
flags &= ~Separator;
|
||||
// separator successfully read
|
||||
consumedInput = j;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1360,7 +1489,7 @@ scanValue(const StreamFormat& fmt, double& value)
|
||||
long consumed = StreamFormatConverter::find(fmt.conv)->
|
||||
scanDouble(fmt, inputLine(consumedInput), value);
|
||||
debug("StreamCore::scanValue(%s, format=%%%c, double) input=\"%s\"\n",
|
||||
name(), fmt.conv, inputLine.expand(consumedInput)());
|
||||
name(), fmt.conv, inputLine.expand(consumedInput, 20)());
|
||||
if (consumed < 0)
|
||||
{
|
||||
if (fmt.flags & default_flag)
|
||||
@ -1514,8 +1643,8 @@ timerCallback()
|
||||
bool StreamCore::
|
||||
evalExec()
|
||||
{
|
||||
outputLine.clear();
|
||||
formatOutput();
|
||||
debug ("StreamCore::evalExec: command = \"%s\"\n", outputLine.expand()());
|
||||
// release bus
|
||||
if (flags & BusOwner)
|
||||
{
|
||||
|
@ -139,7 +139,6 @@ protected:
|
||||
long scanValue(const StreamFormat& format, double& value);
|
||||
long scanValue(const StreamFormat& format, char* value, long maxlen);
|
||||
long scanValue(const StreamFormat& format);
|
||||
bool scanSeparator(); // disencouraged
|
||||
|
||||
StreamBuffer protocolname;
|
||||
unsigned long lockTimeout;
|
||||
|
@ -156,7 +156,6 @@ class Stream : protected StreamCore
|
||||
friend long streamPrintf(dbCommon *record, format_t *format, ...);
|
||||
friend long streamScanfN(dbCommon *record, format_t *format,
|
||||
void*, size_t maxStringSize);
|
||||
friend long streamScanSep(dbCommon *record);
|
||||
friend long streamReload(char* recordname);
|
||||
|
||||
public:
|
||||
@ -173,16 +172,6 @@ epicsExportAddress(int, streamDebug);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MEMGUARD
|
||||
static const iocshFuncDef memguardReportDef =
|
||||
{ "memguardReport", 0, NULL };
|
||||
|
||||
static void memguardReportFunc (const iocshArgBuf *args)
|
||||
{
|
||||
memguardReport();
|
||||
}
|
||||
#endif
|
||||
|
||||
// for subroutine record
|
||||
extern "C" long streamReloadSub()
|
||||
{
|
||||
@ -251,9 +240,6 @@ extern "C" void streamReloadFunc (const iocshArgBuf *args)
|
||||
|
||||
static void streamRegistrar ()
|
||||
{
|
||||
#ifdef MEMGUARD
|
||||
iocshRegister(&memguardReportDef, memguardReportFunc);
|
||||
#endif
|
||||
iocshRegister(&reloadDef, streamReloadFunc);
|
||||
// make streamReload available for subroutine records
|
||||
registryFunctionAdd("streamReload",
|
||||
@ -352,7 +338,6 @@ report(int interest)
|
||||
pstream->ioLink->value.instio.string);
|
||||
}
|
||||
}
|
||||
StreamPrintTimestampFunction = streamEpicsPrintTimestamp;
|
||||
return OK;
|
||||
}
|
||||
|
||||
@ -489,15 +474,6 @@ long streamPrintf(dbCommon *record, format_t *format, ...)
|
||||
return success ? OK : ERROR;
|
||||
}
|
||||
|
||||
long streamScanSep(dbCommon* record)
|
||||
{
|
||||
// depreciated
|
||||
debug("streamScanSep(%s)\n", record->name);
|
||||
Stream* pstream = (Stream*)record->dpvt;
|
||||
if (!pstream) return ERROR;
|
||||
return pstream->scanSeparator() ? OK : ERROR;
|
||||
}
|
||||
|
||||
long streamScanfN(dbCommon* record, format_t *format,
|
||||
void* value, size_t maxStringSize)
|
||||
{
|
||||
@ -935,10 +911,15 @@ getFieldAddress(const char* fieldname, StreamBuffer& address)
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIELD in this record
|
||||
// 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) return false;
|
||||
if (dbNameToAddr(fullname, &dbaddr) != OK)
|
||||
{
|
||||
// VAL in other record
|
||||
sprintf(fullname, "%s.VAL", fieldname);
|
||||
if (dbNameToAddr(fullname, &dbaddr) != OK) return false;
|
||||
}
|
||||
}
|
||||
address.append(&dbaddr, sizeof(dbaddr));
|
||||
return true;
|
||||
@ -968,6 +949,26 @@ formatValue(const StreamFormat& format, const void* fieldaddress)
|
||||
long nelem = pdbaddr->no_elements;
|
||||
size_t size = nelem * typeSize[format.type];
|
||||
char* buffer = fieldBuffer.clear().reserve(size);
|
||||
|
||||
if (strcmp(((dbFldDes*)pdbaddr->pfldDes)->name, "TIME") == 0)
|
||||
{
|
||||
double time;
|
||||
|
||||
if (format.type != double_format)
|
||||
{
|
||||
error ("%s: can only read double values from TIME field\n", name());
|
||||
return false;
|
||||
}
|
||||
if (pdbaddr->precord == record)
|
||||
{
|
||||
/* if getting time from own record, update timestamp first */
|
||||
recGblGetTimeStamp(record);
|
||||
}
|
||||
time = pdbaddr->precord->time.secPastEpoch + 631152000u + pdbaddr->precord->time.nsec * 1e-9;
|
||||
debug("Stream::formatValue(%s): read %f from TIME field\n", name(), time);
|
||||
return printValue(format, time);
|
||||
}
|
||||
|
||||
if (dbGet(pdbaddr, dbfMapping[format.type], buffer,
|
||||
NULL, &nelem, NULL) != 0)
|
||||
{
|
||||
@ -1034,7 +1035,6 @@ bool Stream::
|
||||
matchValue(const StreamFormat& format, const void* fieldaddress)
|
||||
{
|
||||
// this function must increase consumedInput
|
||||
// [I use goto and feel very ashamed for it.]
|
||||
long consumed;
|
||||
long lval;
|
||||
double dval;
|
||||
@ -1058,29 +1058,25 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
|
||||
case long_format:
|
||||
{
|
||||
consumed = scanValue(format, lval);
|
||||
if (consumed < 0) goto noMoreElements;
|
||||
((epicsInt32*)buffer)[nord] = lval;
|
||||
if (consumed >= 0) ((epicsInt32*)buffer)[nord] = lval;
|
||||
break;
|
||||
}
|
||||
case enum_format:
|
||||
{
|
||||
consumed = scanValue(format, lval);
|
||||
if (consumed < 0) goto noMoreElements;
|
||||
((epicsUInt16*)buffer)[nord] = (epicsUInt16)lval;
|
||||
if (consumed >= 0) ((epicsUInt16*)buffer)[nord] = (epicsUInt16)lval;
|
||||
break;
|
||||
}
|
||||
case double_format:
|
||||
{
|
||||
consumed = scanValue(format, dval);
|
||||
if (consumed < 0) goto noMoreElements;
|
||||
((epicsFloat64*)buffer)[nord] = dval;
|
||||
if (consumed >= 0) ((epicsFloat64*)buffer)[nord] = dval;
|
||||
break;
|
||||
}
|
||||
case string_format:
|
||||
{
|
||||
consumed = scanValue(format,
|
||||
buffer+MAX_STRING_SIZE*nord, MAX_STRING_SIZE);
|
||||
if (consumed < 0) goto noMoreElements;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -1088,15 +1084,15 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
|
||||
"Illegal format type\n", name());
|
||||
return false;
|
||||
}
|
||||
if (consumed < 0) break;
|
||||
consumedInput += consumed;
|
||||
}
|
||||
noMoreElements:
|
||||
if (!nord)
|
||||
{
|
||||
// scan error: set other record to alarm status
|
||||
if (pdbaddr->precord != record)
|
||||
{
|
||||
recGblSetSevr(pdbaddr->precord, CALC_ALARM, INVALID_ALARM);
|
||||
(void) recGblSetSevr(pdbaddr->precord, CALC_ALARM, INVALID_ALARM);
|
||||
if (!INIT_RUN)
|
||||
{
|
||||
// process other record to send alarm monitor
|
||||
@ -1105,6 +1101,28 @@ noMoreElements:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (strcmp(((dbFldDes*)pdbaddr->pfldDes)->name, "TIME") == 0)
|
||||
{
|
||||
#ifdef epicsTimeEventDeviceTime
|
||||
if (format.type != double_format)
|
||||
{
|
||||
error ("%s: can only write double values to TIME field\n", name());
|
||||
return false;
|
||||
}
|
||||
dval = dval-631152000u;
|
||||
pdbaddr->precord->time.secPastEpoch = (long)dval;
|
||||
/* rouding: we don't have 9 digits precision in a double of today's number of seconds */
|
||||
pdbaddr->precord->time.nsec = (long)((dval-(long)dval)*1e6)*1000;
|
||||
debug("Stream::matchValue(%s): writing %i.%i to TIME field\n", name(),
|
||||
pdbaddr->precord->time.secPastEpoch, pdbaddr->precord->time.nsec);
|
||||
pdbaddr->precord->tse = epicsTimeEventDeviceTime;
|
||||
return true;
|
||||
#else
|
||||
error ("%s: writing TIME field is not supported in this EPICS version\n", name());
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (pdbaddr->precord == record || INIT_RUN)
|
||||
{
|
||||
// write into own record, thus don't process it
|
||||
|
@ -58,11 +58,19 @@ void StreamError(const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
StreamVError(fmt, args);
|
||||
StreamVError(0, NULL, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void StreamVError(const char* fmt, va_list args)
|
||||
void StreamError(int line, const char* file, const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
StreamVError(line, file, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void StreamVError(int line, const char* file, const char* fmt, va_list args)
|
||||
{
|
||||
char timestamp[40];
|
||||
StreamPrintTimestampFunction(timestamp, 40);
|
||||
@ -79,6 +87,10 @@ void StreamVError(const char* fmt, va_list args)
|
||||
#endif
|
||||
fprintf(stderr, "\033[31;1m");
|
||||
fprintf(stderr, "%s ", timestamp);
|
||||
if (file)
|
||||
{
|
||||
fprintf(stderr, "%s line %d: ", file, line);
|
||||
}
|
||||
vfprintf(stderr, fmt, args);
|
||||
fprintf(stderr, "\033[0m");
|
||||
}
|
||||
|
@ -30,11 +30,19 @@
|
||||
extern int streamDebug;
|
||||
extern void (*StreamPrintTimestampFunction)(char* buffer, int size);
|
||||
|
||||
void StreamError(int line, const char* file, const char* fmt, ...)
|
||||
__attribute__ ((format(printf,3,4)));
|
||||
|
||||
void StreamVError(int line, const char* file, const char* fmt, va_list args)
|
||||
__attribute__ ((format(printf,3,0)));
|
||||
|
||||
void StreamError(const char* fmt, ...)
|
||||
__attribute__ ((format(printf,1,2)));
|
||||
|
||||
void StreamVError(const char* fmt, va_list args)
|
||||
__attribute__ ((format(printf,1,0)));
|
||||
inline void StreamVError(const char* fmt, va_list args)
|
||||
{
|
||||
StreamVError(0, NULL, fmt, args);
|
||||
}
|
||||
|
||||
class StreamDebugClass
|
||||
{
|
||||
|
@ -29,7 +29,8 @@ typedef enum {
|
||||
alt_flag = 0x08,
|
||||
zero_flag = 0x10,
|
||||
skip_flag = 0x20,
|
||||
default_flag = 0x40
|
||||
default_flag = 0x40,
|
||||
compare_flag = 0x80
|
||||
} StreamFormatFlag;
|
||||
|
||||
typedef enum {
|
||||
|
@ -19,8 +19,9 @@
|
||||
* *
|
||||
***************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include "StreamFormatConverter.h"
|
||||
#include "StreamFormat.h"
|
||||
#include "StreamError.h"
|
||||
|
||||
StreamFormatConverter* StreamFormatConverter::
|
||||
@ -31,6 +32,125 @@ StreamFormatConverter::
|
||||
{
|
||||
}
|
||||
|
||||
int StreamFormatConverter::
|
||||
parseFormat(const char*& source, FormatType formatType, StreamFormat& streamFormat, StreamBuffer& infoString)
|
||||
{
|
||||
/*
|
||||
source := [flags] [width] ['.' prec] conv [extra]
|
||||
flags := '-' | '+' | ' ' | '#' | '0' | '*' | '?' | '='
|
||||
width := integer
|
||||
prec := integer
|
||||
conv := character
|
||||
extra := string
|
||||
*/
|
||||
|
||||
// look for flags
|
||||
streamFormat.flags = 0;
|
||||
bool loop = true;
|
||||
while (loop)
|
||||
{
|
||||
switch (*++source)
|
||||
{
|
||||
case '-':
|
||||
streamFormat.flags |= left_flag;
|
||||
break;
|
||||
case '+':
|
||||
streamFormat.flags |= sign_flag;
|
||||
break;
|
||||
case ' ':
|
||||
streamFormat.flags |= space_flag;
|
||||
break;
|
||||
case '#':
|
||||
streamFormat.flags |= alt_flag;
|
||||
break;
|
||||
case '0':
|
||||
streamFormat.flags |= zero_flag;
|
||||
break;
|
||||
case '*':
|
||||
if (formatType != ScanFormat)
|
||||
{
|
||||
error("Use of skip modifier '*' "
|
||||
"only allowed in input formats\n");
|
||||
return false;
|
||||
}
|
||||
streamFormat.flags |= skip_flag;
|
||||
break;
|
||||
case '?':
|
||||
if (formatType != ScanFormat)
|
||||
{
|
||||
error("Use of default modifier '?' "
|
||||
"only allowed in input formats\n");
|
||||
return false;
|
||||
}
|
||||
streamFormat.flags |= default_flag;
|
||||
break;
|
||||
case '=':
|
||||
if (formatType != ScanFormat)
|
||||
{
|
||||
error("Use of compare modifier '=' "
|
||||
"only allowed in input formats\n");
|
||||
return false;
|
||||
}
|
||||
streamFormat.flags |= compare_flag;
|
||||
formatType = PrintFormat;
|
||||
break;
|
||||
default:
|
||||
loop = false;
|
||||
}
|
||||
}
|
||||
// look for width
|
||||
unsigned long val;
|
||||
char* p;
|
||||
val = strtoul (source, &p, 10);
|
||||
source = p;
|
||||
if (val > 0xFFFF)
|
||||
{
|
||||
error("Field width %ld out of range\n", val);
|
||||
return false;
|
||||
}
|
||||
streamFormat.width = (unsigned short)val;
|
||||
// look for prec
|
||||
streamFormat.prec = -1;
|
||||
if (*source == '.')
|
||||
{
|
||||
source++;
|
||||
val = strtoul(source, &p, 10);
|
||||
if (p == source)
|
||||
{
|
||||
debug("source = %s\n", source);
|
||||
error("Numeric precision field expected after '.'\n");
|
||||
return false;
|
||||
}
|
||||
source = p;
|
||||
if (val > 0x7FFF)
|
||||
{
|
||||
error("Precision %ld out of range\n", val);
|
||||
return false;
|
||||
}
|
||||
streamFormat.prec = (short)val;
|
||||
}
|
||||
// look for converter
|
||||
streamFormat.conv = *source++;
|
||||
if (!streamFormat.conv || strchr("'\" (.0+-*?=", streamFormat.conv))
|
||||
{
|
||||
error("Missing converter character\n");
|
||||
return false;
|
||||
}
|
||||
debug("StreamFormatConverter::parseFormat: converter='%c'\n",
|
||||
streamFormat.conv);
|
||||
StreamFormatConverter* converter;
|
||||
converter = StreamFormatConverter::find(streamFormat.conv);
|
||||
if (!converter)
|
||||
{
|
||||
error("No converter registered for format '%%%c'\n",
|
||||
streamFormat.conv);
|
||||
return false;
|
||||
}
|
||||
// parse format and get info string
|
||||
return converter->parse(streamFormat, infoString,
|
||||
source, formatType == ScanFormat);
|
||||
}
|
||||
|
||||
void StreamFormatConverter::
|
||||
provides(const char* name, const char* provided)
|
||||
{
|
||||
@ -112,11 +232,57 @@ static void copyFormatString(StreamBuffer& info, const char* source)
|
||||
const char* p = source - 1;
|
||||
while (*p != '%' && *p != ')') p--;
|
||||
info.append('%');
|
||||
while (++p != source-1) if (*p != '?') info.append(*p);
|
||||
while (++p != source-1) if (*p != '?' && *p != '=') info.append(*p);
|
||||
}
|
||||
|
||||
// A word on sscanf
|
||||
// GNU's sscanf implementation sucks. It calls strlen on the buffer.
|
||||
// That leads to a time consumption proportional to the buffer size.
|
||||
// When reading huge arrays element-wise by repeatedly calling sscanf,
|
||||
// the performance drops to O(n^2).
|
||||
// The vxWorks implementation sucks, too. When all parsed values are skipped
|
||||
// with %*, it returns -1 instead of 0 even though it was successful.
|
||||
|
||||
// Standard Long Converter for 'diouxX'
|
||||
|
||||
static int prepareval(const StreamFormat& fmt, const char*& input, bool& neg)
|
||||
{
|
||||
int length = 0;
|
||||
neg = false;
|
||||
while (isspace(*input)) { input++; length++; }
|
||||
if (fmt.width)
|
||||
{
|
||||
// take local copy because strto* don't have width parameter
|
||||
int width = fmt.width;
|
||||
if (fmt.flags & space_flag)
|
||||
{
|
||||
// normally whitespace does not count to width
|
||||
// but do so if space flag is present
|
||||
width -= length;
|
||||
}
|
||||
strncpy((char*)fmt.info, input, width);
|
||||
((char*)fmt.info)[width] = 0;
|
||||
input = fmt.info;
|
||||
}
|
||||
if (*input == '+')
|
||||
{
|
||||
goto skipsign;
|
||||
}
|
||||
if (*input == '-')
|
||||
{
|
||||
neg = true;
|
||||
skipsign:
|
||||
input++;
|
||||
length++;
|
||||
}
|
||||
if (isspace(*input))
|
||||
{
|
||||
// allow space after sign only if # flag is set
|
||||
if (!(fmt.flags & alt_flag)) return -1;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
class StdLongConverter : public StreamFormatConverter
|
||||
{
|
||||
int parse(const StreamFormat& fmt, StreamBuffer& output, const char*& value, bool scanFormat);
|
||||
@ -128,22 +294,22 @@ int StdLongConverter::
|
||||
parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
const char*& source, bool scanFormat)
|
||||
{
|
||||
if (scanFormat && (fmt.flags & alt_flag))
|
||||
{
|
||||
error("Use of modifier '#' not allowed with %%%c input conversion\n",
|
||||
fmt.conv);
|
||||
return false;
|
||||
}
|
||||
if (scanFormat && fmt.prec >= 0)
|
||||
{
|
||||
error("Use of precision field '.%d' not allowed with %%%c input conversion\n",
|
||||
fmt.prec, fmt.conv);
|
||||
return false;
|
||||
}
|
||||
copyFormatString(info, source);
|
||||
info.append('l');
|
||||
info.append(fmt.conv);
|
||||
if (scanFormat) info.append("%n");
|
||||
if (scanFormat)
|
||||
{
|
||||
if (fmt.width) info.reserve(fmt.width+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
copyFormatString(info, source);
|
||||
info.append('l');
|
||||
info.append(fmt.conv);
|
||||
}
|
||||
return long_format;
|
||||
}
|
||||
|
||||
@ -157,17 +323,39 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
||||
int StdLongConverter::
|
||||
scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||
{
|
||||
int length = -1;
|
||||
if (fmt.flags & skip_flag)
|
||||
char* end;
|
||||
int length;
|
||||
bool neg;
|
||||
int base;
|
||||
|
||||
length = prepareval(fmt, input, neg);
|
||||
if (length < 0) return -1;
|
||||
switch (fmt.conv)
|
||||
{
|
||||
/* can't use return value on vxWorks: sscanf with %* format
|
||||
returns -1 at end of string whether value is found or not */
|
||||
sscanf(input, fmt.info, &length);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sscanf(input, fmt.info, &value, &length) < 1) return -1;
|
||||
case 'd':
|
||||
base = 10;
|
||||
break;
|
||||
case 'o':
|
||||
base = 8;
|
||||
goto signcheck;
|
||||
case 'x':
|
||||
case 'X':
|
||||
base = 16;
|
||||
signcheck:
|
||||
// allow negative hex and oct numbers with - flag
|
||||
if (neg && !(fmt.flags & left_flag)) return -1;
|
||||
break;
|
||||
case 'u':
|
||||
if (neg) return -1;
|
||||
base = 10;
|
||||
break;
|
||||
default:
|
||||
base = 0;
|
||||
}
|
||||
value = strtoul(input, &end, base);
|
||||
if (neg) value = -value;
|
||||
if (end == input) return -1;
|
||||
length += end-input;
|
||||
return length;
|
||||
}
|
||||
|
||||
@ -186,22 +374,21 @@ int StdDoubleConverter::
|
||||
parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
const char*& source, bool scanFormat)
|
||||
{
|
||||
if (scanFormat && (fmt.flags & alt_flag))
|
||||
{
|
||||
error("Use of modifier '#' not allowed with %%%c input conversion\n",
|
||||
fmt.conv);
|
||||
return false;
|
||||
}
|
||||
if (scanFormat && fmt.prec >= 0)
|
||||
{
|
||||
error("Use of precision field '.%d' not allowed with %%%c input conversion\n",
|
||||
fmt.prec, fmt.conv);
|
||||
return false;
|
||||
}
|
||||
copyFormatString(info, source);
|
||||
if (scanFormat) info.append('l');
|
||||
info.append(fmt.conv);
|
||||
if (scanFormat) info.append("%n");
|
||||
if (scanFormat)
|
||||
{
|
||||
if (fmt.width) info.reserve(fmt.width+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
copyFormatString(info, source);
|
||||
info.append(fmt.conv);
|
||||
}
|
||||
return double_format;
|
||||
}
|
||||
|
||||
@ -215,17 +402,16 @@ printDouble(const StreamFormat& fmt, StreamBuffer& output, double value)
|
||||
int StdDoubleConverter::
|
||||
scanDouble(const StreamFormat& fmt, const char* input, double& value)
|
||||
{
|
||||
int length = -1;
|
||||
if (fmt.flags & skip_flag)
|
||||
{
|
||||
/* can't use return value on vxWorks: sscanf with %* format
|
||||
returns -1 at end of string whether value is found or not */
|
||||
sscanf(input, fmt.info, &length);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sscanf(input, fmt.info, &value, &length) < 1) return -1;
|
||||
}
|
||||
char* end;
|
||||
int length;
|
||||
bool neg;
|
||||
|
||||
length = prepareval(fmt, input, neg);
|
||||
if (length < 0) return -1;
|
||||
value = strtod(input, &end);
|
||||
if (neg) value = -value;
|
||||
if (end == input) return -1;
|
||||
length += end-input;
|
||||
return length;
|
||||
}
|
||||
|
||||
@ -244,11 +430,10 @@ int StdStringConverter::
|
||||
parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
const char*& source, bool scanFormat)
|
||||
{
|
||||
if (fmt.flags & (sign_flag|space_flag|zero_flag|alt_flag))
|
||||
if (fmt.flags & (sign_flag|zero_flag))
|
||||
{
|
||||
error("Use of modifiers '+', ' ', '0', '#' "
|
||||
"not allowed with %%%c conversion\n",
|
||||
fmt.conv);
|
||||
error("Use of modifiers '+', '0'"
|
||||
"not allowed with %%s conversion\n");
|
||||
return false;
|
||||
}
|
||||
if (scanFormat && fmt.prec >= 0)
|
||||
@ -274,40 +459,52 @@ int StdStringConverter::
|
||||
scanString(const StreamFormat& fmt, const char* input,
|
||||
char* value, size_t maxlen)
|
||||
{
|
||||
int length = -1;
|
||||
if (*input == '\0')
|
||||
int length = 0;
|
||||
|
||||
int width = fmt.width;
|
||||
|
||||
if ((fmt.flags & skip_flag) || value == NULL) maxlen = 0;
|
||||
|
||||
// if user does not specify width assume "ininity" (-1)
|
||||
if (width == 0)
|
||||
{
|
||||
// match empty string
|
||||
if (value) value[0] = '\0';
|
||||
return 0;
|
||||
if (fmt.conv == 'c') width = 1;
|
||||
else width = -1;
|
||||
}
|
||||
if (fmt.flags & skip_flag)
|
||||
|
||||
while (isspace(*input) && width)
|
||||
{
|
||||
/* can't use return value on vxWorks: sscanf with %* format
|
||||
returns -1 at end of string whether value is found or not */
|
||||
sscanf(input, fmt.info, &length);
|
||||
// normally leading whitespace does not count to width
|
||||
// but do so if space flag is present
|
||||
if (fmt.flags & space_flag)
|
||||
{
|
||||
if (maxlen > 1)
|
||||
{
|
||||
*value++ = *input;
|
||||
maxlen--;
|
||||
}
|
||||
width--;
|
||||
}
|
||||
length++;
|
||||
input++;
|
||||
}
|
||||
else
|
||||
while (*input && width)
|
||||
{
|
||||
char tmpformat[10];
|
||||
const char* f;
|
||||
if (maxlen <= fmt.width || fmt.width == 0)
|
||||
// normally whitespace ends string
|
||||
// but don't end if # flag is present
|
||||
if (!(fmt.flags & alt_flag) && isspace(*input)) break;
|
||||
if (maxlen > 1)
|
||||
{
|
||||
// assure not to read too much
|
||||
sprintf(tmpformat, "%%%ld%c%%n", (long)maxlen-1, fmt.conv);
|
||||
f = tmpformat;
|
||||
*value++ = *input;
|
||||
maxlen--;
|
||||
}
|
||||
else
|
||||
{
|
||||
f = fmt.info;
|
||||
}
|
||||
if (sscanf(input, f, value, &length) < 1) return -1;
|
||||
if (length < 0) return -1;
|
||||
value[length] = '\0';
|
||||
#ifndef NO_TEMPORARY
|
||||
debug("StdStringConverter::scanString: length=%d, value=%s\n",
|
||||
length, StreamBuffer(value,length).expand()());
|
||||
#endif
|
||||
length++;
|
||||
width--;
|
||||
input++;
|
||||
}
|
||||
if (maxlen > 0)
|
||||
{
|
||||
*value = '\0';
|
||||
}
|
||||
return length;
|
||||
}
|
||||
@ -316,11 +513,11 @@ RegisterConverter (StdStringConverter, "s");
|
||||
|
||||
// Standard Characters Converter for 'c'
|
||||
|
||||
class StdCharsConverter : public StdStringConverter
|
||||
class StdCharsConverter : public StreamFormatConverter
|
||||
{
|
||||
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||
virtual bool printLong(const StreamFormat&, StreamBuffer&, long);
|
||||
// scanString is inherited from %s format
|
||||
virtual int scanString(const StreamFormat&, const char*, char*, size_t);
|
||||
};
|
||||
|
||||
int StdCharsConverter::
|
||||
@ -330,8 +527,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
if (fmt.flags & (sign_flag|space_flag|zero_flag|alt_flag))
|
||||
{
|
||||
error("Use of modifiers '+', ' ', '0', '#' "
|
||||
"not allowed with %%%c conversion\n",
|
||||
fmt.conv);
|
||||
"not allowed with %%c conversion\n");
|
||||
return false;
|
||||
}
|
||||
if (scanFormat && fmt.prec >= 0)
|
||||
@ -357,6 +553,37 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
||||
return true;
|
||||
}
|
||||
|
||||
int StdCharsConverter::
|
||||
scanString(const StreamFormat& fmt, const char* input,
|
||||
char* value, size_t maxlen)
|
||||
{
|
||||
int length = 0;
|
||||
|
||||
int width = fmt.width;
|
||||
|
||||
if ((fmt.flags & skip_flag) || value == NULL) maxlen = 0;
|
||||
|
||||
// if user does not specify width assume 1
|
||||
if (width == 0) width = 1;
|
||||
|
||||
while (*input && width)
|
||||
{
|
||||
if (maxlen > 1)
|
||||
{
|
||||
*value++ = *input;
|
||||
maxlen--;
|
||||
}
|
||||
length++;
|
||||
width--;
|
||||
input++;
|
||||
}
|
||||
if (maxlen > 0)
|
||||
{
|
||||
*value = '\0';
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
RegisterConverter (StdCharsConverter, "c");
|
||||
|
||||
// Standard Charset Converter for '['
|
||||
@ -368,6 +595,17 @@ class StdCharsetConverter : public StreamFormatConverter
|
||||
// no print method, %[ is readonly
|
||||
};
|
||||
|
||||
inline void markbit(StreamBuffer& info, bool notflag, char c)
|
||||
{
|
||||
char &infobyte = info[c>>3];
|
||||
char mask = 1<<(c&7);
|
||||
|
||||
if (notflag)
|
||||
infobyte |= mask;
|
||||
else
|
||||
infobyte &= ~mask;
|
||||
}
|
||||
|
||||
int StdCharsetConverter::
|
||||
parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
const char*& source, bool scanFormat)
|
||||
@ -380,8 +618,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
if (fmt.flags & (left_flag|sign_flag|space_flag|zero_flag|alt_flag))
|
||||
{
|
||||
error("Use of modifiers '-', '+', ' ', '0', '#'"
|
||||
"not allowed with %%%c conversion\n",
|
||||
fmt.conv);
|
||||
"not allowed with %%[ conversion\n");
|
||||
return false;
|
||||
}
|
||||
if (scanFormat && fmt.prec >= 0)
|
||||
@ -390,18 +627,46 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
fmt.prec, fmt.conv);
|
||||
return false;
|
||||
}
|
||||
info.printf("%%%s%d[", fmt.flags & skip_flag ? "*" : "", fmt.width);
|
||||
while (*source && *source != ']')
|
||||
|
||||
bool notflag = false;
|
||||
char c = 0;
|
||||
|
||||
info.clear().reserve(32);
|
||||
if (*source == '^')
|
||||
{
|
||||
if (*source == esc) source++;
|
||||
info.append(*source++);
|
||||
notflag = true;
|
||||
source++;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(info(1), 255, 32);
|
||||
}
|
||||
if (*source == ']')
|
||||
{
|
||||
markbit(info, notflag, *source++);
|
||||
}
|
||||
for (; *source && *source != ']'; source++)
|
||||
{
|
||||
if (*source == esc)
|
||||
{
|
||||
markbit(info, notflag, *++source);
|
||||
continue;
|
||||
}
|
||||
if (*source == '-' && c && source[1] && source[1] != ']')
|
||||
{
|
||||
source++;
|
||||
while (c < *source) markbit(info, notflag, c++);
|
||||
while (c > *source) markbit(info, notflag, c--);
|
||||
}
|
||||
c = *source;
|
||||
markbit(info, notflag, c);
|
||||
}
|
||||
if (!*source) {
|
||||
error("Missing ']' after %%[ format conversion\n");
|
||||
return false;
|
||||
}
|
||||
source++; // consume ']'
|
||||
info.append("]%n");
|
||||
|
||||
return string_format;
|
||||
}
|
||||
|
||||
@ -409,33 +674,29 @@ int StdCharsetConverter::
|
||||
scanString(const StreamFormat& fmt, const char* input,
|
||||
char* value, size_t maxlen)
|
||||
{
|
||||
int length = -1;
|
||||
if (fmt.flags & skip_flag)
|
||||
int length = 0;
|
||||
int width = fmt.width;
|
||||
|
||||
if ((fmt.flags & skip_flag) || value == NULL) maxlen = 0;
|
||||
|
||||
// if user does not specify width assume "ininity" (-1)
|
||||
if (width == 0) width = -1;
|
||||
|
||||
while (*input && width)
|
||||
{
|
||||
/* can't use return value on vxWorks: sscanf with %* format
|
||||
returns -1 at end of string whether value is found or not */
|
||||
sscanf(input, fmt.info, &length);
|
||||
if (fmt.info[*input>>3] & 1<<(*input&7)) break;
|
||||
if (maxlen > 1)
|
||||
{
|
||||
*value++ = *input;
|
||||
maxlen--;
|
||||
}
|
||||
length++;
|
||||
width--;
|
||||
input++;
|
||||
}
|
||||
else
|
||||
if (maxlen > 0)
|
||||
{
|
||||
char tmpformat[256];
|
||||
const char* f;
|
||||
if (maxlen <= fmt.width || fmt.width == 0)
|
||||
{
|
||||
const char *p = strchr (fmt.info, '[');
|
||||
// assure not to read too much
|
||||
sprintf(tmpformat, "%%%ld%s", (long)maxlen-1, p);
|
||||
f = tmpformat;
|
||||
}
|
||||
else
|
||||
{
|
||||
f = fmt.info;
|
||||
}
|
||||
if (sscanf(input, f, value, &length) < 1) return -1;
|
||||
if (length < 0) return -1;
|
||||
value[length] = '\0';
|
||||
debug("StdCharsetConverter::scanString: length=%d, value=%s\n",
|
||||
length, value);
|
||||
*value = '\0';
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "StreamFormat.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "StreamProtocol.h"
|
||||
|
||||
#define esc (0x1b)
|
||||
|
||||
@ -41,6 +42,7 @@ class StreamFormatConverter
|
||||
const char* _name;
|
||||
public:
|
||||
virtual ~StreamFormatConverter();
|
||||
static int parseFormat(const char*& source, FormatType, StreamFormat&, StreamBuffer& infoString);
|
||||
const char* name() { return _name; }
|
||||
void provides(const char* name, const char* provided);
|
||||
static StreamFormatConverter* find(unsigned char c);
|
||||
|
@ -81,18 +81,6 @@ StreamProtocolParser::
|
||||
delete next;
|
||||
}
|
||||
|
||||
void StreamProtocolParser::
|
||||
errorMsg(const char* fmt, ...)
|
||||
{
|
||||
char fmt2[200];
|
||||
sprintf (fmt2, "'%s' line %d: %s",
|
||||
filename(), line, fmt);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
StreamVError(fmt2, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void StreamProtocolParser::
|
||||
report()
|
||||
{
|
||||
@ -118,7 +106,7 @@ getProtocol(const char* filename, const StreamBuffer& protocolAndParams)
|
||||
// Have we already seen this file?
|
||||
for (parser = parsers; parser; parser = parser->next)
|
||||
{
|
||||
if (parser->filename.equals(filename))
|
||||
if (parser->filename.startswith(filename))
|
||||
{
|
||||
if (!parser->valid)
|
||||
{
|
||||
@ -234,12 +222,12 @@ getProtocol(const StreamBuffer& protocolAndParams)
|
||||
Protocol* protocol;
|
||||
for (protocol = protocols; protocol; protocol = protocol->next)
|
||||
{
|
||||
if (protocol->protocolname.equals(name()))
|
||||
if (protocol->protocolname.startswith(name()))
|
||||
// constructor also replaces parameters
|
||||
return new Protocol(*protocol, name, 0);
|
||||
}
|
||||
error("Protocol '%s' not found in protocol file '%s'\n",
|
||||
name(), filename());
|
||||
protocolAndParams(), filename());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -292,18 +280,18 @@ parseProtocol(Protocol& protocol, StreamBuffer* commands)
|
||||
// end of protocol or handler definition
|
||||
return true;
|
||||
}
|
||||
errorMsg("Stray '}' in global context\n");
|
||||
error(line, filename(), "Stray '}' in global context\n");
|
||||
return false;
|
||||
}
|
||||
if (strchr("{=", token[0]))
|
||||
{
|
||||
errorMsg("Expect name before '%c'\n", token[0]);
|
||||
error(line, filename(), "Expect name before '%c'\n", token[0]);
|
||||
return false;
|
||||
}
|
||||
do op = readChar(); while (op == ' '); // what comes after token?
|
||||
if (op == EOF)
|
||||
{
|
||||
errorMsg("Unexpected end of file after: %s\n", token());
|
||||
error(line, filename(), "Unexpected end of file after: %s\n", token());
|
||||
return false;
|
||||
}
|
||||
if (op == '=')
|
||||
@ -311,20 +299,20 @@ parseProtocol(Protocol& protocol, StreamBuffer* commands)
|
||||
// variable assignment
|
||||
if (isHandlerContext(protocol, commands))
|
||||
{
|
||||
errorMsg("Variables are not allowed in handlers: %s\n",
|
||||
error(line, filename(), "Variables are not allowed in handlers: %s\n",
|
||||
token());
|
||||
return false;
|
||||
}
|
||||
if (token[0] == '@' || (token[0] >= '0' && token[0] <= '9'))
|
||||
{
|
||||
errorMsg("Variable name cannot start with '%c': %s\n",
|
||||
error(line, filename(), "Variable name cannot start with '%c': %s\n",
|
||||
token[0], token());
|
||||
return false;
|
||||
}
|
||||
if (!parseAssignment(token(), protocol))
|
||||
{
|
||||
line = startline;
|
||||
errorMsg("in variable assignment '%s = ...'\n", token());
|
||||
error(line, filename(), "in variable assignment '%s = ...'\n", token());
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
@ -336,7 +324,7 @@ parseProtocol(Protocol& protocol, StreamBuffer* commands)
|
||||
{
|
||||
if (isHandlerContext(protocol, commands))
|
||||
{
|
||||
errorMsg("Handlers are not allowed in handlers: %s\n",
|
||||
error(line, filename(), "Handlers are not allowed in handlers: %s\n",
|
||||
token());
|
||||
return false;
|
||||
}
|
||||
@ -345,7 +333,7 @@ parseProtocol(Protocol& protocol, StreamBuffer* commands)
|
||||
if (!parseProtocol(protocol, handler))
|
||||
{
|
||||
line = startline;
|
||||
errorMsg("in handler '%s'\n", token());
|
||||
error(line, filename(), "in handler '%s'\n", token());
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
@ -353,16 +341,16 @@ parseProtocol(Protocol& protocol, StreamBuffer* commands)
|
||||
// protocol definition
|
||||
if (!isGlobalContext(commands))
|
||||
{
|
||||
errorMsg("Definition of '%s' not in global context (missing '}' ?)\n",
|
||||
error(line, filename(), "Definition of '%s' not in global context (missing '}' ?)\n",
|
||||
token());
|
||||
return false;
|
||||
}
|
||||
Protocol** ppP;
|
||||
for (ppP = &protocols; *ppP; ppP = &(*ppP)->next)
|
||||
{
|
||||
if ((*ppP)->protocolname.equals(token()))
|
||||
if ((*ppP)->protocolname.startswith(token()))
|
||||
{
|
||||
errorMsg("Protocol '%s' redefined\n", token());
|
||||
error(line, filename(), "Protocol '%s' redefined\n", token());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -370,7 +358,7 @@ parseProtocol(Protocol& protocol, StreamBuffer* commands)
|
||||
if (!parseProtocol(*pP, pP->commands))
|
||||
{
|
||||
line = startline;
|
||||
errorMsg("in protocol '%s'\n", token());
|
||||
error(line, filename(), "in protocol '%s'\n", token());
|
||||
delete pP;
|
||||
return false;
|
||||
}
|
||||
@ -381,7 +369,7 @@ parseProtocol(Protocol& protocol, StreamBuffer* commands)
|
||||
// Must be a command or a protocol reference.
|
||||
if (isGlobalContext(commands))
|
||||
{
|
||||
errorMsg("Expect '=' or '{' instead of '%c' after '%s'\n",
|
||||
error(line, filename(), "Expect '=' or '{' instead of '%c' after '%s'\n",
|
||||
op, token());
|
||||
return false;
|
||||
}
|
||||
@ -392,7 +380,7 @@ parseProtocol(Protocol& protocol, StreamBuffer* commands)
|
||||
Protocol* p;
|
||||
for (p = protocols; p; p = p->next)
|
||||
{
|
||||
if (p->protocolname.equals(token()))
|
||||
if (p->protocolname.startswith(token()))
|
||||
{
|
||||
commands->append(*p->commands);
|
||||
break;
|
||||
@ -406,7 +394,7 @@ parseProtocol(Protocol& protocol, StreamBuffer* commands)
|
||||
if (parseValue(*commands, true) == false)
|
||||
{
|
||||
line = startline;
|
||||
errorMsg("after command '%s'\n", token());
|
||||
error(line, filename(), "after command '%s'\n", token());
|
||||
return false;
|
||||
}
|
||||
debug("parseProtocol: command '%s'\n", (*commands).expand()());
|
||||
@ -486,7 +474,7 @@ Each time newline is read, line is incremented.
|
||||
c = getc(file);
|
||||
if (c != '}')
|
||||
{
|
||||
errorMsg("Expect '}' instead of '%c' after: %s\n",
|
||||
error(line, filename(), "Expect '}' instead of '%c' after: %s\n",
|
||||
c, buffer(token));
|
||||
return false;
|
||||
}
|
||||
@ -495,12 +483,12 @@ Each time newline is read, line is incremented.
|
||||
}
|
||||
if (c == EOF)
|
||||
{
|
||||
errorMsg("Unexpected end of file after '$'\n");
|
||||
error(line, filename(), "Unexpected end of file after '$'\n");
|
||||
return false;
|
||||
}
|
||||
if (strchr (specialchars, c))
|
||||
{
|
||||
errorMsg("Unexpected '%c' after '$'\n,", c);
|
||||
error(line, filename(), "Unexpected '%c' after '$'\n,", c);
|
||||
return false;
|
||||
}
|
||||
// variable like $xyz handled as word token
|
||||
@ -519,7 +507,7 @@ Each time newline is read, line is incremented.
|
||||
{
|
||||
if (c == EOF || c == '\n')
|
||||
{
|
||||
errorMsg("Unterminated quoted string: %s\n",
|
||||
error(line, filename(), "Unterminated quoted string: %s\n",
|
||||
buffer(token));
|
||||
return false;
|
||||
}
|
||||
@ -532,7 +520,7 @@ Each time newline is read, line is incremented.
|
||||
break;
|
||||
}
|
||||
buffer.append(c);
|
||||
if (c == quote && buffer[-1] != '\\')
|
||||
if (c == quote && buffer[-2] != '\\')
|
||||
{
|
||||
quote = false;
|
||||
break;
|
||||
@ -547,7 +535,7 @@ Each time newline is read, line is incremented.
|
||||
// end of file
|
||||
if (!eofAllowed)
|
||||
{
|
||||
errorMsg("Unexpected end of file\n");
|
||||
error(line, filename(), "Unexpected end of file\n");
|
||||
return false;
|
||||
}
|
||||
buffer.append('\0');
|
||||
@ -620,7 +608,7 @@ parseValue(StreamBuffer& buffer, bool lazy)
|
||||
}
|
||||
if (c == '{' || c == '=')
|
||||
{
|
||||
errorMsg("Unexpected '%c' (missing ';' or '\"' ?)\n", c);
|
||||
error(line, filename(), "Unexpected '%c' (missing ';' or '\"' ?)\n", c);
|
||||
return false;
|
||||
}
|
||||
if (strchr (";}", c))
|
||||
@ -657,6 +645,9 @@ printString(StreamBuffer& buffer, const char* s)
|
||||
case skip:
|
||||
buffer.append("\\?");
|
||||
break;
|
||||
case whitespace:
|
||||
buffer.append("\\_");
|
||||
break;
|
||||
case '"':
|
||||
buffer.append("\\\"");
|
||||
break;
|
||||
@ -768,18 +759,6 @@ StreamProtocolParser::Protocol::
|
||||
delete next;
|
||||
}
|
||||
|
||||
void StreamProtocolParser::Protocol::
|
||||
errorMsg(int l, const char* fmt, ...)
|
||||
{
|
||||
char fmt2[200];
|
||||
sprintf (fmt2, "'%s' line %d: %s",
|
||||
filename(), line, fmt);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
StreamVError(fmt2, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void StreamProtocolParser::Protocol::
|
||||
report()
|
||||
{
|
||||
@ -811,7 +790,7 @@ createVariable(const char* name, int linenr)
|
||||
Variable** ppV;
|
||||
for (ppV = &variables; *ppV; ppV = &(*ppV)->next)
|
||||
{
|
||||
if ((*ppV)->name.equals(name))
|
||||
if ((*ppV)->name.startswith(name))
|
||||
{
|
||||
(*ppV)->line = linenr;
|
||||
return &(*ppV)->value;
|
||||
@ -829,7 +808,7 @@ getVariable(const char* name)
|
||||
|
||||
for (pV = variables; pV; pV = pV->next)
|
||||
{
|
||||
if (pV->name.equals(name))
|
||||
if (pV->name.startswith(name))
|
||||
{
|
||||
pV->used = true;
|
||||
return pV;
|
||||
@ -847,12 +826,12 @@ getNumberVariable(const char* varname, unsigned long& value, unsigned long max)
|
||||
if (!compileNumber(value, source, max))
|
||||
{
|
||||
int linenr = getLineNumber(source);
|
||||
errorMsg(linenr, "in variable %s\n", varname);
|
||||
error(linenr, filename(), "in variable %s\n", varname);
|
||||
return false;
|
||||
}
|
||||
if (source != pvar->value.end())
|
||||
{
|
||||
errorMsg(getLineNumber(source),
|
||||
error(getLineNumber(source), filename(),
|
||||
"Garbage in variable '%s' after numeric value %ld: %s\n",
|
||||
varname, value, source);
|
||||
return false;
|
||||
@ -867,7 +846,7 @@ getEnumVariable(const char* varname, unsigned short& value, const char** enumstr
|
||||
if (!pvar) return true;
|
||||
for (value = 0; enumstrings[value]; value++)
|
||||
{
|
||||
if (pvar->value.equals(enumstrings[value]))
|
||||
if (pvar->value.startswith(enumstrings[value]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -925,13 +904,14 @@ getCommands(const char* handlername,StreamBuffer& code, Client* client)
|
||||
{
|
||||
if (handlername)
|
||||
{
|
||||
errorMsg(pvar->line,
|
||||
error(pvar->line, filename(),
|
||||
"in handler '%s'\n", handlername);
|
||||
errorMsg(variables->line,
|
||||
error(variables->line, filename(),
|
||||
"used by protocol '%s'\n", protocolname());
|
||||
return false;
|
||||
}
|
||||
errorMsg(pvar->line, "in protocol '%s'\n", protocolname());
|
||||
error(pvar->line, filename(),
|
||||
"in protocol '%s'\n", protocolname());
|
||||
return false;
|
||||
}
|
||||
debug("commands %s: %s\n", handlername, pvar->value.expand()());
|
||||
@ -955,7 +935,7 @@ replaceVariable(StreamBuffer& buffer, const char* varname)
|
||||
const char* p = parameter[*varname-'0'];
|
||||
if (!p)
|
||||
{
|
||||
errorMsg(linenr,
|
||||
error(linenr, filename(),
|
||||
"Missing value for parameter $%c\n", *varname);
|
||||
return false;
|
||||
}
|
||||
@ -981,7 +961,7 @@ replaceVariable(StreamBuffer& buffer, const char* varname)
|
||||
const Variable* v = getVariable(varname);
|
||||
if (!v)
|
||||
{
|
||||
errorMsg(linenr,
|
||||
error(linenr, filename(),
|
||||
"Undefined variable '%s' referenced\n",
|
||||
varname);
|
||||
return false;
|
||||
@ -1045,7 +1025,7 @@ compileNumber(unsigned long& number, const char*& source, unsigned long max)
|
||||
{
|
||||
debug("StreamProtocolParser::Protocol::compileNumber: %s\n",
|
||||
buffer.expand()());
|
||||
errorMsg(getLineNumber(source),
|
||||
error(getLineNumber(source), filename(),
|
||||
"Unsigned numeric value expected: %s\n", buffer());
|
||||
return false;
|
||||
}
|
||||
@ -1053,7 +1033,7 @@ compileNumber(unsigned long& number, const char*& source, unsigned long max)
|
||||
{
|
||||
debug("StreamProtocolParser::Protocol::compileNumber: %s\n",
|
||||
buffer.expand()());
|
||||
errorMsg(getLineNumber(source),
|
||||
error(getLineNumber(source), filename(),
|
||||
"Garbage after numeric value: %s\n", buffer());
|
||||
return false;
|
||||
}
|
||||
@ -1061,7 +1041,7 @@ compileNumber(unsigned long& number, const char*& source, unsigned long max)
|
||||
{
|
||||
debug("StreamProtocolParser::Protocol::compileNumber: %s\n",
|
||||
buffer.expand()());
|
||||
errorMsg(getLineNumber(source),
|
||||
error(getLineNumber(source), filename(),
|
||||
"Value %s out of range [0...%ld]\n", buffer(), max);
|
||||
return false;
|
||||
}
|
||||
@ -1080,10 +1060,9 @@ compileString(StreamBuffer& buffer, const char*& source,
|
||||
{
|
||||
bool escaped = false;
|
||||
int n;
|
||||
long formatPos[20];
|
||||
int numFormats = 0;
|
||||
int newline = 0;
|
||||
StreamBuffer formatbuffer;
|
||||
int formatpos = buffer.length();
|
||||
line = getLineNumber(source);
|
||||
|
||||
debug("StreamProtocolParser::Protocol::compileString "
|
||||
@ -1094,41 +1073,58 @@ compileString(StreamBuffer& buffer, const char*& source,
|
||||
// 1) read a line from protocol source and code quoted strings,
|
||||
// numerical bytes, tokens, etc, and replace variables and parameters
|
||||
// 2) replace the formats in the line
|
||||
// thus variables can be replaces inside the format info string
|
||||
// thus variables can be replaced inside the format info string
|
||||
|
||||
while (1)
|
||||
{
|
||||
debug("StreamProtocolParser::Protocol::compileString "
|
||||
"buffer so far: %s\n", buffer.expand()());
|
||||
// this is step 2: replacing the formats
|
||||
if (!*source || (newline = getLineNumber(source)) != line)
|
||||
{
|
||||
// compile all formats in this line
|
||||
// We do this here after all variables in this line
|
||||
// have been replaced and after string has been coded.
|
||||
int offs = 0;
|
||||
for (n = 0; n < numFormats; n++)
|
||||
if (formatType != NoFormat)
|
||||
{
|
||||
int pos = formatPos[n] + offs;
|
||||
debug("StreamProtocolParser::Protocol::compileString "
|
||||
"format=\"%s\"\n", buffer.expand(pos)());
|
||||
formatbuffer.clear();
|
||||
const char* p = buffer(pos);
|
||||
if (!compileFormat(formatbuffer, p, formatType, client))
|
||||
int nformats=0;
|
||||
char c;
|
||||
while ((c = buffer[formatpos]) != '\0')
|
||||
{
|
||||
p = buffer(pos);
|
||||
formatbuffer.clear();
|
||||
printString(formatbuffer, p);
|
||||
errorMsg(line, "in format string: \"%s\"\n",
|
||||
formatbuffer());
|
||||
return false;
|
||||
if (c == esc) {
|
||||
// ignore escaped %
|
||||
formatpos+=2;
|
||||
continue;
|
||||
}
|
||||
if (c == '%') {
|
||||
debug("StreamProtocolParser::Protocol::compileString "
|
||||
"format=\"%s\"\n", buffer.expand(formatpos)());
|
||||
nformats++;
|
||||
formatbuffer.clear();
|
||||
const char* p = buffer(formatpos);
|
||||
if (!compileFormat(formatbuffer, p, formatType, client))
|
||||
{
|
||||
p = buffer(formatpos);
|
||||
formatbuffer.clear();
|
||||
printString(formatbuffer, p);
|
||||
error(line, filename(),
|
||||
"in format string: \"%s\"\n",
|
||||
formatbuffer());
|
||||
return false;
|
||||
}
|
||||
int formatlen = p - buffer(formatpos);
|
||||
buffer.replace(formatpos, formatlen, formatbuffer);
|
||||
debug("StreamProtocolParser::Protocol::compileString "
|
||||
"replaced by: \"%s\"\n", buffer.expand(formatpos)());
|
||||
formatpos += formatbuffer.length();
|
||||
continue;
|
||||
}
|
||||
formatpos ++;
|
||||
}
|
||||
int formatlen = p - buffer(pos);
|
||||
buffer.replace(pos, formatlen, formatbuffer);
|
||||
debug("StreamProtocolParser::Protocol::compileString "
|
||||
"replaced by: \"%s\"\n", buffer.expand(pos)());
|
||||
offs += formatbuffer.length() - formatlen;
|
||||
"%d formats found in line %d\n", nformats, line);
|
||||
}
|
||||
if (!*source) break;
|
||||
numFormats = 0;
|
||||
line = newline;
|
||||
}
|
||||
// this is step 1: coding the string
|
||||
@ -1144,19 +1140,15 @@ compileString(StreamBuffer& buffer, const char*& source,
|
||||
switch (*source)
|
||||
{
|
||||
case '$': // can't be: readToken would have made a token from this
|
||||
errorMsg(line,
|
||||
error(line, filename(),
|
||||
"INTERNAL ERROR: unconverted \\$ in quoted string\n");
|
||||
return false;
|
||||
case '?':
|
||||
if (formatType != ScanFormat)
|
||||
{
|
||||
errorMsg(line,
|
||||
"Quoted \\? only allowed in input: %s\n",
|
||||
source-1);
|
||||
return false;
|
||||
}
|
||||
buffer.append(skip);
|
||||
break;
|
||||
case '_':
|
||||
buffer.append(whitespace);
|
||||
break;
|
||||
case 'a':
|
||||
buffer.append(7);
|
||||
break;
|
||||
@ -1179,7 +1171,7 @@ compileString(StreamBuffer& buffer, const char*& source,
|
||||
sscanf (source, "%3o%n", &temp, &n);
|
||||
if (temp > 0xFF)
|
||||
{
|
||||
errorMsg(line,
|
||||
error(line, filename(),
|
||||
"Octal source %#o does not fit in byte: %s\n",
|
||||
temp, source-1);
|
||||
return false;
|
||||
@ -1195,7 +1187,7 @@ compileString(StreamBuffer& buffer, const char*& source,
|
||||
case 'x': // hex numbers (max 2 digits after 0)
|
||||
if (sscanf (source+1, "%2x%n", &temp, &n) < 1)
|
||||
{
|
||||
errorMsg(line,
|
||||
error(line, filename(),
|
||||
"Hex digit expected after \\x: %s\n",
|
||||
source-1);
|
||||
return false;
|
||||
@ -1220,7 +1212,7 @@ compileString(StreamBuffer& buffer, const char*& source,
|
||||
sscanf (source, "%3u%n", &temp, &n);
|
||||
if (temp > 0xFF)
|
||||
{
|
||||
errorMsg(line,
|
||||
error(line, filename(),
|
||||
"Decimal source %d does not fit in byte: %s\n",
|
||||
temp, source-1);
|
||||
return false;
|
||||
@ -1239,29 +1231,13 @@ compileString(StreamBuffer& buffer, const char*& source,
|
||||
source++;
|
||||
continue;
|
||||
}
|
||||
if (quoted) // look for ending quotes, escapes, and formats
|
||||
if (quoted) // look for ending quotes and escapes
|
||||
{
|
||||
switch (*source)
|
||||
{
|
||||
case '\\': // escape next character
|
||||
escaped = true;
|
||||
break;
|
||||
case '%': // format specifier in string
|
||||
if (formatType != NoFormat)
|
||||
{
|
||||
// format is allowed here
|
||||
// just memorize position here and and do actual coding later
|
||||
// after all variables and parameters have been replaced
|
||||
// so that extra information is ready for format converter
|
||||
if (numFormats+1 == sizeof(formatPos))
|
||||
{
|
||||
errorMsg(line, "Max 20 formats allowed in one protocol line");
|
||||
return false;
|
||||
}
|
||||
formatPos[numFormats++]=buffer.length();
|
||||
buffer.append(*source);
|
||||
break;
|
||||
}
|
||||
case '"':
|
||||
case '\'':
|
||||
if (*source == quoted) // ending quote
|
||||
@ -1310,13 +1286,13 @@ compileString(StreamBuffer& buffer, const char*& source,
|
||||
{
|
||||
if (*p != 0)
|
||||
{
|
||||
errorMsg(line,
|
||||
error(line, filename(),
|
||||
"Garbage after numeric source: %s", source);
|
||||
return false;
|
||||
}
|
||||
if (temp > 0xFF || temp < -0x80)
|
||||
{
|
||||
errorMsg(line,
|
||||
error(line, filename(),
|
||||
"Value %s does not fit in byte\n", source);
|
||||
return false;
|
||||
}
|
||||
@ -1349,6 +1325,7 @@ compileString(StreamBuffer& buffer, const char*& source,
|
||||
{"nl", 0x0A},
|
||||
{"vt", 0x0B},
|
||||
{"ff", 0x0C},
|
||||
{"np", 0x0C},
|
||||
{"cr", 0x0D},
|
||||
{"so", 0x0E},
|
||||
{"si", 0x0F},
|
||||
@ -1379,7 +1356,7 @@ compileString(StreamBuffer& buffer, const char*& source,
|
||||
c = codes[i].code;
|
||||
if (c == skip && formatType != ScanFormat)
|
||||
{
|
||||
errorMsg(line,
|
||||
error(line, filename(),
|
||||
"Use of '%s' only allowed in input formats\n",
|
||||
source);
|
||||
return false;
|
||||
@ -1396,7 +1373,7 @@ compileString(StreamBuffer& buffer, const char*& source,
|
||||
}
|
||||
if (c) continue;
|
||||
// source may contain a function name
|
||||
errorMsg(line,
|
||||
error(line, filename(),
|
||||
"Unexpected word: %s\n", source);
|
||||
return false;
|
||||
}
|
||||
@ -1432,14 +1409,14 @@ compileFormat(StreamBuffer& buffer, const char*& formatstr,
|
||||
buffer.append(format_field);
|
||||
if (!client)
|
||||
{
|
||||
errorMsg(line,
|
||||
error(line, filename(),
|
||||
"Using fieldname is not possible in this context\n");
|
||||
return false;
|
||||
}
|
||||
const char* fieldnameEnd = strchr(source+=2, ')');
|
||||
if (!fieldnameEnd)
|
||||
{
|
||||
errorMsg(line,
|
||||
error(line, filename(),
|
||||
"Missing ')' after field name\n");
|
||||
return false;
|
||||
}
|
||||
@ -1451,7 +1428,7 @@ compileFormat(StreamBuffer& buffer, const char*& formatstr,
|
||||
StreamBuffer fieldAddress;
|
||||
if (!client->getFieldAddress(buffer(fieldname), fieldAddress))
|
||||
{
|
||||
errorMsg(line,
|
||||
error(line, filename(),
|
||||
"Field '%s' not found\n", buffer(fieldname));
|
||||
return false;
|
||||
}
|
||||
@ -1465,140 +1442,12 @@ compileFormat(StreamBuffer& buffer, const char*& formatstr,
|
||||
buffer.append(format);
|
||||
}
|
||||
const char* formatstart = source + 1;
|
||||
// look for flags
|
||||
streamFormat.flags = 0;
|
||||
bool loop = true;
|
||||
while (loop)
|
||||
{
|
||||
switch (*++source)
|
||||
{
|
||||
case '-':
|
||||
streamFormat.flags |= left_flag;
|
||||
break;
|
||||
case '+':
|
||||
streamFormat.flags |= sign_flag;
|
||||
break;
|
||||
case ' ':
|
||||
streamFormat.flags |= space_flag;
|
||||
break;
|
||||
case '#':
|
||||
streamFormat.flags |= alt_flag;
|
||||
break;
|
||||
case '0':
|
||||
streamFormat.flags |= zero_flag;
|
||||
break;
|
||||
case '*':
|
||||
if (formatType != ScanFormat)
|
||||
{
|
||||
errorMsg(line,
|
||||
"Use of skip modifier '*' "
|
||||
"only allowed in input formats\n");
|
||||
return false;
|
||||
}
|
||||
if (fieldname)
|
||||
{
|
||||
errorMsg(line,
|
||||
"Use of skip modifier '*' not allowed "
|
||||
"together with field name\n");
|
||||
return false;
|
||||
}
|
||||
streamFormat.flags |= skip_flag;
|
||||
break;
|
||||
case '?':
|
||||
if (formatType != ScanFormat)
|
||||
{
|
||||
errorMsg(line,
|
||||
"Use of default modifier '?' "
|
||||
"only allowed in input formats\n");
|
||||
return false;
|
||||
}
|
||||
streamFormat.flags |= default_flag;
|
||||
break;
|
||||
default:
|
||||
loop = false;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (formatType != PrintFormat &&
|
||||
streamFormat.flags & (left_flag|sign_flag|space_flag|zero_flag))
|
||||
{
|
||||
errorMsg(line,
|
||||
"Use of format modifiers '-', '+', ' ', '0' "
|
||||
"only allowed in output formats\n");
|
||||
return false;
|
||||
}
|
||||
if (!(~streamFormat.flags & (left_flag|zero_flag)))
|
||||
{
|
||||
errorMsg(line,
|
||||
"Can't use modifiers '-' and '0' together\n");
|
||||
return false;
|
||||
}
|
||||
if (!(~streamFormat.flags & (space_flag|sign_flag)))
|
||||
{
|
||||
errorMsg(line,
|
||||
"Can't use modifiers ' ' and '+' together\n");
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
// look for width
|
||||
unsigned long val;
|
||||
char* p;
|
||||
val = strtoul (source, &p, 10);
|
||||
source = p;
|
||||
if (val > 0xFFFF)
|
||||
{
|
||||
errorMsg(line,
|
||||
"Field width %ld out of range\n", val);
|
||||
return false;
|
||||
}
|
||||
streamFormat.width = (unsigned short)val;
|
||||
// look for prec
|
||||
streamFormat.prec = -1;
|
||||
if (*source == '.')
|
||||
{
|
||||
source++;
|
||||
val = strtoul(source, &p, 10);
|
||||
if (p == source)
|
||||
{
|
||||
debug("source = %s\n", source);
|
||||
errorMsg(line,
|
||||
"Numeric precision field expected after '.'\n");
|
||||
return false;
|
||||
}
|
||||
source = p;
|
||||
if (val > 0x7FFF)
|
||||
{
|
||||
errorMsg(line,
|
||||
"Precision %ld out of range\n", val);
|
||||
return false;
|
||||
}
|
||||
streamFormat.prec = (short)val;
|
||||
}
|
||||
// look for converter
|
||||
streamFormat.conv = *source++;
|
||||
debug("StreamProtocolParser::Protocol::compileFormat: converter='%c'\n",
|
||||
streamFormat.conv);
|
||||
if (!streamFormat.conv || strchr("'\" (.0+-*", streamFormat.conv))
|
||||
{
|
||||
debug("StreamProtocolParser::Protocol::compileFormat: formatstr='%s'\n",
|
||||
formatstr);
|
||||
errorMsg(line,
|
||||
"Missing converter character\n");
|
||||
return false;
|
||||
}
|
||||
StreamFormatConverter* converter;
|
||||
converter = StreamFormatConverter::find(streamFormat.conv);
|
||||
if (!converter)
|
||||
{
|
||||
errorMsg(line,
|
||||
"No converter registered for format '%%%c'\n",
|
||||
streamFormat.conv);
|
||||
return false;
|
||||
}
|
||||
|
||||
// parse format and get info string
|
||||
StreamBuffer infoString;
|
||||
int type = converter->parse(streamFormat, infoString,
|
||||
source, formatType == ScanFormat);
|
||||
int type = StreamFormatConverter::parseFormat(source,
|
||||
formatType, streamFormat, infoString);
|
||||
|
||||
if (!type)
|
||||
{
|
||||
// parsing failed
|
||||
@ -1606,18 +1455,25 @@ compileFormat(StreamBuffer& buffer, const char*& formatstr,
|
||||
}
|
||||
if (type < long_format && type > pseudo_format)
|
||||
{
|
||||
errorMsg(line,
|
||||
error(line, filename(),
|
||||
"Illegal format type %d returned from '%%%c' converter\n",
|
||||
type, streamFormat.conv);
|
||||
return false;
|
||||
}
|
||||
if (type == pseudo_format && fieldname)
|
||||
{
|
||||
errorMsg(line,
|
||||
error(line, filename(),
|
||||
"Fieldname not allowed with pseudo format: '%%(%s)%c'\n",
|
||||
buffer(fieldname), streamFormat.conv);
|
||||
return false;
|
||||
}
|
||||
if (fieldname && streamFormat.flags & skip_flag)
|
||||
{
|
||||
error(line, filename(),
|
||||
"Use of skip modifier '*' not allowed "
|
||||
"together with redirection\n");
|
||||
return false;
|
||||
}
|
||||
streamFormat.type = static_cast<StreamFormatType>(type);
|
||||
if (infoString && infoString[-1] != eos)
|
||||
{
|
||||
@ -1655,13 +1511,13 @@ compileCommands(StreamBuffer& buffer, const char*& source, Client* client)
|
||||
args = source + strlen(source)+1+sizeof(int);
|
||||
if (!client->compileCommand(this, buffer, command, args))
|
||||
{
|
||||
errorMsg(getLineNumber(source),
|
||||
error(getLineNumber(source), filename(),
|
||||
"in command '%s'\n", command);
|
||||
return false;
|
||||
}
|
||||
if (*args)
|
||||
{
|
||||
errorMsg(getLineNumber(source),
|
||||
error(getLineNumber(source), filename(),
|
||||
"Garbage after '%s' command: '%s'\n",
|
||||
command, args);
|
||||
return false;
|
||||
|
@ -32,7 +32,7 @@ public:
|
||||
|
||||
enum Codes
|
||||
{
|
||||
eos = 0, skip, format, format_field, last_function_code
|
||||
eos = 0, skip, whitespace, format, format_field, last_function_code
|
||||
};
|
||||
|
||||
class Client;
|
||||
@ -75,8 +75,6 @@ public:
|
||||
bool compileString(StreamBuffer& buffer, const char*& source,
|
||||
FormatType formatType = NoFormat, Client* = NULL, int quoted = false);
|
||||
bool checkUnused();
|
||||
void errorMsg(int line, const char* fmt, ...)
|
||||
__attribute__ ((format(printf,3,4)));
|
||||
~Protocol();
|
||||
void report();
|
||||
};
|
||||
@ -115,8 +113,6 @@ private:
|
||||
const char* specialchars = NULL, bool eofAllowed = false);
|
||||
bool parseAssignment(const char* variable, Protocol&);
|
||||
bool parseValue(StreamBuffer& buffer, bool lazy = false);
|
||||
void errorMsg(const char* fmt, ...)
|
||||
__attribute__ ((format(printf,2,3)));
|
||||
|
||||
protected:
|
||||
~StreamProtocolParser(); // get rid of cygnus-2.7.2 compiler warning
|
||||
|
539
src/TimestampConverter.cc
Normal file
539
src/TimestampConverter.cc
Normal file
@ -0,0 +1,539 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) *
|
||||
* (C) 2010 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is the time stamp converter of StreamDevice. *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
|
||||
#include "StreamFormatConverter.h"
|
||||
#include "StreamError.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define tzset() _tzset()
|
||||
#define timezone _timezone
|
||||
#define localtime_r(timet,tm) localtime_s(tm,timet) /* Windows sucks */
|
||||
#endif
|
||||
|
||||
#ifdef __rtems__
|
||||
#define timezone _timezone
|
||||
#endif
|
||||
|
||||
#ifdef vxWorks
|
||||
int timezone = 0;
|
||||
#define tzset() do {\
|
||||
(void) (sscanf(getenv("TIMEZONE"), "%*[^:]::%d", &timezone) || \
|
||||
sscanf(getenv("TIMEZONE"), "%*[^:]:%*[^:]:%d", &timezone) || \
|
||||
sscanf(getenv("EPICS_TS_MIN_WEST"), "%d", &timezone));\
|
||||
timezone*=60;\
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
class TimestampConverter : public StreamFormatConverter
|
||||
{
|
||||
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||
bool printDouble(const StreamFormat&, StreamBuffer&, double);
|
||||
int scanDouble(const StreamFormat&, const char*, double&);
|
||||
};
|
||||
|
||||
int TimestampConverter::
|
||||
parse(const StreamFormat&, StreamBuffer& info,
|
||||
const char*& source, bool)
|
||||
{
|
||||
unsigned int n;
|
||||
char* c;
|
||||
|
||||
if (*source == '(')
|
||||
{
|
||||
while (*++source != ')')
|
||||
{
|
||||
switch (*source)
|
||||
{
|
||||
case 0:
|
||||
error ("missing ')' after %%T format\n");
|
||||
return false;
|
||||
case esc:
|
||||
info.append(*++source);
|
||||
if (*source == '%') info.append('%');
|
||||
break;
|
||||
case '%':
|
||||
source++;
|
||||
/* look for formatted fractions like %3f */
|
||||
if (isdigit(*source))
|
||||
{
|
||||
n = strtoul(source, &c, 10);
|
||||
if (*c == 'f')
|
||||
{
|
||||
source = c;
|
||||
info.printf("%%0%uf", n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* look for nanoseconds %N of %f */
|
||||
if (*source == 'N' || *source == 'f')
|
||||
{
|
||||
info.printf("%%09f");
|
||||
break;
|
||||
}
|
||||
/* look for seconds with fractions like %.3S */
|
||||
if (*source == '.')
|
||||
{
|
||||
c = (char*) source+1;
|
||||
n = isdigit(*c) ? strtoul(c, &c, 10) : 9;
|
||||
if (toupper(*c) == 'S')
|
||||
{
|
||||
source = c;
|
||||
info.printf("%%%c.%%0%uf", *c, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* else normal format */
|
||||
info.append('%');
|
||||
default:
|
||||
info.append(*source);
|
||||
}
|
||||
}
|
||||
source++;
|
||||
info.append('\0');
|
||||
}
|
||||
else
|
||||
{
|
||||
info.append("%Y-%m-%d %H:%M:%S").append('\0');
|
||||
}
|
||||
return double_format;
|
||||
}
|
||||
|
||||
bool TimestampConverter::
|
||||
printDouble(const StreamFormat& format, StreamBuffer& output, double value)
|
||||
{
|
||||
struct tm brokenDownTime;
|
||||
char buffer [40];
|
||||
char fracbuffer [15];
|
||||
int length;
|
||||
time_t sec;
|
||||
double frac;
|
||||
int i, n;
|
||||
char* c;
|
||||
char* p;
|
||||
|
||||
sec = (time_t) value;
|
||||
frac = value - sec;
|
||||
localtime_r(&sec, &brokenDownTime);
|
||||
debug ("TimestampConverter::printDouble %f, '%s'\n", value, format.info);
|
||||
length = strftime(buffer, sizeof(buffer), format.info, &brokenDownTime);
|
||||
i = output.length();
|
||||
output.append(buffer, length);
|
||||
|
||||
/* look for fractional seconds */
|
||||
while ((i = output.find("%0",i)) != -1)
|
||||
{
|
||||
n = strtol(output(i+1), &c, 10);
|
||||
if (*c++ != 'f') return false;
|
||||
/* print fractional part */
|
||||
sprintf(fracbuffer, "%.*f", n, frac);
|
||||
p = strchr(fracbuffer, '.')+1;
|
||||
output.replace(i, c-output(i), p);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* many OS don't have strptime or strptime does not fully support
|
||||
all fields, e.g. %z.
|
||||
*/
|
||||
|
||||
static int strmatch(const char*& input, const char** strings, int minlen)
|
||||
{
|
||||
int i;
|
||||
int c;
|
||||
|
||||
for (i=0; strings[i]; i++) {
|
||||
for (c=0; ; c++)
|
||||
{
|
||||
if (strings[i][c] == 0) {
|
||||
input += c;
|
||||
return i;
|
||||
}
|
||||
if (tolower(input[c]) != strings[i][c]) {
|
||||
if (c >= minlen) {
|
||||
input += c;
|
||||
return i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int nummatch(const char*& input, int min, int max)
|
||||
{
|
||||
int i;
|
||||
char *c;
|
||||
|
||||
i = strtol(input, &c, 10);
|
||||
if (c == input) return -10000;
|
||||
if (i < min || i > max) return -10000;
|
||||
input = c;
|
||||
return i;
|
||||
}
|
||||
|
||||
static const char* scantime(const char* input, const char* format, struct tm *tm, unsigned long *ns)
|
||||
{
|
||||
static const char* months[] = {
|
||||
"january", "february", "march", "april", "may", "june",
|
||||
"july", "august", "september", "november", "december", 0 };
|
||||
static const char* ampm[] = {
|
||||
"am", "pm", 0 };
|
||||
|
||||
int i, n;
|
||||
int pm = -1;
|
||||
int century = -1;
|
||||
int zone = 0;
|
||||
|
||||
tzset();
|
||||
zone = timezone/60;
|
||||
debug ("TimestampConverter::scantime: native time zone = %d\n", zone);
|
||||
|
||||
while (*format)
|
||||
{
|
||||
switch (*format)
|
||||
{
|
||||
case '%':
|
||||
debug ("TimestampConverter::scantime: input = '%s'\n", input);
|
||||
format++;
|
||||
startover:
|
||||
switch (*format++)
|
||||
{
|
||||
/* Modifiers (ignore) */
|
||||
case 'E':
|
||||
case 'O':
|
||||
goto startover;
|
||||
/* constants */
|
||||
case 0: /* stray % at end of format string */
|
||||
format--;
|
||||
case '%':
|
||||
if (*input++ != '%') return NULL;
|
||||
break;
|
||||
case 'n':
|
||||
if (*input++ != '\n') return NULL;
|
||||
break;
|
||||
case 't':
|
||||
if (*input++ != '\t') return NULL;
|
||||
break;
|
||||
/* ignored */
|
||||
case 'A': /* day of week name */
|
||||
case 'a':
|
||||
while (isalpha((int)*input)) input++;
|
||||
/* ignore */
|
||||
break;
|
||||
case 'u': /* day of week number (Monday = 1 to Sunday = 7) */
|
||||
case 'w': /* day of week number (Sunday = 0 to Saturday = 6) */
|
||||
i = nummatch(input, 0, 7);
|
||||
if (i < 0)
|
||||
{
|
||||
error ("error parsing day of week: '%.20s'\n", input);
|
||||
return NULL;
|
||||
}
|
||||
debug ("TimestampConverter::scantime: day of week = %d\n", i);
|
||||
/* ignore */
|
||||
break;
|
||||
case 'U': /* week number */
|
||||
case 'W':
|
||||
case 'V':
|
||||
i = nummatch(input, 0, 53);
|
||||
if (i < 0)
|
||||
{
|
||||
error ("error parsing week number: '%.20s'\n", input);
|
||||
return NULL;
|
||||
}
|
||||
debug ("TimestampConverter::scantime: week number = %d\n", i);
|
||||
/* ignore */
|
||||
break;
|
||||
case 'j': /* day of year */
|
||||
i = nummatch(input, 0, 366);
|
||||
if (i < 0)
|
||||
{
|
||||
error ("error parsing day of year: '%.20s'\n", input);
|
||||
return NULL;
|
||||
}
|
||||
debug ("TimestampConverter::scantime: day of year = %d\n", i);
|
||||
/* ignore */
|
||||
break;
|
||||
case 'Z': /* time zone name */
|
||||
while (isalpha((int)*input)) input++;
|
||||
/* ignore */
|
||||
break;
|
||||
/* date */
|
||||
case 'b': /* month */
|
||||
case 'h':
|
||||
case 'B':
|
||||
case 'm':
|
||||
i = strmatch(input, months, 3);
|
||||
if (i < 0)
|
||||
{
|
||||
i = nummatch(input, 1, 12);
|
||||
if (i < 0)
|
||||
{
|
||||
error ("error parsing month: '%.20s'\n", input);
|
||||
return NULL;
|
||||
}
|
||||
i--; /* Jan = 0 */
|
||||
}
|
||||
tm->tm_mon = i;
|
||||
debug ("TimestampConverter::scantime: month = %d (%s)\n", tm->tm_mon+1, months[tm->tm_mon]);
|
||||
break;
|
||||
case 'd': /* day of month */
|
||||
case 'e':
|
||||
i = nummatch(input, 1, 31);
|
||||
if (i < 0)
|
||||
{
|
||||
error ("error parsing day of month: '%.20s'\n", input);
|
||||
return NULL;
|
||||
}
|
||||
tm->tm_mday = i;
|
||||
debug ("TimestampConverter::scantime: day = %d\n", tm->tm_mday);
|
||||
break;
|
||||
case 'Y': /* year */
|
||||
case 'y':
|
||||
i = strtol(input, (char**)&input, 10);
|
||||
if (i < 100)
|
||||
{ /* 2 digit year */
|
||||
if (century == -1) century = (i >= 69);
|
||||
tm->tm_year = i + century * 100; /* 0 = 1900 */
|
||||
}
|
||||
else
|
||||
{ /* 4 digit year */
|
||||
tm->tm_year = i - 1900; /* 0 = 1900 */
|
||||
}
|
||||
debug ("TimestampConverter::scantime: year = %d\n", tm->tm_year + 1900);
|
||||
break;
|
||||
case 'C': /* century */
|
||||
i = nummatch(input, 0, 99);
|
||||
if (i < 0)
|
||||
{
|
||||
error ("error parsing century: '%.20s'\n", input);
|
||||
return NULL;
|
||||
}
|
||||
century = i - 19;
|
||||
tm->tm_year = tm->tm_year%100 + 100 * i; /* 0 = 1900 */
|
||||
debug ("TimestampConverter::scantime: year = %d\n", tm->tm_year + 1900);
|
||||
break;
|
||||
|
||||
/* time */
|
||||
case 'H': /* hour */
|
||||
case 'k':
|
||||
case 'I':
|
||||
case 'l':
|
||||
i = nummatch(input, 0, 23);
|
||||
if (i < 0)
|
||||
{
|
||||
error ("error parsing hour: '%.20s'\n", input);
|
||||
return NULL;
|
||||
}
|
||||
if ((pm == 0) && (i == 12)) i = 0;
|
||||
if ((pm == 1) && (i < 12)) i += 12;
|
||||
tm->tm_hour = i;
|
||||
debug ("TimestampConverter::scantime: hour = %d\n", tm->tm_hour);
|
||||
break;
|
||||
case 'P': /* AM / PM */
|
||||
case 'p':
|
||||
i = strmatch(input, ampm, 1);
|
||||
if (i < 0)
|
||||
{
|
||||
error ("error parsing am/pm: '%.20s'\n", input);
|
||||
return NULL;
|
||||
}
|
||||
pm = i;
|
||||
if ((pm == 0) && (tm->tm_hour == 12)) tm->tm_hour = 0;
|
||||
if ((pm == 1) && (tm->tm_hour < 12)) tm->tm_hour += 12;
|
||||
debug ("TimestampConverter::scantime: %s hour = %d\n", pm?"PM":"AM", tm->tm_hour);
|
||||
break;
|
||||
case 'M': /* minute */
|
||||
i = nummatch(input, 1, 59);
|
||||
if (i < 0)
|
||||
{
|
||||
error ("error parsing minute: '%.20s'\n", input);
|
||||
return NULL;
|
||||
}
|
||||
tm->tm_min = i;
|
||||
debug ("TimestampConverter::scantime: min = %d\n", tm->tm_min);
|
||||
break;
|
||||
case 'S': /* second */
|
||||
i = nummatch(input, 1, 60);
|
||||
if (i < 0)
|
||||
{
|
||||
error ("error parsing week second: '%.20s'\n", input);
|
||||
return NULL;
|
||||
}
|
||||
tm->tm_sec = i;
|
||||
debug ("TimestampConverter::scantime: sec = %d\n", tm->tm_sec);
|
||||
break;
|
||||
case 's': /* second since 1970 */
|
||||
i = strtol(input, (char**)&input, 10);
|
||||
tm->tm_sec = i;
|
||||
tm->tm_mon = -1;
|
||||
tm->tm_isdst = 0;
|
||||
debug ("TimestampConverter::scantime: sec = %d\n", tm->tm_sec);
|
||||
break;
|
||||
case '0': /* fractions of seconds like %09f */
|
||||
n = strtol(format-1, (char**)&format, 10);
|
||||
if (*format++ != 'f') return NULL;
|
||||
debug ("max %d digits fraction in '%s'\n", n, input);
|
||||
i = 0;
|
||||
while (n-- && isdigit(*input))
|
||||
{
|
||||
i *= 10;
|
||||
i += *input++ - '0';
|
||||
}
|
||||
while (i < 100000000) i *= 10;
|
||||
*ns = i;
|
||||
debug ("TimestampConverter::scantime: nanosec = %d, rest '%s'\n", i, input);
|
||||
break;
|
||||
case 'z': /* time zone offset */
|
||||
i = nummatch(input, -2400, 2400);
|
||||
if (i < -2400)
|
||||
{
|
||||
error ("error parsing time zone: '%.20s'\n", input);
|
||||
return NULL;
|
||||
}
|
||||
zone = i / 100 * 60 + i % 100;
|
||||
tm->tm_isdst = 0;
|
||||
debug ("TimestampConverter::scantime: zone = %d\n", zone);
|
||||
break;
|
||||
case '+': /* set time zone in format string */
|
||||
case '-':
|
||||
format--;
|
||||
i = nummatch(format, -2400, 2400);
|
||||
zone = i / 100 * 60 + i % 100;
|
||||
tm->tm_isdst = 0;
|
||||
debug ("TimestampConverter::scantime: zone = %d\n", zone);
|
||||
break;
|
||||
/* shortcuts */
|
||||
case 'c':
|
||||
if ((input = scantime(input, "%a %b %d %H:%M:%S %Y", tm, ns)) == NULL)
|
||||
return NULL;
|
||||
break;
|
||||
case 'D':
|
||||
if ((input = scantime(input, "%m/%d/%y", tm, ns)) == NULL)
|
||||
return NULL;
|
||||
break;
|
||||
case 'F':
|
||||
if ((input = scantime(input, "%Y-%m-%d", tm, ns)) == NULL)
|
||||
return NULL;
|
||||
break;
|
||||
case 'R':
|
||||
if ((input = scantime(input, "%H:%M", tm, ns)) == NULL)
|
||||
return NULL;
|
||||
break;
|
||||
case 'T':
|
||||
if ((input = scantime(input, "%H:%M:%S", tm, ns)) == NULL)
|
||||
return NULL;
|
||||
break;
|
||||
case 'x':
|
||||
if ((input = scantime(input, "%m/%d/%y", tm, ns)) == NULL)
|
||||
return NULL;
|
||||
break;
|
||||
case 'X':
|
||||
case 'r':
|
||||
if ((input = scantime(input, "%I:%M:%S %p", tm, ns)) == NULL)
|
||||
return NULL;
|
||||
break;
|
||||
default:
|
||||
error ("unknown time format %%%s\n", --format);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
format++;
|
||||
while (isspace(*input)) input++;
|
||||
break;
|
||||
default:
|
||||
if (*format++ != *input++)
|
||||
{
|
||||
error("input '%.20s' does not match constant '%.20s'\n", --input, --format);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
zone -= timezone/60;
|
||||
tm->tm_min += zone;
|
||||
tm->tm_hour += tm->tm_min / 60;
|
||||
tm->tm_min %= 60;
|
||||
if (tm->tm_min < 0)
|
||||
{
|
||||
tm->tm_min += 60;
|
||||
tm->tm_hour -= 1;
|
||||
}
|
||||
tm->tm_mday -= tm->tm_hour / 24;
|
||||
tm->tm_hour %= 24;
|
||||
if (tm->tm_hour < 0)
|
||||
{
|
||||
tm->tm_min += 24;
|
||||
tm->tm_mday -= 1;
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int TimestampConverter::
|
||||
scanDouble(const StreamFormat& format, const char* input, double& value)
|
||||
{
|
||||
struct tm brokenDownTime;
|
||||
time_t seconds;
|
||||
unsigned long nanoseconds;
|
||||
const char* end;
|
||||
|
||||
/* Init time stamp with "today" */
|
||||
time (&seconds);
|
||||
localtime_r(&seconds, &brokenDownTime);
|
||||
brokenDownTime.tm_sec = 0;
|
||||
brokenDownTime.tm_min = 0;
|
||||
brokenDownTime.tm_hour = 0;
|
||||
brokenDownTime.tm_yday = 0;
|
||||
brokenDownTime.tm_isdst = -1;
|
||||
nanoseconds = 0;
|
||||
|
||||
end = scantime(input, format.info, &brokenDownTime, &nanoseconds);
|
||||
if (end == NULL) {
|
||||
error ("error parsing time\n");
|
||||
return -1;
|
||||
}
|
||||
if (brokenDownTime.tm_mon == -1) {
|
||||
seconds = brokenDownTime.tm_sec;
|
||||
} else {
|
||||
seconds = mktime(&brokenDownTime);
|
||||
if (seconds == (time_t) -1 && brokenDownTime.tm_yday == 0)
|
||||
{
|
||||
error ("mktime failed for %02d/%02d/%04d %02d:%02d:%02d\n",
|
||||
brokenDownTime.tm_mon+1,
|
||||
brokenDownTime.tm_mday,
|
||||
brokenDownTime.tm_year+1900,
|
||||
brokenDownTime.tm_hour,
|
||||
brokenDownTime.tm_min,
|
||||
brokenDownTime.tm_sec);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
value = seconds + nanoseconds*1e-9;
|
||||
return end-input;
|
||||
}
|
||||
|
||||
RegisterConverter (TimestampConverter, "T");
|
@ -85,7 +85,6 @@ long streamReport(int interest);
|
||||
long streamReadWrite(dbCommon *record);
|
||||
long streamGetIointInfo(int cmd, dbCommon *record, IOSCANPVT *ppvt);
|
||||
long streamPrintf(dbCommon *record, format_t *format, ...);
|
||||
long streamScanSep(dbCommon *record);
|
||||
long streamScanfN(dbCommon *record, format_t *format,
|
||||
void*, size_t maxStringSize);
|
||||
|
||||
@ -99,7 +98,7 @@ long streamScanfN(dbCommon *record, format_t *format,
|
||||
#define devStreamGetIointInfo streamGetIointInfo
|
||||
#define devStreamPrintf streamPrintf
|
||||
#define devStreamPrintSep(record) (0)
|
||||
#define devStreamScanSep streamScanSep
|
||||
#define devStreamScanSep (0)
|
||||
#define devStreamScanf(record, format, value) \
|
||||
streamScanfN(record, format, value, MAX_STRING_SIZE)
|
||||
#define streamScanf(record, format, value) \
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <stdlib.h>
|
||||
#include "devStream.h"
|
||||
#include <aaiRecord.h>
|
||||
#include <errlog.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
static long readData (dbCommon *record, format_t *format)
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <stdlib.h>
|
||||
#include "devStream.h"
|
||||
#include <aaoRecord.h>
|
||||
#include <errlog.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
static long readData (dbCommon *record, format_t *format)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "devStream.h"
|
||||
#include <waveformRecord.h>
|
||||
#include <string.h>
|
||||
#include <errlog.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
static long readData (dbCommon *record, format_t *format)
|
||||
|
6
src/makedbd.pl
Normal file
6
src/makedbd.pl
Normal file
@ -0,0 +1,6 @@
|
||||
for (@ARGV) {
|
||||
print "device($_,INST_IO,dev${_}Stream,\"stream\")\n";
|
||||
}
|
||||
print "driver(stream)\n";
|
||||
print "variable(streamDebug, int)\n";
|
||||
print "registrar(streamRegistrar)\n";
|
6
src/makeref.pl
Normal file
6
src/makeref.pl
Normal file
@ -0,0 +1,6 @@
|
||||
$t=@ARGV[0];
|
||||
shift;
|
||||
for (@ARGV) {
|
||||
print "extern void* ref_${_}$t;\n";
|
||||
print "void* p$_ = ref_${_}$t;\n";
|
||||
}
|
25
srcSynApps/Makefile
Normal file
25
srcSynApps/Makefile
Normal file
@ -0,0 +1,25 @@
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
-include ../src/CONFIG_STREAM
|
||||
-include ../../src/CONFIG_STREAM
|
||||
|
||||
LIBRARY_DEFAULT = streamSynApps
|
||||
|
||||
DBD += $(LIBRARY_DEFAULT).dbd
|
||||
|
||||
ifeq ($(LOADABLE_MODULE),YES)
|
||||
SRCS += $(LIBRARY_DEFAULT)_registerRecordDeviceDriver.cpp
|
||||
endif
|
||||
SRCS += $(SYNAPPS_RECORDS:%=dev%Stream.c)
|
||||
|
||||
LIB_LIBS += stream $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
# create streamSynApps.dbd from all SYNAPPS_RECORDS
|
||||
$(COMMON_DIR)/$(LIBRARY_DEFAULT).dbd: ../../src/CONFIG_STREAM
|
||||
@for r in $(SYNAPPS_RECORDS); \
|
||||
do echo "device($$r,INST_IO,dev$${r}Stream,\"stream\")"; \
|
||||
done > $@
|
108
srcSynApps/devscalcoutStream.c
Normal file
108
srcSynApps/devscalcoutStream.c
Normal file
@ -0,0 +1,108 @@
|
||||
/***************************************************************
|
||||
* Stream Device record interface for scalcout records *
|
||||
* *
|
||||
* (C) 2006 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is an EPICS record Interface for StreamDevice. *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
|
||||
#include <devStream.h>
|
||||
#include <sCalcoutRecord.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
/* scalcout record has a bug: it never calls init_record
|
||||
of the device support.
|
||||
Fix: sCalcoutRecord.c, end of init_record() add
|
||||
|
||||
if(pscalcoutDSET->init_record ) {
|
||||
return (*pscalcoutDSET->init_record)(pcalc);
|
||||
}
|
||||
The bug has been fixed in version 2-6-1.
|
||||
*/
|
||||
|
||||
static long readData (dbCommon *record, format_t *format)
|
||||
{
|
||||
scalcoutRecord *sco = (scalcoutRecord *) record;
|
||||
|
||||
switch (format->type)
|
||||
{
|
||||
case DBF_DOUBLE:
|
||||
{
|
||||
return streamScanf (record, format, &sco->val);
|
||||
}
|
||||
case DBF_LONG:
|
||||
case DBF_ENUM:
|
||||
{
|
||||
long lval;
|
||||
|
||||
if (streamScanf (record, format, &lval)) return ERROR;
|
||||
sco->val = lval;
|
||||
return OK;
|
||||
}
|
||||
case DBF_STRING:
|
||||
{
|
||||
return (streamScanfN (record, format,
|
||||
sco->sval, sizeof(sco->val)));
|
||||
}
|
||||
}
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
static long writeData (dbCommon *record, format_t *format)
|
||||
{
|
||||
scalcoutRecord *sco = (scalcoutRecord *) record;
|
||||
|
||||
switch (format->type)
|
||||
{
|
||||
case DBF_DOUBLE:
|
||||
{
|
||||
return streamPrintf (record, format, sco->oval);
|
||||
}
|
||||
case DBF_LONG:
|
||||
case DBF_ENUM:
|
||||
{
|
||||
return streamPrintf (record, format, (long)sco->oval);
|
||||
}
|
||||
case DBF_STRING:
|
||||
{
|
||||
return streamPrintf (record, format, sco->osv);
|
||||
}
|
||||
}
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
static long initRecord (dbCommon *record)
|
||||
{
|
||||
scalcoutRecord *sco = (scalcoutRecord *) record;
|
||||
|
||||
return streamInitRecord (record, &sco->out, readData, writeData);
|
||||
}
|
||||
|
||||
struct {
|
||||
long number;
|
||||
DEVSUPFUN report;
|
||||
DEVSUPFUN init;
|
||||
DEVSUPFUN init_record;
|
||||
DEVSUPFUN get_ioint_info;
|
||||
DEVSUPFUN write;
|
||||
} devscalcoutStream = {
|
||||
5,
|
||||
streamReport,
|
||||
streamInit,
|
||||
initRecord,
|
||||
streamGetIointInfo,
|
||||
streamWrite,
|
||||
};
|
||||
|
||||
epicsExportAddress(dset,devscalcoutStream);
|
19
stream.dbd
Normal file
19
stream.dbd
Normal file
@ -0,0 +1,19 @@
|
||||
device(aai,INST_IO,devaaiStream,"stream")
|
||||
device(aao,INST_IO,devaaoStream,"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(calcout,INST_IO,devcalcoutStream,"stream")
|
||||
driver(stream)
|
||||
variable(streamDebug, int)
|
||||
registrar(streamRegistrar)
|
4
streamApp/.cvsignore
Normal file
4
streamApp/.cvsignore
Normal file
@ -0,0 +1,4 @@
|
||||
StreamDebug.log
|
||||
streamApp
|
||||
streamApp.exe*
|
||||
TS.*
|
65
streamApp/Makefile
Normal file
65
streamApp/Makefile
Normal file
@ -0,0 +1,65 @@
|
||||
TOP=../..
|
||||
|
||||
# Look if we have EPICS R3.13 or R3.14
|
||||
ifeq ($(wildcard $(TOP)/configure),)
|
||||
# EPICS R3.13
|
||||
include $(TOP)/config/CONFIG_APP
|
||||
# The real work is in Makefile.Vx
|
||||
include $(TOP)/config/RULES_ARCHS
|
||||
else
|
||||
|
||||
# EPICS R3.14
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
#HOST_OPT = NO
|
||||
|
||||
PROD = streamApp
|
||||
DBD = streamApp.dbd
|
||||
|
||||
streamApp_DBD += base.dbd
|
||||
#streamApp_DBD += aaiRecord.dbd aaoRecord.dbd
|
||||
|
||||
PROD_SRCS += streamApp_registerRecordDeviceDriver.cpp
|
||||
PROD_SRCS_DEFAULT = streamAppMain.cc
|
||||
PROD_SRCS_vxWorks = -nil-
|
||||
|
||||
PROD_LIBS = stream
|
||||
|
||||
ifdef ASYN
|
||||
# Which types of asyn busses do you have?
|
||||
ifneq ($(OS_CLASS), WIN32)
|
||||
# asynDriver up to version 4-16 does not support serial port for Windows!
|
||||
streamApp_DBD += drvAsynSerialPort.dbd
|
||||
endif
|
||||
streamApp_DBD += drvAsynIPPort.dbd
|
||||
#streamApp_DBD += drvGsIP488.dbd
|
||||
#streamApp_DBD += drvNi1014.dbd
|
||||
streamApp_DBD += drvVxi11.dbd
|
||||
PROD_LIBS += asyn
|
||||
endif
|
||||
|
||||
ifneq ($(words $(CALC) $(SYNAPPS)), 0)
|
||||
# With synApps scalcout record
|
||||
streamApp_DBD += calc.dbd
|
||||
streamApp_DBD += streamSynApps.dbd
|
||||
PROD_LIBS += calc sscan
|
||||
PROD_LIBS_DEFAULT += streamSynApps
|
||||
endif
|
||||
|
||||
streamApp_DBD += stream.dbd
|
||||
|
||||
PROD_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
# Write StreamDevice debug output to this file
|
||||
CPPFLAGS += -DDEBUGFILE=StreamDebug.log
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
clean:: myclean
|
||||
|
||||
myclean:
|
||||
$(RM) core* StreamDebug.log
|
||||
|
||||
endif
|
||||
|
||||
|
8
streamApp/Makefile.Host
Normal file
8
streamApp/Makefile.Host
Normal file
@ -0,0 +1,8 @@
|
||||
TOP = ../../..
|
||||
|
||||
include $(TOP)/config/CONFIG_APP
|
||||
|
||||
DBDEXPAND = streamAppInclude-3-13.dbd
|
||||
DBDNAME = streamApp.dbd
|
||||
|
||||
include $(TOP)/config/RULES.Host
|
20
streamApp/Makefile.Vx
Normal file
20
streamApp/Makefile.Vx
Normal file
@ -0,0 +1,20 @@
|
||||
TOP = ../../..
|
||||
|
||||
include $(TOP)/config/CONFIG_APP
|
||||
|
||||
LIBNAME = streamApp
|
||||
|
||||
LDLIBS += $(COMPAT_BIN)/compatLib
|
||||
LDLIBS += $(ASYN_BIN)/asynLib
|
||||
LDLIBS += $(INSTALL_BIN)/streamLib
|
||||
|
||||
include ../base-3-13LIBOBJS
|
||||
|
||||
# Write StreamDevice debug output to this file
|
||||
CPPFLAGS += -DDEBUGFILE=StreamDebug.log
|
||||
|
||||
include $(TOP)/config/RULES.Vx
|
||||
include $(TOP)/config/RULES.munch
|
||||
|
||||
# Rebuild when LIBOBJS change
|
||||
$(LIBNAME): ../base-3-13LIBOBJS
|
242
streamApp/base-3-13.dbd
Normal file
242
streamApp/base-3-13.dbd
Normal file
@ -0,0 +1,242 @@
|
||||
include "menuGlobal.dbd"
|
||||
include "menuConvert.dbd"
|
||||
include "aiRecord.dbd"
|
||||
include "aaiRecord.dbd"
|
||||
include "aoRecord.dbd"
|
||||
include "aaoRecord.dbd"
|
||||
include "biRecord.dbd"
|
||||
include "boRecord.dbd"
|
||||
include "calcRecord.dbd"
|
||||
include "calcoutRecord.dbd"
|
||||
include "compressRecord.dbd"
|
||||
include "dfanoutRecord.dbd"
|
||||
#include "egRecord.dbd"
|
||||
#include "egeventRecord.dbd"
|
||||
#include "erRecord.dbd"
|
||||
#include "ereventRecord.dbd"
|
||||
include "eventRecord.dbd"
|
||||
include "fanoutRecord.dbd"
|
||||
#include "histogramRecord.dbd"
|
||||
include "longinRecord.dbd"
|
||||
include "longoutRecord.dbd"
|
||||
include "mbbiRecord.dbd"
|
||||
include "mbbiDirectRecord.dbd"
|
||||
include "mbboRecord.dbd"
|
||||
include "mbboDirectRecord.dbd"
|
||||
include "permissiveRecord.dbd"
|
||||
#include "pidRecord.dbd"
|
||||
#include "pulseCounterRecord.dbd"
|
||||
#include "pulseDelayRecord.dbd"
|
||||
#include "pulseTrainRecord.dbd"
|
||||
#include "scanRecord.dbd"
|
||||
include "selRecord.dbd"
|
||||
include "seqRecord.dbd"
|
||||
include "stateRecord.dbd"
|
||||
#include "steppermotorRecord.dbd"
|
||||
include "stringinRecord.dbd"
|
||||
include "stringoutRecord.dbd"
|
||||
include "subRecord.dbd"
|
||||
#include "gsubRecord.dbd"
|
||||
#include "palRecord.dbd"
|
||||
include "subArrayRecord.dbd"
|
||||
#include "timerRecord.dbd"
|
||||
#include "waitRecord.dbd"
|
||||
include "waveformRecord.dbd"
|
||||
device(ai,CONSTANT,devAiSoft,"Soft Channel")
|
||||
device(ai,CONSTANT,devAiSoftRaw,"Raw Soft Channel")
|
||||
#device(ai,VME_IO,devAiXy566Se,"XYCOM-566 SE Scanned")
|
||||
#device(ai,VME_IO,devAiXy566Di,"XYCOM-566 Dif Scanned")
|
||||
#device(ai,VME_IO,devAiXy566DiL,"XYCOM-566 Dif Latched")
|
||||
#device(ai,VME_IO,devAiDvx2502,"DVX-2502")
|
||||
#device(ai,CONSTANT,devAiTestAsyn,"Test Asyn")
|
||||
#device(ai,AB_IO,devAiAb1771Il,"AB-1771IL-Analog In")
|
||||
#device(ai,AB_IO,devAiAb1771Ife,"AB-1771IFE")
|
||||
#device(ai,AB_IO,devAiAb1771Ixe,"AB-1771IXE-Millivolt In")
|
||||
#device(ai,AB_IO,devAiAb1771IfeSe,"AB-1771IFE-SE")
|
||||
#device(ai,AB_IO,devAiAb1771IfeMa,"AB-1771IFE-4to20MA")
|
||||
#device(ai,AB_IO,devAiAb1771Ife0to5V,"AB-1771IFE-0to5Volt")
|
||||
#device(ai,AB_IO,devAiAb1771IrPlatinum,"AB-1771RTD-Platinum")
|
||||
#device(ai,AB_IO,devAiAb1771IrCopper,"AB-1771RTD-Copper")
|
||||
#device(ai,CAMAC_IO,devAiCamac,"Camac")
|
||||
#device(ai,VME_IO,devAiAt5Vxi,"VXI-AT5-AI")
|
||||
#device(ai,GPIB_IO,devAiK486Gpib,"Keithley-486")
|
||||
#device(ai,VME_IO,devAiKscV215,"KSC-V215")
|
||||
#device(ai,INST_IO,devAiVXStats,"VX stats")
|
||||
#device(aai,CAMAC_IO,devAaiCamac,"Camac")
|
||||
device(ao,CONSTANT,devAoSoft,"Soft Channel")
|
||||
device(ao,CONSTANT,devAoSoftRaw,"Raw Soft Channel")
|
||||
#device(ao,VME_IO,devAoVmiVme4100,"VMIVME-4100")
|
||||
#device(ao,CONSTANT,devAoTestAsyn,"Test Asyn")
|
||||
#device(ao,AB_IO,devAoAb1771Ofe,"AB-1771OFE")
|
||||
#device(ao,CAMAC_IO,devAoCamac,"Camac")
|
||||
#device(ao,VME_IO,devAoAt5Vxi,"VXI-AT5-AO")
|
||||
#device(ao,INST_IO,devAoVXStats,"VX stats")
|
||||
device(bi,CONSTANT,devBiSoft,"Soft Channel")
|
||||
device(bi,CONSTANT,devBiSoftRaw,"Raw Soft Channel")
|
||||
#device(bi,VME_IO,devBiMpv910,"MPV-910")
|
||||
#device(bi,VME_IO,devBiXVme210,"XVME-210")
|
||||
#device(bi,CONSTANT,devBiTestAsyn,"Test Asyn")
|
||||
#device(bi,AB_IO,devBiAb,"AB-Binary Input")
|
||||
#device(bi,AB_IO,devBiAb16,"AB-16 bit BI")
|
||||
#device(bi,AB_IO,devBiAb32,"AB-32 bit BI")
|
||||
#device(bi,CAMAC_IO,devBiCamac,"Camac")
|
||||
#device(bi,VME_IO,devBiAt5Vxi,"VXI-AT5-BI")
|
||||
#device(bi,VME_IO,devBiXy240,"XYCOM-240")
|
||||
#device(bi,VME_IO,devBiHpe1368a,"VXI-HPE1368-VS")
|
||||
#device(bi,VME_IO,devBiAt8Fp,"AT8-FP10S")
|
||||
#device(bi,VME_IO,devBiAvme9440,"AVME9440 I")
|
||||
device(bo,CONSTANT,devBoSoft,"Soft Channel")
|
||||
device(bo,CONSTANT,devBoSoftRaw,"Raw Soft Channel")
|
||||
#device(bo,VME_IO,devBoMpv902,"MPV-902")
|
||||
#device(bo,VME_IO,devBoXVme220,"XVME-220")
|
||||
#device(bo,CONSTANT,devBoTestAsyn,"Test Asyn")
|
||||
#device(bo,AB_IO,devBoAb,"AB-Binary Output")
|
||||
#device(bo,AB_IO,devBoAb16,"AB-16 bit BO")
|
||||
#device(bo,AB_IO,devBoAb32,"AB-32 bit BO")
|
||||
#device(bo,CAMAC_IO,devBoCamac,"Camac")
|
||||
#device(bo,VME_IO,devBoAt5Vxi,"VXI-AT5-BO")
|
||||
#device(bo,GPIB_IO,devBoK486Gpib,"Keithley-486")
|
||||
#device(bo,VME_IO,devBoXy240,"XYCOM-240")
|
||||
#device(bo,VME_IO,devBoHpe1368a,"VXI-HPE1368-VS")
|
||||
#device(bo,VME_IO,devBoAt8Fp,"AT8-FP10S")
|
||||
#device(bo,VME_IO,devBoAvme9440,"AVME9440 O")
|
||||
device(event,CONSTANT,devEventSoft,"Soft Channel")
|
||||
#device(event,VME_IO,devEventMz8310,"Mizar-8310")
|
||||
#device(event,CONSTANT,devEventTestIoEvent,"Test IoEvent")
|
||||
#device(event,VME_IO,devErEpicsEvent,"APS event receiver")
|
||||
#device(histogram,CONSTANT,devHistogramSoft,"Soft Channel")
|
||||
#device(histogram,CONSTANT,devHistogramTestAsyn,"Test Asyn")
|
||||
device(longin,CONSTANT,devLiSoft,"Soft Channel")
|
||||
#device(longin,CAMAC_IO,devLiCamac,"Camac")
|
||||
#device(longin,INST_IO,devLiVXStats,"VX stats")
|
||||
device(longout,CONSTANT,devLoSoft,"Soft Channel")
|
||||
#device(longout,CAMAC_IO,devLoCamac,"Camac")
|
||||
device(mbbi,CONSTANT,devMbbiSoft,"Soft Channel")
|
||||
device(mbbi,CONSTANT,devMbbiSoftRaw,"Raw Soft Channel")
|
||||
#device(mbbi,VME_IO,devMbbiMpv910,"MPV-910")
|
||||
#device(mbbi,VME_IO,devMbbiXVme210,"XVME-210")
|
||||
#device(mbbi,CONSTANT,devMbbiTestAsyn,"Test Asyn")
|
||||
#device(mbbi,AB_IO,devMbbiAb,"AB-Binary Input")
|
||||
#device(mbbi,AB_IO,devMbbiAb16,"AB-16 bit BI")
|
||||
#device(mbbi,AB_IO,devMbbiAb32,"AB-32 bit BI")
|
||||
#device(mbbi,AB_IO,devMbbiAbAdapterStat,"AB-Adapter Status")
|
||||
#device(mbbi,AB_IO,devMbbiAbCardStat,"AB-Card Status")
|
||||
#device(mbbi,CAMAC_IO,devMbbiCamac,"Camac")
|
||||
#device(mbbi,VME_IO,devMbbiAt5Vxi,"VXI-AT5-BI")
|
||||
#device(mbbi,VME_IO,devMbbiXy240,"XYCOM-240")
|
||||
#device(mbbi,VME_IO,devMbbiHpe1368a,"VXI-HPE1368-VS")
|
||||
#device(mbbi,VME_IO,devMbbiAt8Fp,"AT8-FP10S")
|
||||
#device(mbbi,VME_IO,devMbbiAvme9440,"AVME9440 I")
|
||||
device(mbbiDirect,CONSTANT,devMbbiDirectSoft,"Soft Channel")
|
||||
device(mbbiDirect,CONSTANT,devMbbiDirectSoftRaw,"Raw Soft Channel")
|
||||
#device(mbbiDirect,VME_IO,devMbbiDirectMpv910,"MPV-910")
|
||||
#device(mbbiDirect,VME_IO,devMbbiDirectXVme210,"XVME-210")
|
||||
#device(mbbiDirect,AB_IO,devMbbiDirectAb,"AB-Binary Input")
|
||||
#device(mbbiDirect,AB_IO,devMbbiDirectAb16,"AB-16 bit BI")
|
||||
#device(mbbiDirect,AB_IO,devMbbiDirectAb32,"AB-32 bit BI")
|
||||
#device(mbbiDirect,CAMAC_IO,devMbbiDirectCamac,"Camac")
|
||||
#device(mbbiDirect,VME_IO,devMbbiDirectAt5Vxi,"VXI-AT5-BI")
|
||||
device(mbbo,CONSTANT,devMbboSoft,"Soft Channel")
|
||||
device(mbbo,CONSTANT,devMbboSoftRaw,"Raw Soft Channel")
|
||||
#device(mbbo,VME_IO,devMbboMpv902,"MPV-902")
|
||||
#device(mbbo,VME_IO,devMbboXVme220,"XVME-220")
|
||||
#device(mbbo,CONSTANT,devMbboTestAsyn,"Test Asyn")
|
||||
#device(mbbo,AB_IO,devMbboAb,"AB-Binary Output")
|
||||
#device(mbbo,AB_IO,devMbboAb16,"AB-16 bit BO")
|
||||
#device(mbbo,AB_IO,devMbboAb32,"AB-32 bit BO")
|
||||
#device(mbbo,VME_IO,devMbboAt5Vxi,"VXI-AT5-BO")
|
||||
#device(mbbo,GPIB_IO,devMbboK486Gpib,"Keithley-486")
|
||||
#device(mbbo,VME_IO,devMbboXy240,"XYCOM-240")
|
||||
#device(mbbo,VME_IO,devMbboHpe1368a,"VXI-HPE1368-VS")
|
||||
#device(mbbo,VME_IO,devMbboAt8Fp,"AT8-FP10S")
|
||||
#device(mbbo,VME_IO,devMbboAvme9440,"AVME9440 O")
|
||||
device(mbboDirect,CONSTANT,devMbboDirectSoft,"Soft Channel")
|
||||
device(mbboDirect,CONSTANT,devMbboDirectSoftRaw,"Raw Soft Channel")
|
||||
#device(mbboDirect,VME_IO,devMbboDirectMpv902,"MPV-902")
|
||||
#device(mbboDirect,VME_IO,devMbboDirectXVme220,"XVME-220")
|
||||
#device(mbboDirect,AB_IO,devMbboDirectAb,"AB-Binary Output")
|
||||
#device(mbboDirect,AB_IO,devMbboDirectAb16,"AB-16 bit BO")
|
||||
#device(mbboDirect,AB_IO,devMbboDirectAb32,"AB-32 bit BO")
|
||||
#device(mbboDirect,CAMAC_IO,devMbboDirectCamac,"Camac")
|
||||
#device(mbboDirect,VME_IO,devMbboDirectAt5Vxi,"VXI-AT5-BO")
|
||||
#device(pulseCounter,VME_IO,devPcMz8310,"Mizar-8310")
|
||||
#device(pulseDelay,VME_IO,devPdMz8310,"Mizar-8310")
|
||||
#device(pulseTrain,CONSTANT,devPtSoft,"Soft Channel")
|
||||
#device(pulseTrain,VME_IO,devPtMz8310,"Mizar-8310")
|
||||
#device(steppermotor,VME_IO,devSmCompumotor1830,"Compumotor 1830")
|
||||
#device(steppermotor,VME_IO,devSmOms6Axis,"OMS 6-Axis")
|
||||
#device(steppermotor,AB_IO,devSmAB1746Hstp1,"Allen Bradley 1746-HTSP1")
|
||||
device(stringin,CONSTANT,devSiSoft,"Soft Channel")
|
||||
#device(stringin,CONSTANT,devSiTestAsyn,"Test Asyn")
|
||||
device(stringout,CONSTANT,devSoSoft,"Soft Channel")
|
||||
#device(stringout,CONSTANT,devSoTestAsyn,"Test Asyn")
|
||||
device(subArray,CONSTANT,devSASoft,"Soft Channel")
|
||||
#device(timer,VME_IO,devTmMizar8310,"Mizar-8310")
|
||||
#device(timer,VME_IO,devTmDg535,"DG 535")
|
||||
#device(timer,VME_IO,devTmAt5Vxi,"VXI-AT5-TIME")
|
||||
device(waveform,CONSTANT,devWfSoft,"Soft Channel")
|
||||
#device(waveform,VME_IO,devWfXy566Sc,"XYCOM-566 Single Channel")
|
||||
#device(waveform,VME_IO,devWfComet,"Comet Digitizer")
|
||||
#device(waveform,VME_IO,devWfJoergerVtr1,"Joerger Digitizer")
|
||||
#device(waveform,CONSTANT,devWfTestAsyn,"Test Asyn")
|
||||
#device(waveform,VME_IO,devWfDvx2502,"DVX-2502")
|
||||
#device(waveform,VME_IO,devWfPentek4261,"Pentek 4261")
|
||||
#device(waveform,CAMAC_IO,devWfCamac,"Camac")
|
||||
#device(waveform,VME_IO,devWfJoergerVtr1,"Joerger-VTR1")
|
||||
#device(waveform,VME_IO,devWfComet,"Omnibyte-COMET")
|
||||
#device(eg,VME_IO,devEg,"APS event generator G")
|
||||
#device(egevent,VME_IO,devEgEvent,"APS event generator E")
|
||||
#device(er,VME_IO,devEr,"APS event receiver")
|
||||
#device(erevent,VME_IO,devErevent,"APS event receiver")
|
||||
#device(wait,CONSTANT,devWaitIoEvent,"Soft Channel")
|
||||
#device(ai,INST_IO,devAiCan,"CANbus")
|
||||
#device(ao,INST_IO,devAoCan,"CANbus")
|
||||
#device(bi,INST_IO,devBiCan,"CANbus")
|
||||
#device(bo,INST_IO,devBoCan,"CANbus")
|
||||
#device(mbbi,INST_IO,devMbbiCan,"CANbus")
|
||||
#device(mbbo,INST_IO,devMbboCan,"CANbus")
|
||||
#device(mbbiDirect,INST_IO,devMbbiDirectCan,"CANbus")
|
||||
#device(mbboDirect,INST_IO,devMbboDirectCan,"CANbus")
|
||||
#device(bi,VME_IO,devBiVmic2534,"Vmic2534")
|
||||
#device(bo,VME_IO,devBoVmic2534,"Vmic2534")
|
||||
#device(mbbi,VME_IO,devMbbiVmic2534,"Vmic2534")
|
||||
#device(mbbo,VME_IO,devMbboVmic2534,"Vmic2534")
|
||||
|
||||
#include "symb.dbd"
|
||||
|
||||
#device(ai,AB_IO,devAiAbSlcDcm,"AB-SLC500DCM")
|
||||
#device(ai,AB_IO,devAiAbSlcDcmSigned,"AB-SLC500DCM-Signed")
|
||||
#device(ao,AB_IO,devAoAbSlcDcm,"AB-SLC500DCM")
|
||||
#device(longin,AB_IO,devLiAbSlcDcm,"AB-SLC500DCM")
|
||||
#device(longout,AB_IO,devLoAbSlcDcm,"AB-SLC500DCM")
|
||||
|
||||
#driver(drvXy010)
|
||||
#driver(drvVxi)
|
||||
#driver(drvGpib)
|
||||
#driver(drvBitBus)
|
||||
#driver(drvBb910)
|
||||
#driver(drvXy210)
|
||||
#driver(drvBb902)
|
||||
#driver(drvXy220)
|
||||
#driver(drvXy566)
|
||||
#driver(drvDvx)
|
||||
#driver(drvVmi4100)
|
||||
#driver(drvAb)
|
||||
#driver(drvAt5Vxi)
|
||||
#driver(drvCompuSm)
|
||||
#driver(drvOms)
|
||||
#driver(drvMz8310)
|
||||
#driver(drvHpe1368a)
|
||||
#driver(drvXy240)
|
||||
#driver(drvKscV215)
|
||||
#driver(drvComet)
|
||||
#driver(drvJgvtr1)
|
||||
#driver(drvFp)
|
||||
#driver(drvFpm)
|
||||
#driver(drvIpac)
|
||||
#driver(drvTip810)
|
||||
#driver(drvVmi2534)
|
||||
#include "bptTypeJdegC.dbd"
|
||||
#include "bptTypeJdegF.dbd"
|
||||
#include "bptTypeKdegC.dbd"
|
||||
#include "bptTypeKdegF.dbd"
|
216
streamApp/base-3-13LIBOBJS
Normal file
216
streamApp/base-3-13LIBOBJS
Normal file
@ -0,0 +1,216 @@
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/aaiRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/aaoRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/aiRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/aoRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/biRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/boRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/calcRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/calcoutRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/compressRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/dfanoutRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/egRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/egeventRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/erRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/ereventRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/eventRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/fanoutRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/gsubRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/histogramRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/longinRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/longoutRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/mbbiRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/mbbiDirectRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/mbboRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/mbboDirectRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/palRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/permissiveRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/pidRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/pulseCounterRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/pulseDelayRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/pulseTrainRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/scanRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/recWaitCa.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/recDynLink.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/recDynLinkTest.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/selRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/seqRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/stateRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/steppermotorRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/stringinRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/stringoutRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/subRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/subArrayRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/timerRecord.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/waitRecord.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/waveformRecord.o
|
||||
#
|
||||
# Device Support
|
||||
#
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAaiCamac.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAiCamac.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAiDvx2502.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAiKscV215.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devAiSoft.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devAiSoftRaw.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devVXStats.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devAiTestAsyn.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAiXy566Di.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAiXy566DiL.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAiXy566Se.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAaoCamac.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAoCamac.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devAoSoft.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devAoSoftRaw.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devAoTestAsyn.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAoVmiVme4100.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devApsEg.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devApsEr.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAt5Vxi.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAt8Fp.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAvme9440.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devBiCamac.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devBiMpv910.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devBiSoft.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devBiSoftRaw.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devBiTestAsyn.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devBiXVme210.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devBoCamac.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devBoMpv902.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devBoSoft.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devBoSoftRaw.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devBoTestAsyn.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devBoXVme220.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devCommonGpib.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devEventSoft.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devEventTestIoEvent.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devHistogramSoft.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devHistogramTestAsyn.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devHpe1368a.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devLiCamac.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devLiSoft.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devLoCamac.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devLoSoft.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbbiCamac.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbbiDirectCamac.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbbiDirectMpv910.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devMbbiDirectSoft.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devMbbiDirectSoftRaw.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbbiDirectXVme210.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbbiMpv910.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devMbbiSoft.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devMbbiSoftRaw.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devMbbiTestAsyn.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbbiXVme210.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbboCamac.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbboDirectCamac.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbboDirectMpv902.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devMbboDirectSoft.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devMbboDirectSoftRaw.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbboDirectXVme220.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbboMpv902.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devMbboSoft.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devMbboSoftRaw.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devMbboTestAsyn.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbboXVme220.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMz8310.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devPtSoft.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devSASoft.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devSiSoft.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devSiTestAsyn.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devSmCompumotor1830.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devSmOms6Axis.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devSoSoft.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devSoTestAsyn.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devTimerMz8310.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devWfCamac.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devWfComet.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devWfDvx2502.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devWfJoergerVtr1.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devWfSoft.o
|
||||
LIBOBJS += $(EPICS_BASE_BIN)/devWfTestAsyn.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devWfXy566Sc.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devWfPentek4261.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devXy240.o
|
||||
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAB1771IFE.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAB1771IL.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAB1771IR.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAB1771IXE.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAB1771OFE.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devABSLCDCM.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devABBINARY.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devABStatus.o
|
||||
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAiCan.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAoCan.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devBiCan.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devBoCan.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbbiCan.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbboCan.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbbiDirectCan.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devMbboDirectCan.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devVmic2534.o
|
||||
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/symb
|
||||
|
||||
#
|
||||
# Driver support ANSI
|
||||
#
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvAb.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvAt5Vxi.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvEpvxi.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvEpvxiMsg.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvHp1404a.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvHpe1368a.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvHpe1445a.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvKscV215.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvMz8310.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvStc.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvTime.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvCaenV265.o
|
||||
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvVipc310.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvVipc610.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvIpMv162.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvIpac.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvTip810.o
|
||||
#
|
||||
# Driver support NON ANSI
|
||||
#
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/module_types.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvBB232.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvBb902.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvBb910.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvBitBus.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvComet.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvCompuSm.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvDvx.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvFp.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvFpm.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvGpib.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvJgvtr1.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvMsg.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvOms.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvTranServ.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvVmi4100.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvXy010.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvXy210.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvXy220.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvXy240.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvXy566.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/drvVmic2534.o
|
||||
#
|
||||
#from src/devOpt
|
||||
#
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devAnalytekGpib.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devBBInteract.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devGpibInteract.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devK486Gpib.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devLibOpt.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devXxDc5009Gpib.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devXxDg535Gpib.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devXxK196Gpib.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devXxK263Gpib.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devXxSkeletonGpib.o
|
||||
#LIBOBJS += $(EPICS_BASE_BIN)/devXxSr620Gpib.o
|
||||
|
21
streamApp/example-3-13.cmd
Normal file
21
streamApp/example-3-13.cmd
Normal file
@ -0,0 +1,21 @@
|
||||
BIN="<library directory>"
|
||||
DBD="<dbd directory>"
|
||||
HOME="<ioc home direcory>"
|
||||
|
||||
#where can protocols be located?
|
||||
STREAM_PROTOCOL_PATH=".:protocols:../protocols/"
|
||||
|
||||
cd BIN
|
||||
ld < iocCore
|
||||
ld < streamApp.munch
|
||||
dbLoadDatabase "streamApp.dbd",DBD
|
||||
|
||||
drvAsynIPPortConfigure "terminal", "xxx.xxx.xxx.xxx:40000"
|
||||
|
||||
#load the records
|
||||
cd HOME
|
||||
dbLoadRecords "example.db","PREFIX=DZ"
|
||||
|
||||
#lots of debug output
|
||||
#streamDebug=1
|
||||
iocInit
|
38
streamApp/example.cmd
Normal file
38
streamApp/example.cmd
Normal file
@ -0,0 +1,38 @@
|
||||
dbLoadDatabase "O.Common/streamApp.dbd"
|
||||
streamApp_registerRecordDeviceDriver
|
||||
|
||||
#where can protocols be located?
|
||||
epicsEnvSet "STREAM_PROTOCOL_PATH", ".:protocols:../protocols/"
|
||||
|
||||
#setup the busses
|
||||
|
||||
#example serial port setup
|
||||
#drvAsynSerialPortConfigure "COM2", "/dev/ttyS1"
|
||||
#asynOctetSetInputEos "COM2",0,"\r\n"
|
||||
#asynOctetSetOutputEos "COM2",0,"\r\n"
|
||||
#asynSetOption ("COM2", 0, "baud", "9600")
|
||||
#asynSetOption ("COM2", 0, "bits", "8")
|
||||
#asynSetOption ("COM2", 0, "parity", "none")
|
||||
#asynSetOption ("COM2", 0, "stop", "1")
|
||||
#asynSetOption ("COM2", 0, "clocal", "Y")
|
||||
#asynSetOption ("COM2", 0, "crtscts", "N")
|
||||
|
||||
#example telnet style IP port setup
|
||||
drvAsynIPPortConfigure "terminal", "localhost:40000"
|
||||
asynOctetSetInputEos "terminal",0,"\r\n"
|
||||
asynOctetSetOutputEos "terminal",0,"\r\n"
|
||||
|
||||
#example VXI11 (GPIB via IP) port setup
|
||||
#vxi11Configure "GPIB","ins023",1,5.0,"hpib"
|
||||
|
||||
#load the records
|
||||
dbLoadRecords "example.db","PREFIX=DZ"
|
||||
#dbLoadRecords "scalcout.db","PREFIX=DZ"
|
||||
|
||||
#lots! of debug output
|
||||
#var streamDebug 1
|
||||
|
||||
iocInit
|
||||
|
||||
#enable debug output
|
||||
var streamDebug 1
|
170
streamApp/example.db
Normal file
170
streamApp/example.db
Normal file
@ -0,0 +1,170 @@
|
||||
# process this record to reload all stream protocols
|
||||
record (sub, "$(PREFIX):reload")
|
||||
{
|
||||
field (SNAM, "streamReload")
|
||||
}
|
||||
|
||||
# some scaling -10...10V <-> 0x0000...0xffff and back
|
||||
record (ao, "$(PREFIX):ao")
|
||||
{
|
||||
field (DESC, "An analog value")
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@example.proto set-ao terminal")
|
||||
field (PREC, "3")
|
||||
field (LINR, "LINEAR")
|
||||
field (ESLO, "0.000305180437934") # 20.0 / 0xffff
|
||||
field (EOFF, "-10")
|
||||
field (DRVL, "-10")
|
||||
field (DRVH, "10")
|
||||
field (EGU, "V")
|
||||
}
|
||||
|
||||
record (ai, "$(PREFIX):ai")
|
||||
{
|
||||
field (DESC, "An analog value")
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@example.proto ai terminal")
|
||||
field (PREC, "3")
|
||||
field (LINR, "LINEAR")
|
||||
field (ESLO, "0.000305180437934") # 20.0 / 0xffff
|
||||
field (EOFF, "-10")
|
||||
field (EGU, "V")
|
||||
}
|
||||
|
||||
# simple integer and binary i/o
|
||||
record (longout, "$(PREFIX):lo")
|
||||
{
|
||||
field (DESC, "An integer value")
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@example.proto lo terminal")
|
||||
}
|
||||
|
||||
record (longin, "$(PREFIX):li")
|
||||
{
|
||||
field (DESC, "An integer value")
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@example.proto li terminal")
|
||||
}
|
||||
|
||||
record (bo, "$(PREFIX):bo")
|
||||
{
|
||||
field (DESC, "A bit value")
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@example.proto bo terminal")
|
||||
field (MASK, "42")
|
||||
field (ZNAM, "OFF")
|
||||
field (ONAM, "ON")
|
||||
}
|
||||
|
||||
record (bi, "$(PREFIX):bi")
|
||||
{
|
||||
field (DESC, "A bit value")
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@example.proto bi terminal")
|
||||
field (ZNAM, "OFF")
|
||||
field (ONAM, "ON")
|
||||
}
|
||||
|
||||
# playing with enums
|
||||
record (mbbo, "$(PREFIX):mbbo")
|
||||
{
|
||||
field (DESC, "Print Enums")
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@example.proto enums terminal")
|
||||
field (ZRST, "A")
|
||||
field (ZRVL, "2")
|
||||
field (ONST, "B")
|
||||
field (ONVL, "3")
|
||||
field (TWST, "C")
|
||||
field (TWVL, "1")
|
||||
field (THST, "D")
|
||||
field (THVL, "0")
|
||||
}
|
||||
|
||||
record (stringout, "$(PREFIX):command")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@example.proto COMMAND terminal")
|
||||
}
|
||||
|
||||
record (stringin, "$(PREFIX):info")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@example.proto info terminal")
|
||||
}
|
||||
|
||||
# prints all available checksums
|
||||
record (stringout, "$(PREFIX):checksum")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@example.proto checksum terminal")
|
||||
}
|
||||
|
||||
# this record gets any (terminated) input line
|
||||
record (stringin, "$(PREFIX):spy")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@example.proto spy terminal")
|
||||
field (SCAN, "I/O Intr")
|
||||
field (FLNK, "$(PREFIX):log5")
|
||||
}
|
||||
|
||||
# these records log the last few input lines
|
||||
record (stringin, "$(PREFIX):log5")
|
||||
{
|
||||
field (INP, "$(PREFIX):log4")
|
||||
field (FLNK, "$(PREFIX):log4")
|
||||
}
|
||||
|
||||
record (stringin, "$(PREFIX):log4")
|
||||
{
|
||||
field (INP, "$(PREFIX):log3")
|
||||
field (FLNK, "$(PREFIX):log3")
|
||||
}
|
||||
|
||||
record (stringin, "$(PREFIX):log3")
|
||||
{
|
||||
field (INP, "$(PREFIX):log2")
|
||||
field (FLNK, "$(PREFIX):log2")
|
||||
}
|
||||
|
||||
record (stringin, "$(PREFIX):log2")
|
||||
{
|
||||
field (INP, "$(PREFIX):log1")
|
||||
field (FLNK, "$(PREFIX):log1")
|
||||
}
|
||||
|
||||
record (stringin, "$(PREFIX):log1")
|
||||
{
|
||||
field (INP, "$(PREFIX):spy")
|
||||
}
|
||||
|
||||
# caput to A,B,C or PROC to process this
|
||||
record (calcout, "$(PREFIX):calcout")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@example.proto calcout terminal")
|
||||
field (A, "3.1415")
|
||||
field (B, "15")
|
||||
field (C, "8")
|
||||
field (CALC, "0") # should be a valid expression
|
||||
field (DESC, "filename")
|
||||
}
|
||||
|
||||
# read a long string as a waveform of characteres
|
||||
record (waveform, "$(PREFIX):hugestring")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@example.proto char_wave_in terminal")
|
||||
field (FTVL, "CHAR")
|
||||
field (NELM, "1000")
|
||||
}
|
||||
|
||||
# write an array of strings
|
||||
record (waveform, "$(PREFIX):strings")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@example.proto string_wave_out terminal")
|
||||
field (FTVL, "STRING")
|
||||
field (NELM, "10")
|
||||
}
|
127
streamApp/example.proto
Normal file
127
streamApp/example.proto
Normal file
@ -0,0 +1,127 @@
|
||||
# example stream protocol file
|
||||
|
||||
Terminator = CR LF;
|
||||
ReplyTimeout = 10000; # 10 sec is very long, for keyboard input
|
||||
ReadTimeout = 1000; # also long for keyboard input
|
||||
|
||||
binary {
|
||||
out "%B\x00\xff";
|
||||
}
|
||||
|
||||
# note the field access
|
||||
ai {
|
||||
out "%(NAME)s [int] ? ";
|
||||
in "%i"; # read to RVAL and convert
|
||||
}
|
||||
|
||||
set-ao {
|
||||
out '%(NAME)s = %f %(EGU)s [0x%04x]';
|
||||
}
|
||||
|
||||
li {
|
||||
out "%(NAME)s [int] ? ";
|
||||
in "%i";
|
||||
}
|
||||
|
||||
lo {
|
||||
out '%(NAME)s = %i = %#x = %b(bin) = %D(BCD)';
|
||||
}
|
||||
|
||||
bi {
|
||||
out "%(NAME)s [0 or 1] ? ";
|
||||
in "%i";
|
||||
}
|
||||
|
||||
# using variables
|
||||
s0 = false;
|
||||
s1 = true;
|
||||
bo {
|
||||
out '%(NAME)s = %i = %{\${s0}|\${s1}} = "%s"';
|
||||
}
|
||||
|
||||
enums
|
||||
{
|
||||
out "%{choice0|choice1|choice2} %d %s";
|
||||
}
|
||||
|
||||
checksum {
|
||||
out "%s%<sum> sum";
|
||||
out "%s%<nsum> nsum";
|
||||
out "%s%<-sum> -sum";
|
||||
out "%s%<notsum> notsum";
|
||||
out "%s%<~sum> ~sum";
|
||||
out "%s%<xor> xor";
|
||||
out "%s%<crc8> crc8";
|
||||
out "%s%<ccitt8> ccitt8";
|
||||
out "%s%<sum16> sum16";
|
||||
out "%s%<crc16> crc16";
|
||||
out "%s%<crc16r> crc16r";
|
||||
out "%s%<ccitt16> ccitt16";
|
||||
out "%s%<ccitt16a> ccitt16 with augment";
|
||||
out "%s%<sum32> sum32";
|
||||
out "%s%<crc32> crc32";
|
||||
out "%s%<crc32r> crcr32";
|
||||
out "%s%<jamcrc> jamcrc";
|
||||
out "%s%<adler32> adler32";
|
||||
|
||||
out "%s%0<sum> sum (ASCII)";
|
||||
out "%s%0<nsum> nsum (ASCII)";
|
||||
out "%s%0<-sum> -sum (ASCII)";
|
||||
out "%s%0<notsum> notsum (ASCII)";
|
||||
out "%s%0<~sum> ~sum (ASCII)";
|
||||
out "%s%0<xor> xor (ASCII)";
|
||||
out "%s%0<crc8> crc8 (ASCII)";
|
||||
out "%s%0<ccitt8> ccitt8 (ASCII)";
|
||||
out "%s%0<sum16> sum16 (ASCII)";
|
||||
out "%s%0<crc16> crc16 (ASCII)";
|
||||
out "%s%0<crc16r> crc16r (ASCII)";
|
||||
out "%s%0<ccitt16> ccitt16 (ASCII)";
|
||||
out "%s%0<ccitt16a> ccitt16 with augment (ASCII)";
|
||||
out "%s%0<sum32> sum32 (ASCII)";
|
||||
out "%s%0<crc32> crc32 (ASCII)";
|
||||
out "%s%0<crc32r> crcr32 (ASCII)";
|
||||
out "%s%0<jamcrc> jamcrc (ASCII)";
|
||||
out "%s%0<adler32> adler32 (ASCII)";
|
||||
out "%s%0<hexsum8> hexsum8 (ASCII)";
|
||||
}
|
||||
|
||||
command {
|
||||
out "%s";
|
||||
}
|
||||
|
||||
info {
|
||||
out "%s";
|
||||
in "%39c";
|
||||
}
|
||||
|
||||
read {
|
||||
in "%39c";
|
||||
}
|
||||
|
||||
spy {
|
||||
extraInput=ignore;
|
||||
PollPeriod = 10;
|
||||
in "%39c";
|
||||
}
|
||||
|
||||
# accessing fields
|
||||
calcout {
|
||||
out "OVAL=%f A=%(A)f B=%(B)f C=%(C)f";
|
||||
}
|
||||
|
||||
scalcout {
|
||||
out "OVAL=%f SOV=%s A=%(A)f B=%(B)f AA=%(AA)s";
|
||||
}
|
||||
|
||||
# output an array of strings
|
||||
string_wave_out {
|
||||
separator = ", ";
|
||||
out "waveform %(NAME)s = (%s)";
|
||||
}
|
||||
|
||||
char_wave_in {
|
||||
outterminator = "";
|
||||
out CR LF "Enter String: ";
|
||||
in "%1000c";
|
||||
out 'Got: "%s"' CR LF;
|
||||
}
|
34
streamApp/regexp.README
Normal file
34
streamApp/regexp.README
Normal file
@ -0,0 +1,34 @@
|
||||
How to use regular expressions in StreamDevice.
|
||||
|
||||
First, you need the PCRE library.
|
||||
If it is already installed for your (Linux) system (try: rpm -ql pcre),
|
||||
set the following variables in your RELEASE file:
|
||||
PCRE_INCLUDE=<direcrory of pcre.h>
|
||||
PCRE_LIB=<direcrory of libpcre.so>
|
||||
|
||||
For vxWorks, Windows and others you're probably out of luck here.
|
||||
In that case, download the PCRE package from www.pcre.org and
|
||||
epics.web.psi.ch/software/streamdevice/pcre/Makefile and compile
|
||||
PCRE as an EPICS application. Use the variable PCRE in your RELEASE file
|
||||
to define the location of this application.
|
||||
|
||||
If either PCRE or PCRE_INCLUDE or PCRE_LIB are set in the RELEASE file,
|
||||
StreamDevice is automatically build with regular expression support.
|
||||
|
||||
The syntax is %/regexp/. It can only be used in input. It returns the
|
||||
next string that matches the regexp. Anything before this string is skipped.
|
||||
|
||||
To use sub-expressions use %.n/rexexp/ where n is a number from 1 to 9
|
||||
to match the n-th sub-expression.
|
||||
|
||||
It is possible to limit the input length to the match algorithm like
|
||||
%m/regexp/ where m is the maximal length.
|
||||
|
||||
Example:
|
||||
in "%100.1/<title>(.*)<\/title>/";
|
||||
This searches the next 100 bytes and returns the string bewteen
|
||||
<title> and </title>. Any input before <title> is skipped. Any input
|
||||
after </title> is left in the buffer (and can by matched by other formats).
|
||||
Note that the / in </title> must be escaped.
|
||||
|
||||
See regexp.cmd, regexp.proto, regexp.db for a working example.
|
10
streamApp/regexp.cmd
Normal file
10
streamApp/regexp.cmd
Normal file
@ -0,0 +1,10 @@
|
||||
dbLoadDatabase "O.Common/streamApp.dbd"
|
||||
streamApp_registerRecordDeviceDriver
|
||||
|
||||
# no autoconnect for web servers (see regexp.proto)
|
||||
drvAsynIPPortConfigure web epics.web.psi.ch:80 0 1
|
||||
|
||||
dbLoadRecords regexp.db
|
||||
|
||||
iocInit
|
||||
# var streamDebug 1
|
5
streamApp/regexp.db
Normal file
5
streamApp/regexp.db
Normal file
@ -0,0 +1,5 @@
|
||||
record (stringin, "DZ:regexp")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@regexp.proto readTitle web")
|
||||
}
|
18
streamApp/regexp.proto
Normal file
18
streamApp/regexp.proto
Normal file
@ -0,0 +1,18 @@
|
||||
# regular expression example
|
||||
# extract the title of from a web page
|
||||
|
||||
outterminator = NL;
|
||||
interminator = "</html>" NL; # terminators can have arbitrary length
|
||||
|
||||
# Web servers close the connection after sending a page.
|
||||
# Thus, we can't use autoconnect (see drvAsynIPPortConfigure)
|
||||
# Handle connection manually in protocol.
|
||||
|
||||
readTitle {
|
||||
extraInput=ignore;
|
||||
|
||||
connect 1000; # connect to server, 1 second timeout
|
||||
out "GET http://epics.web.psi.ch/"; # HTTP request
|
||||
in "%.1/<title>(.*)<\/title>/"; # get string in <title></title>
|
||||
disconnect; # servers closes, so do we.
|
||||
}
|
19
streamApp/simple.cmd
Normal file
19
streamApp/simple.cmd
Normal file
@ -0,0 +1,19 @@
|
||||
dbLoadDatabase "O.Common/streamApp.dbd"
|
||||
streamApp_registerRecordDeviceDriver
|
||||
|
||||
#where can protocols be located?
|
||||
epicsEnvSet "STREAM_PROTOCOL_PATH", ".:protocols:../protocols/"
|
||||
|
||||
#setup the busses
|
||||
|
||||
#drvAsynIPPortConfigure "L0", "localhost:40000"
|
||||
vxi11Configure "L0","gpib-dz-1",0,0.0,"gpib0",0,0
|
||||
|
||||
#load the records
|
||||
dbLoadRecords "simple.db","P=DZ,BUS=L0 28"
|
||||
|
||||
var streamDebug 1
|
||||
iocInit
|
||||
|
||||
#enable debug output
|
||||
var streamDebug 1
|
15
streamApp/simple.db
Normal file
15
streamApp/simple.db
Normal file
@ -0,0 +1,15 @@
|
||||
record (stringout, "$(P):cmd")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@simple.proto cmd $(BUS)")
|
||||
}
|
||||
record (stringout, "$(P):info")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@simple.proto info $(BUS)")
|
||||
}
|
||||
record (stringin, "$(P):read")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@simple.proto read $(BUS)")
|
||||
}
|
13
streamApp/simple.proto
Normal file
13
streamApp/simple.proto
Normal file
@ -0,0 +1,13 @@
|
||||
terminator = CR LF;
|
||||
|
||||
cmd {
|
||||
out "%s";
|
||||
}
|
||||
info {
|
||||
extrainput=ignore;
|
||||
out "%s";
|
||||
in "%39c";
|
||||
}
|
||||
read {
|
||||
in "%39c";
|
||||
}
|
3
streamApp/streamAppInclude-3-13.dbd
Normal file
3
streamApp/streamAppInclude-3-13.dbd
Normal file
@ -0,0 +1,3 @@
|
||||
include "base-3-13.dbd"
|
||||
include "asyn.dbd"
|
||||
include "stream.dbd"
|
37
streamApp/streamAppMain.cc
Normal file
37
streamApp/streamAppMain.cc
Normal file
@ -0,0 +1,37 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is an example application initializer for StreamDevice. *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
|
||||
#include <epicsThread.h>
|
||||
#include <iocsh.h>
|
||||
#include <devStream.h>
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
#ifdef DEBUGFILE
|
||||
#define STR2(x) #x
|
||||
#define STR(x) STR2(x)
|
||||
StreamDebugFile = fopen(STR(DEBUGFILE), "w");
|
||||
#endif
|
||||
if(argc>=2) {
|
||||
iocsh(argv[1]);
|
||||
epicsThreadSleep(.2);
|
||||
}
|
||||
iocsh(NULL);
|
||||
return(0);
|
||||
}
|
195
streamApp/terminal.tcl
Executable file
195
streamApp/terminal.tcl
Executable file
@ -0,0 +1,195 @@
|
||||
#!/usr/bin/env wish
|
||||
|
||||
wm iconify .
|
||||
|
||||
proc createTerm {sock} {
|
||||
global socket port
|
||||
toplevel .$sock
|
||||
text .$sock.t -yscrollcommand ".$sock.v set"
|
||||
scrollbar .$sock.v -command ".$sock.t yview"
|
||||
.$sock.t tag configure output -foreground red
|
||||
.$sock.t tag configure input -foreground darkgreen
|
||||
grid rowconfigure .$sock 0 -weight 1
|
||||
grid columnconfigure .$sock 0 -weight 1
|
||||
grid .$sock.t .$sock.v -sticky nsew
|
||||
bind .$sock.t <Destroy> "close $sock; unset socket(.$sock.t)"
|
||||
bind .$sock.t <F1> "%W delete 0.1 end"
|
||||
set socket(.$sock.t) $sock
|
||||
focus .$sock.t
|
||||
wm title .$sock "port $port <-> [fconfigure $sock -peername]"
|
||||
}
|
||||
|
||||
set port [lindex $argv 0]
|
||||
if {$port == ""} { set port 40000 }
|
||||
if [catch {
|
||||
socket -server connect $port
|
||||
} msg ] {
|
||||
return -code error "$msg (port $port)"
|
||||
}
|
||||
|
||||
proc connect {sock addr port} {
|
||||
fconfigure $sock -blocking 0 -buffering none
|
||||
createTerm $sock
|
||||
fileevent $sock readable "receiveHandler $sock"
|
||||
}
|
||||
|
||||
proc escape {string} {
|
||||
while {![string is print -failindex index $string]} {
|
||||
set char [string index $string $index]
|
||||
scan $char "%c" code
|
||||
switch $char {
|
||||
"\r" { set escaped "\\r" }
|
||||
"\n" { set escaped "\\n" }
|
||||
"\a" { set escaped "\\a" }
|
||||
"\t" { set escaped "\\t" }
|
||||
default { set escaped [format "<%02x>" $code] }
|
||||
}
|
||||
set string [string replace $string $index $index $escaped]
|
||||
}
|
||||
return $string
|
||||
}
|
||||
|
||||
proc sendReply {sock text} {
|
||||
.$sock.t mark set insert end
|
||||
.$sock.t insert end $text
|
||||
.$sock.t see end
|
||||
puts -nonewline $sock $text
|
||||
# puts "sending \"[escape $text]\"\n"
|
||||
}
|
||||
|
||||
proc checkNum {n} {
|
||||
if {[string is integer $n] && $n >= 0} {return $n}
|
||||
return -code error "argument $n must be a positive number"
|
||||
}
|
||||
|
||||
proc receiveHandler {sock} {
|
||||
set a [read $sock]
|
||||
if [eof $sock] {
|
||||
destroy .$sock
|
||||
return
|
||||
}
|
||||
.$sock.t mark set insert end
|
||||
.$sock.t insert end $a output
|
||||
.$sock.t see end
|
||||
set l [split $a]
|
||||
if [catch {
|
||||
switch -- [lindex $l 0] {
|
||||
"disconnect" {
|
||||
sendReply $sock [string range $a 11 end]
|
||||
destroy .$sock
|
||||
}
|
||||
"echo" {
|
||||
sendReply $sock [string range $a 5 end]
|
||||
}
|
||||
"longmsg" {
|
||||
set length [checkNum [lindex $l 1]]
|
||||
sendReply $sock "[string range x[string repeat 0123456789abcdefghijklmnopqrstuvwxyz [expr $length / 36 + 1]] 1 $length]\n"
|
||||
}
|
||||
"wait" {
|
||||
set wait [checkNum [lindex $l 1]]
|
||||
after $wait [list sendReply $sock "Done\n"]
|
||||
}
|
||||
"start" {
|
||||
set wait [checkNum [lindex $l 1]]
|
||||
set ::counter 0
|
||||
after $wait sendAsync $wait [list [lindex $l 2]]
|
||||
sendReply $sock "Started\n"
|
||||
}
|
||||
"stop" {
|
||||
set ::counter -1
|
||||
sendReply $sock "Stopped\n"
|
||||
}
|
||||
"set" {
|
||||
set ::values([lindex $a 1]) [lrange $l 2 end-1]
|
||||
sendReply $sock "Ok\n"
|
||||
}
|
||||
"get" {
|
||||
if [info exists ::values([lindex $l 1])] {
|
||||
sendReply $sock "[lindex $l 1] $::values([lindex $l 1])\n"
|
||||
} else {
|
||||
sendReply $sock "ERROR: [lindex $l 1] not found\n"
|
||||
}
|
||||
}
|
||||
"help" {
|
||||
sendReply $sock "help this text\n"
|
||||
sendReply $sock "echo string reply string\n"
|
||||
sendReply $sock "wait msec reply Done after some time\n"
|
||||
sendReply $sock "start msec start sending messages priodically\n"
|
||||
sendReply $sock "stop stop sending messages\n"
|
||||
sendReply $sock "set key value set a value\n"
|
||||
sendReply $sock "get key reply value\n"
|
||||
sendReply $sock "disconnect close connection\n"
|
||||
}
|
||||
}
|
||||
} msg] {
|
||||
sendReply $sock "ERROR: $msg\n"
|
||||
puts stderr $::errorInfo
|
||||
}
|
||||
}
|
||||
|
||||
proc sendAsync {wait message} {
|
||||
if {$::counter < 0} return
|
||||
foreach term [array names ::socket] {
|
||||
sendReply $::socket($term) "Message number [incr ::counter] $message\n";
|
||||
}
|
||||
after $wait sendAsync $wait [list $message]
|
||||
}
|
||||
|
||||
if {[info proc tkTextInsert] != ""} {
|
||||
set insert tkTextInsert
|
||||
set paste tkTextPaste
|
||||
set pastesel tkPasteSelection
|
||||
} else {
|
||||
set insert tk::TextInsert
|
||||
set paste tk_textPaste
|
||||
set pastesel ::tk::TextPasteSelection
|
||||
}
|
||||
|
||||
rename $insert tkTextInsert_org
|
||||
rename $paste tkTextPaste_org
|
||||
rename $pastesel tkTextPasteSel_org
|
||||
|
||||
proc $insert {w s} {
|
||||
puts [list insert $w $s]
|
||||
global socket
|
||||
if {[string equal $s ""] || [string equal [$w cget -state] "disabled"]} {
|
||||
return
|
||||
}
|
||||
sendReply $socket($w) $s
|
||||
}
|
||||
|
||||
proc $paste {w x y} {
|
||||
puts [list paste $w $s]
|
||||
global insert
|
||||
set s [selection get -displayof $w]
|
||||
$insert $w $s
|
||||
}
|
||||
|
||||
proc $pastesel {w x y} {
|
||||
global insert
|
||||
$w mark set insert [TextClosestGap $w $x $y]
|
||||
if {![catch {::tk::GetSelection $w PRIMARY} sel]} {
|
||||
set oldSeparator [$w cget -autoseparators]
|
||||
if {$oldSeparator} {
|
||||
$w configure -autoseparators 0
|
||||
$w edit separator
|
||||
}
|
||||
$insert $w $sel
|
||||
if {$oldSeparator} {
|
||||
$w edit separator
|
||||
$w configure -autoseparators 1
|
||||
}
|
||||
}
|
||||
if {[$w cget -state] eq "normal"} {focus $w}
|
||||
}
|
||||
|
||||
#remove bindings on Control-<letter>
|
||||
for {set ascii 0x61} {$ascii <= 0x7a} {incr ascii} {
|
||||
bind Text <Control-[format %c $ascii]> ""
|
||||
}
|
||||
#remove bindings on symbolic tags
|
||||
foreach tag {Clear Paste Copy Cut } {
|
||||
bind Text <<$tag>> ""
|
||||
}
|
||||
|
||||
bind Text <Control-Key> [list $insert %W %A]
|
900
streamApp/test.adl
Normal file
900
streamApp/test.adl
Normal file
@ -0,0 +1,900 @@
|
||||
|
||||
file {
|
||||
name="/afs/psi.ch/user/z/zimoch/top/StreamDevice-2/streamApp/test.adl"
|
||||
version=030100
|
||||
}
|
||||
display {
|
||||
object {
|
||||
x=261
|
||||
y=341
|
||||
width=552
|
||||
height=362
|
||||
}
|
||||
clr=14
|
||||
bclr=50
|
||||
cmap=""
|
||||
gridSpacing=5
|
||||
gridOn=1
|
||||
snapToGrid=1
|
||||
}
|
||||
"color map" {
|
||||
ncolors=65
|
||||
colors {
|
||||
ffffff,
|
||||
ececec,
|
||||
dadada,
|
||||
c8c8c8,
|
||||
bbbbbb,
|
||||
aeaeae,
|
||||
9e9e9e,
|
||||
919191,
|
||||
858585,
|
||||
787878,
|
||||
696969,
|
||||
5a5a5a,
|
||||
464646,
|
||||
2d2d2d,
|
||||
000000,
|
||||
00d800,
|
||||
1ebb00,
|
||||
339900,
|
||||
2d7f00,
|
||||
216c00,
|
||||
fd0000,
|
||||
de1309,
|
||||
be190b,
|
||||
a01207,
|
||||
820400,
|
||||
5893ff,
|
||||
597ee1,
|
||||
4b6ec7,
|
||||
3a5eab,
|
||||
27548d,
|
||||
fbf34a,
|
||||
f9da3c,
|
||||
eeb62b,
|
||||
e19015,
|
||||
cd6100,
|
||||
ffb0ff,
|
||||
d67fe2,
|
||||
ae4ebc,
|
||||
8b1a96,
|
||||
610a75,
|
||||
a4aaff,
|
||||
8793e2,
|
||||
6a73c1,
|
||||
4d52a4,
|
||||
343386,
|
||||
c7bb6d,
|
||||
b79d5c,
|
||||
a47e3c,
|
||||
7d5627,
|
||||
58340f,
|
||||
99ffff,
|
||||
73dfff,
|
||||
4ea5f9,
|
||||
2a63e4,
|
||||
0a00b8,
|
||||
ebf1b5,
|
||||
d4db9d,
|
||||
bbc187,
|
||||
a6a462,
|
||||
8b8239,
|
||||
73ff6b,
|
||||
52da3b,
|
||||
3cb420,
|
||||
289315,
|
||||
1a7309,
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=105
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log9"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=115
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log8"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=125
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log7"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=135
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log6"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=145
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log5"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=155
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log4"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=165
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log3"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=175
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log2"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=185
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log1"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=195
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log0"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text entry" {
|
||||
object {
|
||||
x=50
|
||||
y=265
|
||||
width=390
|
||||
height=20
|
||||
}
|
||||
control {
|
||||
chan="$(P):cmd"
|
||||
clr=14
|
||||
bclr=12
|
||||
}
|
||||
clrmod="alarm"
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=215
|
||||
width=390
|
||||
height=14
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):spy"
|
||||
clr=14
|
||||
bclr=12
|
||||
}
|
||||
clrmod="alarm"
|
||||
limits {
|
||||
}
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=105
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log9"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=115
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log8"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=125
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log7"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=135
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log6"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=145
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log5"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=155
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log4"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=165
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log3"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=175
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log2"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=185
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log1"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=195
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log0"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=215
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="spy"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=270
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="cmd"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=295
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="info"
|
||||
}
|
||||
"text entry" {
|
||||
object {
|
||||
x=50
|
||||
y=290
|
||||
width=390
|
||||
height=20
|
||||
}
|
||||
control {
|
||||
chan="$(P):info"
|
||||
clr=14
|
||||
bclr=12
|
||||
}
|
||||
clrmod="alarm"
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=235
|
||||
width=390
|
||||
height=14
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):spybin"
|
||||
clr=14
|
||||
bclr=12
|
||||
}
|
||||
clrmod="alarm"
|
||||
format="string"
|
||||
limits {
|
||||
}
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=235
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="spybin"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=320
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="request"
|
||||
}
|
||||
"text entry" {
|
||||
object {
|
||||
x=50
|
||||
y=315
|
||||
width=390
|
||||
height=20
|
||||
}
|
||||
control {
|
||||
chan="$(P):request"
|
||||
clr=14
|
||||
bclr=12
|
||||
}
|
||||
clrmod="alarm"
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=340
|
||||
width=390
|
||||
height=14
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):reply"
|
||||
clr=14
|
||||
bclr=12
|
||||
}
|
||||
clrmod="alarm"
|
||||
limits {
|
||||
}
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=340
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="reply"
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=445
|
||||
y=340
|
||||
width=100
|
||||
height=15
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):reply.STAT"
|
||||
clr=14
|
||||
bclr=12
|
||||
}
|
||||
clrmod="alarm"
|
||||
format="string"
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=445
|
||||
y=315
|
||||
width=100
|
||||
height=15
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):request.STAT"
|
||||
clr=14
|
||||
bclr=12
|
||||
}
|
||||
clrmod="alarm"
|
||||
format="string"
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=445
|
||||
y=290
|
||||
width=100
|
||||
height=15
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):info.STAT"
|
||||
clr=14
|
||||
bclr=12
|
||||
}
|
||||
clrmod="alarm"
|
||||
format="string"
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=445
|
||||
y=265
|
||||
width=100
|
||||
height=15
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):cmd.STAT"
|
||||
clr=14
|
||||
bclr=12
|
||||
}
|
||||
clrmod="alarm"
|
||||
format="string"
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=445
|
||||
y=235
|
||||
width=100
|
||||
height=15
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):spybin.STAT"
|
||||
clr=14
|
||||
bclr=12
|
||||
}
|
||||
clrmod="alarm"
|
||||
format="string"
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=445
|
||||
y=215
|
||||
width=100
|
||||
height=15
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):spy.STAT"
|
||||
clr=14
|
||||
bclr=12
|
||||
}
|
||||
clrmod="alarm"
|
||||
format="string"
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=5
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log19"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=15
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log18"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=25
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log17"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=35
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log16"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=45
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log15"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=55
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log14"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=65
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log13"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=75
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log12"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=85
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log11"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
"text update" {
|
||||
object {
|
||||
x=50
|
||||
y=95
|
||||
width=390
|
||||
height=10
|
||||
}
|
||||
monitor {
|
||||
chan="$(P):log10"
|
||||
clr=14
|
||||
bclr=4
|
||||
}
|
||||
limits {
|
||||
}
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=5
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log19"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=15
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log18"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=25
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log17"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=35
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log16"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=45
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log15"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=55
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log14"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=65
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log13"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=75
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log12"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=85
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log11"
|
||||
}
|
||||
text {
|
||||
object {
|
||||
x=5
|
||||
y=95
|
||||
width=25
|
||||
height=10
|
||||
}
|
||||
"basic attribute" {
|
||||
clr=14
|
||||
}
|
||||
textix="log10"
|
||||
}
|
10
streamApp/test.cmd
Normal file
10
streamApp/test.cmd
Normal file
@ -0,0 +1,10 @@
|
||||
dbLoadDatabase "O.Common/streamApp.dbd"
|
||||
streamApp_registerRecordDeviceDriver
|
||||
|
||||
epicsEnvSet "STREAM_PROTOCOL_PATH", "."
|
||||
|
||||
drvAsynIPPortConfigure "terminal", "localhost:40000"
|
||||
|
||||
dbLoadRecords "test.db","P=TEST"
|
||||
iocInit
|
||||
var streamDebug 1
|
133
streamApp/test.db
Normal file
133
streamApp/test.db
Normal file
@ -0,0 +1,133 @@
|
||||
record (stringout, "$(P):cmd")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto command terminal")
|
||||
field (VAL, "")
|
||||
}
|
||||
record (stringout, "$(P):info")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto info terminal")
|
||||
}
|
||||
record (stringout, "$(P):request")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto request($(P):reply.VAL) terminal")
|
||||
}
|
||||
record (stringin, "$(P):reply")
|
||||
{
|
||||
}
|
||||
record (stringin, "$(P):spy")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto spy terminal")
|
||||
field (SCAN, "I/O Intr")
|
||||
field (FLNK, "$(P):log19")
|
||||
}
|
||||
record (stringin, "$(P):log0")
|
||||
{
|
||||
field (INP, "$(P):spy")
|
||||
}
|
||||
record (stringin, "$(P):log1")
|
||||
{
|
||||
field (INP, "$(P):log0")
|
||||
field (FLNK, "$(P):log0")
|
||||
}
|
||||
record (stringin, "$(P):log2")
|
||||
{
|
||||
field (INP, "$(P):log1")
|
||||
field (FLNK, "$(P):log1")
|
||||
}
|
||||
record (stringin, "$(P):log3")
|
||||
{
|
||||
field (INP, "$(P):log2")
|
||||
field (FLNK, "$(P):log2")
|
||||
}
|
||||
record (stringin, "$(P):log4")
|
||||
{
|
||||
field (INP, "$(P):log3")
|
||||
field (FLNK, "$(P):log3")
|
||||
}
|
||||
record (stringin, "$(P):log5")
|
||||
{
|
||||
field (INP, "$(P):log4")
|
||||
field (FLNK, "$(P):log4")
|
||||
}
|
||||
record (stringin, "$(P):log6")
|
||||
{
|
||||
field (INP, "$(P):log5")
|
||||
field (FLNK, "$(P):log5")
|
||||
}
|
||||
record (stringin, "$(P):log7")
|
||||
{
|
||||
field (INP, "$(P):log6")
|
||||
field (FLNK, "$(P):log6")
|
||||
}
|
||||
record (stringin, "$(P):log8")
|
||||
{
|
||||
field (INP, "$(P):log7")
|
||||
field (FLNK, "$(P):log7")
|
||||
}
|
||||
record (stringin, "$(P):log9")
|
||||
{
|
||||
field (INP, "$(P):log8")
|
||||
field (FLNK, "$(P):log8")
|
||||
}
|
||||
record (stringin, "$(P):log10")
|
||||
{
|
||||
field (INP, "$(P):log9")
|
||||
field (FLNK, "$(P):log9")
|
||||
}
|
||||
record (stringin, "$(P):log11")
|
||||
{
|
||||
field (INP, "$(P):log10")
|
||||
field (FLNK, "$(P):log10")
|
||||
}
|
||||
record (stringin, "$(P):log12")
|
||||
{
|
||||
field (INP, "$(P):log11")
|
||||
field (FLNK, "$(P):log11")
|
||||
}
|
||||
record (stringin, "$(P):log13")
|
||||
{
|
||||
field (INP, "$(P):log12")
|
||||
field (FLNK, "$(P):log12")
|
||||
}
|
||||
record (stringin, "$(P):log14")
|
||||
{
|
||||
field (INP, "$(P):log13")
|
||||
field (FLNK, "$(P):log13")
|
||||
}
|
||||
record (stringin, "$(P):log15")
|
||||
{
|
||||
field (INP, "$(P):log14")
|
||||
field (FLNK, "$(P):log14")
|
||||
}
|
||||
record (stringin, "$(P):log16")
|
||||
{
|
||||
field (INP, "$(P):log15")
|
||||
field (FLNK, "$(P):log15")
|
||||
}
|
||||
record (stringin, "$(P):log17")
|
||||
{
|
||||
field (INP, "$(P):log16")
|
||||
field (FLNK, "$(P):log16")
|
||||
}
|
||||
record (stringin, "$(P):log18")
|
||||
{
|
||||
field (INP, "$(P):log17")
|
||||
field (FLNK, "$(P):log17")
|
||||
}
|
||||
record (stringin, "$(P):log19")
|
||||
{
|
||||
field (INP, "$(P):log18")
|
||||
field (FLNK, "$(P):log18")
|
||||
}
|
||||
record (waveform, "$(P):spybin")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto spybin terminal")
|
||||
field (FTVL, "CHAR")
|
||||
field (NELM, "2000")
|
||||
field (SCAN, "I/O Intr")
|
||||
}
|
25
streamApp/test.proto
Normal file
25
streamApp/test.proto
Normal file
@ -0,0 +1,25 @@
|
||||
terminator = CR LF;
|
||||
readtimeout = 1000;
|
||||
pollperiod = 10;
|
||||
replytimeout = 1000;
|
||||
command {
|
||||
out "%s";
|
||||
}
|
||||
info {
|
||||
out "%s";
|
||||
in "%39c";
|
||||
}
|
||||
request {
|
||||
out "%s";
|
||||
in "%(\$1)39c";
|
||||
}
|
||||
spy {
|
||||
extraInput=ignore;
|
||||
in "%39c";
|
||||
}
|
||||
spybin {
|
||||
readtimeout = 1;
|
||||
terminator = "";
|
||||
extraInput=ignore;
|
||||
in "%r";
|
||||
}
|
21
streamApp/test.readme
Normal file
21
streamApp/test.readme
Normal file
@ -0,0 +1,21 @@
|
||||
Simple test environment:
|
||||
|
||||
1) Start device simulation:
|
||||
terminal.tcl &
|
||||
Or set up a real device.
|
||||
|
||||
2) Start ioc:
|
||||
xterm -e test.cmd &
|
||||
Or edit test.cmd first.
|
||||
|
||||
3) Start medm:
|
||||
medm -x -macro P=TEST test.adl &
|
||||
|
||||
Records:
|
||||
TEST:cmd - writes string to device
|
||||
TEST:info - writes string and reads reply (result in same record)
|
||||
TEST:spy - gets any input line from device
|
||||
TEST:spybin - gets any input (binary waveform)
|
||||
TEST:log* - history of TEST:spy
|
||||
|
||||
Try to write 'help' to TEST:cmd.
|
40
streamApp/tests/printdouble
Executable file
40
streamApp/tests/printdouble
Executable file
@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
filename=$$
|
||||
trap "rm -f $filename.c $filename " EXIT TERM KILL
|
||||
|
||||
cat > $filename.c << EOF
|
||||
#line 8
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main (int argc, char** args)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
double d;
|
||||
unsigned char c [8];
|
||||
} u;
|
||||
|
||||
int i,j;
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
u.f = atof (args[i]);
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
printf ("\\\\x%02x", u.c[j]);
|
||||
}
|
||||
printf ("\n");
|
||||
u.d = atof (args[i]);
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
printf ("\\\\x%02x", u.c[j]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
cc -Wall -pedantic $filename.c -o $filename && $filename "$@"
|
204
streamApp/tests/streamtestlib.tcl
Normal file
204
streamApp/tests/streamtestlib.tcl
Normal file
@ -0,0 +1,204 @@
|
||||
#
|
||||
# Usage
|
||||
# 1) source this file
|
||||
# 2) define variables records, protocol, starup
|
||||
# 3) call startioc
|
||||
# 4) use ioccmd, assure, receive, send,...
|
||||
# 5) call finish
|
||||
|
||||
set testname [file tail $argv0]
|
||||
|
||||
proc bgerror msg {
|
||||
error $::errorInfo
|
||||
}
|
||||
|
||||
set debug 0
|
||||
proc debugmsg {string} {
|
||||
global debug
|
||||
if $debug {puts $string}
|
||||
}
|
||||
|
||||
proc deviceconnect {s addr port} {
|
||||
debugmsg "incoming connenction"
|
||||
global sock
|
||||
set sock $s
|
||||
fconfigure $sock -blocking no -buffering none -translation binary
|
||||
fileevent $sock readable "receiveHandler $sock"
|
||||
}
|
||||
|
||||
set inputbuffer {}
|
||||
proc receiveHandler {sock} {
|
||||
global inputbuffer inputlog
|
||||
set input [read $sock]
|
||||
puts -nonewline $inputlog $input
|
||||
append inputbuffer $input
|
||||
debugmsg "receiving \"[escape $inputbuffer]\""
|
||||
if [eof $sock] {
|
||||
close $sock
|
||||
debugmsg "connection closed by ioc"
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
proc startioc {} {
|
||||
global debug records protocol startup port sock ioc testname env streamversion
|
||||
set fd [open test.db w]
|
||||
puts $fd $records
|
||||
close $fd
|
||||
set fd [open test.proto w]
|
||||
puts $fd $protocol
|
||||
close $fd
|
||||
set fd [open test.cmd w 0777]
|
||||
|
||||
if [info exists streamversion] {
|
||||
puts $fd "#!/usr/local/bin/iocsh"
|
||||
puts $fd "require stream,$streamversion"
|
||||
} else {
|
||||
puts $fd "#!../O.$env(EPICS_HOST_ARCH)/streamApp"
|
||||
puts $fd "dbLoadDatabase ../O.Common/streamApp.dbd"
|
||||
puts $fd "streamApp_registerRecordDeviceDriver"
|
||||
}
|
||||
puts $fd "epicsEnvSet STREAM_PROTOCOL_PATH ."
|
||||
puts $fd "drvAsynIPPortConfigure device localhost:$port"
|
||||
puts $fd "dbLoadRecords test.db"
|
||||
puts $fd $startup
|
||||
puts $fd "iocInit"
|
||||
puts $fd "dbl"
|
||||
puts $fd "dbior stream 2"
|
||||
puts $fd "var streamDebug 1"
|
||||
close $fd
|
||||
if [info exists streamversion] {
|
||||
set ioc [open "|iocsh test.cmd >& $testname.ioclog 2>@stderr" w]
|
||||
} else {
|
||||
set ioc [open "|../O.$env(EPICS_HOST_ARCH)/streamApp test.cmd >& $testname.ioclog 2>@stderr" w]
|
||||
}
|
||||
fconfigure $ioc -blocking yes -buffering none
|
||||
debugmsg "waiting to connect"
|
||||
vwait sock
|
||||
}
|
||||
|
||||
set lastcommand ""
|
||||
set line 0
|
||||
proc ioccmd {command} {
|
||||
global ioc
|
||||
global lastcommand
|
||||
global line
|
||||
set lastcommand $command
|
||||
set line 0
|
||||
debugmsg "$command"
|
||||
puts $ioc $command
|
||||
}
|
||||
|
||||
proc send {string} {
|
||||
global sock lastsent
|
||||
set lastsent $string
|
||||
puts -nonewline $sock $string
|
||||
flush $sock
|
||||
}
|
||||
|
||||
set timeout 5000
|
||||
proc receive {} {
|
||||
global inputbuffer timeoutid timeout
|
||||
set timeoutid [after $timeout {
|
||||
set inputbuffer {}
|
||||
}]
|
||||
if {$inputbuffer == {}} { vwait inputbuffer }
|
||||
after cancel $timeoutid
|
||||
if {$inputbuffer == {}} {
|
||||
return -code error "Error in receive: timeout"
|
||||
}
|
||||
set index [string first "\n" $inputbuffer]
|
||||
if {$index > -1} {
|
||||
set input [string range $inputbuffer 0 $index]
|
||||
set inputbuffer [string range $inputbuffer [expr $index+1] end]
|
||||
} else {
|
||||
set input $inputbuffer
|
||||
set inputbuffer {}
|
||||
}
|
||||
return $input
|
||||
}
|
||||
|
||||
set faults 0
|
||||
proc assure {args} {
|
||||
global faults
|
||||
global lastcommand
|
||||
global lastsent
|
||||
global line
|
||||
|
||||
incr line
|
||||
set input {}
|
||||
for {set i 0} {$i < [llength $args]} {incr i} {
|
||||
if [catch {lappend input [receive]} msg] {
|
||||
puts stderr $msg
|
||||
break
|
||||
}
|
||||
}
|
||||
set notfound {}
|
||||
foreach expected $args {
|
||||
set index [lsearch -exact $input $expected]
|
||||
if {$index > -1} {
|
||||
set input [lreplace $input $index $index]
|
||||
} else {
|
||||
lappend notfound $expected
|
||||
}
|
||||
}
|
||||
if {[llength $notfound] || [llength $input]} {
|
||||
puts stderr "In command \"$lastcommand\""
|
||||
if [info exists lastsent] {
|
||||
puts stderr "last sent: \"[escape $lastsent]\""
|
||||
}
|
||||
}
|
||||
foreach string $notfound {
|
||||
puts stderr "Error in assure: line $line missing \"[escape $string]\""
|
||||
}
|
||||
foreach string $input {
|
||||
puts stderr "Error in assure: got unexpected \"[escape $string]\""
|
||||
}
|
||||
if {[llength $notfound] || [llength $input]} {incr faults}
|
||||
}
|
||||
|
||||
proc escape {string} {
|
||||
set result ""
|
||||
set length [string length $string]
|
||||
for {set i 0} {$i < $length} {incr i} {
|
||||
set c [string index $string $i]
|
||||
scan $c %c n
|
||||
if {$n == 13} {
|
||||
append result "\\r"
|
||||
} elseif {$n == 10} {
|
||||
append result "\\n"
|
||||
} elseif {($n & 127) < 32} {
|
||||
append result [format "<%02x>" $n]
|
||||
} else {
|
||||
append result $c
|
||||
}
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
proc finish {} {
|
||||
global ioc timeout testname faults
|
||||
set timeout 1000
|
||||
while {![catch {set string [receive]}]} {
|
||||
puts stderr "Error in finish: unexpected \"[escape $string]\""
|
||||
incr faults
|
||||
}
|
||||
after 100
|
||||
close $ioc
|
||||
if $faults {
|
||||
puts "\033\[31;7mTest failed.\033\[0m"
|
||||
exit 1
|
||||
}
|
||||
puts "\033\[32mTest passed.\033\[0m"
|
||||
eval file delete [glob -nocomplain test.*] StreamDebug.log $testname.ioclog
|
||||
}
|
||||
|
||||
set port 40123
|
||||
socket -server deviceconnect $port
|
||||
set inputlog [open "test.inputlog" w]
|
||||
|
||||
# SLS style driver modules (optionally with version)
|
||||
if {[lindex $argv 0] == "-sls"} {
|
||||
set streamversion [lindex $argv 1]
|
||||
set argv [lrange $argv 2 end]
|
||||
}
|
96
streamApp/tests/test64Bit
Executable file
96
streamApp/tests/test64Bit
Executable file
@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (ao, "DZ:ao")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto ao device")
|
||||
}
|
||||
record (longout, "DZ:longout")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto longout device")
|
||||
}
|
||||
record (bo, "DZ:bo")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto bo device")
|
||||
field (MASK, "-1")
|
||||
}
|
||||
record (mbbo, "DZ:mbbo")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto mbbo device")
|
||||
field (ZRVL, "0")
|
||||
field (ONVL, "-1")
|
||||
field (ZRST, "0")
|
||||
field (ONST, "-1")
|
||||
}
|
||||
record (mbboDirect, "DZ:mbboDirect")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto mbboDirect device")
|
||||
}
|
||||
record (ai, "DZ:ai")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto ai device")
|
||||
}
|
||||
record (longin, "DZ:longin")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto longin device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
# these records use signed values: %d
|
||||
ao {out "ao %.3f %d %(VAL).3f %(RVAL)d";}
|
||||
longout {out "longout %d %(VAL)d";}
|
||||
ai {out "ai?"; in "%d"; out "ai %d";}
|
||||
longin {out "longin?"; in "%d"; out "longin %d";}
|
||||
# these records use unsigned values: %u, %x
|
||||
bo {out "bo %u %x %b";}
|
||||
mbbo {out "mbbo %u %x %b";}
|
||||
mbboDirect {out "mbboDirect %u %x %b";}
|
||||
bi {out "bi?"; in "%d"; out "bi %d %x";}
|
||||
mbbi {out "mbbi?"; in "%d"; out "mbbi %d %x";}
|
||||
mbbiDirect {out "mbbiDirect?"; in "%d"; out "mbbiDirect %d %x";}
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
ioccmd {dbpf DZ:ao -1}
|
||||
assure "ao -1.000 -1 -1.000 -1\n"
|
||||
ioccmd {dbpf DZ:longout -1}
|
||||
assure "longout -1 -1\n"
|
||||
ioccmd {dbpf DZ:bo 1}
|
||||
assure "bo 4294967295 ffffffff 11111111111111111111111111111111\n"
|
||||
ioccmd {dbpf DZ:mbbo -1}
|
||||
assure "mbbo 4294967295 ffffffff 11111111111111111111111111111111\n"
|
||||
ioccmd {dbpf DZ:mbboDirect.B0 1}
|
||||
assure "mbboDirect 1 1 1\n"
|
||||
ioccmd {dbpf DZ:mbboDirect -1}
|
||||
assure "mbboDirect 65535 ffff 1111111111111111\n"
|
||||
ioccmd {dbpf DZ:ai.PROC 1}
|
||||
assure "ai?\n"
|
||||
send "-1\n"
|
||||
assure "ai -1\n"
|
||||
ioccmd {dbpf DZ:longin.PROC 1}
|
||||
assure "longin?\n"
|
||||
send "-1\n"
|
||||
assure "longin -1\n"
|
||||
|
||||
|
||||
finish
|
35
streamApp/tests/testBo
Executable file
35
streamApp/tests/testBo
Executable file
@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (bo, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto test1 device")
|
||||
field (ZNAM, "OFF")
|
||||
field (ONAM, "ON")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
test1 {out "%i %r %s";}
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1 0}
|
||||
assure "0 \x00 OFF"
|
||||
ioccmd {dbpf DZ:test1 1}
|
||||
assure "1 \x01 ON"
|
||||
|
||||
finish
|
108
streamApp/tests/testCharset
Executable file
108
streamApp/tests/testCharset
Executable file
@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (stringin, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test1 device")
|
||||
}
|
||||
record (stringin, "DZ:test2")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test2 device")
|
||||
}
|
||||
record (stringin, "DZ:test3")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test3 device")
|
||||
}
|
||||
record (stringin, "DZ:test4")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test4 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
extraInput=ignore;
|
||||
@mismatch {out "mismatch";}
|
||||
test1 {in "%[a-zA-Z1-5]%(DESC) #s"; out "%s|%(DESC)s" }
|
||||
test2 {in "%[]A-Za-z ]%(DESC) #s"; out "%s|%(DESC)s" }
|
||||
test3 {in "%[^]A-Z]%(DESC) #s"; out "%s|%(DESC)s" }
|
||||
test4 {in "%[^]-A-Z]%(DESC) #s"; out "%s|%(DESC)s" }
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "This is a test\n"
|
||||
assure "This| is a test\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "Test123]bla\n"
|
||||
assure "Test123|]bla\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "Test123456\n"
|
||||
assure "Test12345|6\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "Test43210\n"
|
||||
assure "Test4321|0\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "test-bla\n"
|
||||
assure "test|-bla\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send " Space first\n"
|
||||
assure "| Space first\n"
|
||||
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "This is a test\n"
|
||||
assure "This is a test|\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "Test]xx123bla\n"
|
||||
assure "Test]xx|123bla\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "test-bla\n"
|
||||
assure "test|-bla\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send " Space first\n"
|
||||
assure " Space first|\n"
|
||||
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "this is a test\n"
|
||||
assure "this is a test|\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "test]xx123bla\n"
|
||||
assure "test|]xx123bla\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "test-bla\n"
|
||||
assure "test-bla|\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send " Space first\n"
|
||||
assure " |Space first\n"
|
||||
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "this is a test\n"
|
||||
assure "this is a test|\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "test]xx123bla\n"
|
||||
assure "test|]xx123bla\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "test-bla\n"
|
||||
assure "test|-bla\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send " Space first\n"
|
||||
assure " |Space first\n"
|
||||
|
||||
finish
|
||||
|
30
streamApp/tests/testChecksum
Executable file
30
streamApp/tests/testChecksum
Executable file
@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (ao, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto test1 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
test1 {out 0x55 0x40 0x04 0x00 0x00 'z;' "%<sum>";}
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
ioccmd {dbpf DZ:test1 "1"}
|
||||
assure "\x55\x40\x04\x00\x00z;\x4e"
|
||||
|
||||
finish
|
43
streamApp/tests/testCompare
Executable file
43
streamApp/tests/testCompare
Executable file
@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (ao, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto test1 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
@mismatch { out "mismatch"; }
|
||||
test1 {out "set %.2f"; in "ack %=.2f X"; out "OK"; }
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1 3.14}
|
||||
assure "set 3.14\n"
|
||||
send "ack 3.14 X\n"
|
||||
assure "OK\n"
|
||||
ioccmd {dbpf DZ:test1 0}
|
||||
assure "set 0.00\n"
|
||||
send "ack 0.00 X\n"
|
||||
assure "OK\n"
|
||||
ioccmd {dbpf DZ:test1 1}
|
||||
assure "set 1.00\n"
|
||||
send "ack 1.0 X\n"
|
||||
assure "mismatch\n"
|
||||
|
||||
finish
|
56
streamApp/tests/testDefaultInput
Executable file
56
streamApp/tests/testDefaultInput
Executable file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (longin, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto integer device")
|
||||
}
|
||||
record (ai, "DZ:test2")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto double device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
integer {out "integer"; in "n: %?d xx"; out "n = %d"; }
|
||||
double {out "double"; in "n: %?g xx"; out "n = %.4f"; }
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
assure "integer\n";
|
||||
send "n: -12 xx\n";
|
||||
assure "n = -12\n";
|
||||
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
assure "integer\n";
|
||||
send "n: xx\n";
|
||||
assure "n = 0\n";
|
||||
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
assure "double\n";
|
||||
send "n: 3.1415 xx\n";
|
||||
assure "n = 3.1415\n";
|
||||
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
assure "double\n";
|
||||
send "n: xx\n";
|
||||
assure "n = 0.0000\n";
|
||||
|
||||
|
||||
finish
|
124
streamApp/tests/testDouble
Executable file
124
streamApp/tests/testDouble
Executable file
@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (ai, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test1 device")
|
||||
}
|
||||
record (ai, "DZ:test2")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test2 device")
|
||||
}
|
||||
record (ai, "DZ:test3")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test3 device")
|
||||
}
|
||||
record (ai, "DZ:test4")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test4 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
@mismatch {out "mismatch";}
|
||||
test1 {in "%f"; out "|%f|%10f|%.2f|%- 10.5f|% f|%+f|%-5.1f|%#f|"; }
|
||||
test2 {in "%6f%(DESC)s"; out "|%g|%(DESC)s|"; }
|
||||
test3 {in "% 6f%(DESC)s"; out "|%g|%(DESC)s|"; }
|
||||
test4 {in "%#f"; out "%f"; }
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
set inf [format %f inf]
|
||||
set nan [format %f nan]
|
||||
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "3.14159265359\n"
|
||||
assure "|3.141593| 3.141593|3.14| 3.14159 | 3.141593|+3.141593|3.1 |3.141593|\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "-3.14159265359\n"
|
||||
assure "|-3.141593| -3.141593|-3.14|-3.14159 |-3.141593|-3.141593|-3.1 |-3.141593|\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "0\n"
|
||||
assure "|0.000000| 0.000000|0.00| 0.00000 | 0.000000|+0.000000|0.0 |0.000000|\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "NAN\n"
|
||||
assure "|$nan| $nan|$nan| $nan | $nan|+$nan|$nan |$nan|\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "-Inf\n"
|
||||
assure "|-$inf| -$inf|-$inf|-$inf |-$inf|-$inf|-$inf |-$inf|\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "1e6\n"
|
||||
assure "|1000000.000000|1000000.000000|1000000.00| 1000000.00000| 1000000.000000|+1000000.000000|1000000.0|1000000.000000|\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send " - 3.14159265359\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "bla\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send " bla\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "-bla\n"
|
||||
assure "mismatch\n"
|
||||
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "3.14159265359\n"
|
||||
assure "|3.1415|9265359|\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send " 3.14159265359\n"
|
||||
assure "|3.1415|9265359|\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send " 10blabla\n"
|
||||
assure "|10|blabla|\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send " 1\n"
|
||||
assure "|1||\n"
|
||||
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "3.14159265359\n"
|
||||
assure "|3.1415|9265359|\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send " 3.14159265359\n"
|
||||
assure "|3|.14159265359|\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send " 10blabla\n"
|
||||
assure "|10|blabla|\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send " 1\n"
|
||||
assure "|1||\n"
|
||||
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "3.14159265359\n"
|
||||
assure "3.141593\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send " -3.14159265359\n"
|
||||
assure "-3.141593\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send " - 3.14159265359\n"
|
||||
assure "-3.141593\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send " + 3.14159265359\n"
|
||||
assure "3.141593\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send " +- 3.14159265359\n"
|
||||
assure "mismatch\n"
|
||||
|
||||
finish
|
75
streamApp/tests/testDummyInterface
Executable file
75
streamApp/tests/testDummyInterface
Executable file
@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "dummy" is not connected to any I/O
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (ao, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto test1 dummy")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
test1 {exec "dbpr %(NAME)s %i >testDummyInterface.out";}
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1 3}
|
||||
|
||||
after 1000
|
||||
|
||||
if [catch {
|
||||
set fd [open testDummyInterface.out]
|
||||
set output [read $fd]
|
||||
close $fd
|
||||
} msg] {
|
||||
puts stderr $msg
|
||||
incr faults
|
||||
}
|
||||
|
||||
set expected {ACKS: NO_ALARM ACKT: YES ADEL: 0 ALST: 0
|
||||
AOFF: 0 ASG: ASLO: 0 BKPT: 00
|
||||
DESC: DISA: 0 DISP: 0 DISS: NO_ALARM
|
||||
DISV: 1 DOL:CONSTANT DRVH: 0 DRVL: 0
|
||||
DTYP: stream EGU: EGUF: 0 EGUL: 0
|
||||
EOFF: 0 ESLO: 1 EVNT: 0 FLNK:CONSTANT 0
|
||||
HHSV: NO_ALARM HIGH: 0 HIHI: 0 HOPR: 0
|
||||
HSV: NO_ALARM HYST: 0 INIT: 1
|
||||
IVOA: Continue normally IVOV: 0 LALM: 3
|
||||
LBRK: 0 LCNT: 0 LINR: NO CONVERSION LLSV: NO_ALARM
|
||||
LOLO: 0 LOPR: 0 LOW: 0 LSV: NO_ALARM
|
||||
MDEL: 0 MLST: 0 NAME: DZ:test1 NSEV: NO_ALARM
|
||||
NSTA: NO_ALARM OIF: Full OMOD: 1 OMSL: supervisory
|
||||
ORAW: 0 ORBV: 0 OROC: 0
|
||||
OUT:INST_IO @test.proto test1 dummy OVAL: 3 PACT: 1
|
||||
PHAS: 0 PINI: NO PREC: 0 PRIO: LOW
|
||||
PROC: 0 PUTF: 1 PVAL: 3 RBV: 0
|
||||
ROFF: 0 RPRO: 0 RVAL: 3 SCAN: Passive
|
||||
SDIS:CONSTANT SEVR: INVALID SIML:CONSTANT SIMM: NO
|
||||
SIMS: NO_ALARM SIOL:CONSTANT STAT: UDF TIME: <undefined>
|
||||
TPRO: 0 TSE: 0 TSEL:CONSTANT UDF: 0
|
||||
VAL: 3
|
||||
}
|
||||
|
||||
if {"$output" != "$expected"} {
|
||||
puts stderr "Wrong output:"
|
||||
puts stderr "$output"
|
||||
puts stderr "instead of:"
|
||||
puts stderr "$expected"
|
||||
incr faults
|
||||
} else {
|
||||
file delete testDummyInterface.out
|
||||
}
|
||||
|
||||
finish
|
124
streamApp/tests/testEnum
Executable file
124
streamApp/tests/testEnum
Executable file
@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (longout, "DZ:testout")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto out device")
|
||||
}
|
||||
record (longin, "DZ:testin")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto in device")
|
||||
}
|
||||
record (longout, "DZ:testout1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto out1 device")
|
||||
}
|
||||
record (longin, "DZ:testin1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto in1 device")
|
||||
}
|
||||
record (longout, "DZ:testout2")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto out2 device")
|
||||
}
|
||||
record (longin, "DZ:testin2")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto in2 device")
|
||||
}
|
||||
record (longin, "DZ:testin3")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto in3 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
out {out "%{zero|one|two}bla";}
|
||||
in {in "%{zero|one|two}bla"; out "%d";}
|
||||
out1 {out "%#{zero|one|two}bla";}
|
||||
in1 {in "%#{zero|one|two}bla"; out "%d";}
|
||||
out2 {out "%#{zero=-1|one|two=5}bla";}
|
||||
in2 {in "%#{zero=-1|one|two=5}bla"; out "%d";}
|
||||
in3 {in "%{\x00|\r|}bla"; out "%d";}
|
||||
}
|
||||
|
||||
set startup {
|
||||
var streamDebug 1
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:testout 0}
|
||||
assure "zerobla\n"
|
||||
ioccmd {dbpf DZ:testout 1}
|
||||
assure "onebla\n"
|
||||
ioccmd {dbpf DZ:testout 2}
|
||||
assure "twobla\n"
|
||||
ioccmd {dbpf DZ:testout1 0}
|
||||
assure "zerobla\n"
|
||||
ioccmd {dbpf DZ:testout1 1}
|
||||
assure "onebla\n"
|
||||
ioccmd {dbpf DZ:testout1 2}
|
||||
assure "twobla\n"
|
||||
ioccmd {dbpf DZ:testout2 -1}
|
||||
assure "zerobla\n"
|
||||
ioccmd {dbpf DZ:testout2 0}
|
||||
assure "onebla\n"
|
||||
ioccmd {dbpf DZ:testout2 5}
|
||||
assure "twobla\n"
|
||||
|
||||
ioccmd {dbpf DZ:testin.PROC 1}
|
||||
send "zerobla\n"
|
||||
assure "0\n"
|
||||
ioccmd {dbpf DZ:testin.PROC 1}
|
||||
send "onebla\n"
|
||||
assure "1\n"
|
||||
ioccmd {dbpf DZ:testin.PROC 1}
|
||||
send "twobla\n"
|
||||
assure "2\n"
|
||||
ioccmd {dbpf DZ:testin1.PROC 1}
|
||||
send "zerobla\n"
|
||||
assure "0\n"
|
||||
ioccmd {dbpf DZ:testin1.PROC 1}
|
||||
send "onebla\n"
|
||||
assure "1\n"
|
||||
ioccmd {dbpf DZ:testin1.PROC 1}
|
||||
send "twobla\n"
|
||||
assure "2\n"
|
||||
ioccmd {dbpf DZ:testin2.PROC 1}
|
||||
send "zerobla\n"
|
||||
assure "-1\n"
|
||||
ioccmd {dbpf DZ:testin2.PROC 1}
|
||||
send "onebla\n"
|
||||
assure "0\n"
|
||||
ioccmd {dbpf DZ:testin2.PROC 1}
|
||||
send "twobla\n"
|
||||
assure "5\n"
|
||||
|
||||
ioccmd {dbpf DZ:testin3.PROC 1}
|
||||
send "\000bla\n"
|
||||
assure "0\n"
|
||||
ioccmd {dbpf DZ:testin3.PROC 1}
|
||||
send "\rbla\n"
|
||||
assure "1\n"
|
||||
ioccmd {dbpf DZ:testin3.PROC 1}
|
||||
send "bla\n"
|
||||
assure "2\n"
|
||||
|
||||
|
||||
finish
|
67
streamApp/tests/testFormatm
Executable file
67
streamApp/tests/testFormatm
Executable file
@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (ao, "DZ:ao")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto ao device")
|
||||
}
|
||||
record (ai, "DZ:ai")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto ai device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
ao {out "'%m' '%.4m' '%+.4m' '% .4m' '% +.4m' '%10.4m' '%-10.4m'";}
|
||||
ai {out "?"; in "%m"; out "%.4e";}
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:ao 0}
|
||||
assure "'000000+00' '0000+00' '+0000+00' ' 0000+00' '+0000+00' ' 0000+00' '0000+00 '\n"
|
||||
ioccmd {dbpf DZ:ao 1}
|
||||
assure "'100000-05' '1000-03' '+1000-03' ' 1000-03' '+1000-03' ' 1000-03' '1000-03 '\n"
|
||||
ioccmd {dbpf DZ:ao 1000}
|
||||
assure "'100000-02' '1000+00' '+1000+00' ' 1000+00' '+1000+00' ' 1000+00' '1000+00 '\n"
|
||||
ioccmd {dbpf DZ:ao 1000000}
|
||||
assure "'100000+01' '1000+03' '+1000+03' ' 1000+03' '+1000+03' ' 1000+03' '1000+03 '\n"
|
||||
ioccmd {dbpf DZ:ao -1}
|
||||
assure "'-100000-05' '-1000-03' '-1000-03' '-1000-03' '-1000-03' ' -1000-03' '-1000-03 '\n"
|
||||
ioccmd {dbpf DZ:ao 12345}
|
||||
assure "'123450-01' '1235+01' '+1235+01' ' 1235+01' '+1235+01' ' 1235+01' '1235+01 '\n"
|
||||
ioccmd {dbpf DZ:ao -1.2345e-15}
|
||||
assure "'-123450-20' '-1235-18' '-1235-18' '-1235-18' '-1235-18' ' -1235-18' '-1235-18 '\n"
|
||||
ioccmd {dbpf DZ:ao 1e-100}
|
||||
assure "'100000-105' '1000-103' '+1000-103' ' 1000-103' '+1000-103' ' 1000-103' '1000-103 '\n"
|
||||
ioccmd {dbpf DZ:ai.PROC 1}
|
||||
assure "?\n"
|
||||
send "+1234+56\n"
|
||||
assure "1.2340e+59\n"
|
||||
ioccmd {dbpf DZ:ai.PROC 1}
|
||||
assure "?\n"
|
||||
send "-1234-56\n"
|
||||
assure "-1.2340e-53\n"
|
||||
ioccmd {dbpf DZ:ai.PROC 1}
|
||||
assure "?\n"
|
||||
send "-12340000-60\n"
|
||||
assure "-1.2340e-53\n"
|
||||
ioccmd {dbpf DZ:ai.PROC 1}
|
||||
assure "?\n"
|
||||
send "+00000000+0\n"
|
||||
assure "0.0000e+00\n"
|
||||
finish
|
102
streamApp/tests/testFormats
Executable file
102
streamApp/tests/testFormats
Executable file
@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (ao, "DZ:ao")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto ao device")
|
||||
field (EOFF, "-10")
|
||||
field (ESLO, "0.000305180437934")
|
||||
field (LINR, "LINEAR")
|
||||
}
|
||||
record (longout, "DZ:lo")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto lo device")
|
||||
}
|
||||
record (longout, "DZ:bcd")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto bcd device")
|
||||
}
|
||||
record (stringout, "DZ:chksum")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto chksum device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
ao {out "%.2f %.2e %.2E %.2g %.2G %i %d %u %o %04x %#.2f %#.2e %#.2E %#.2g %#.2G %#i %#d %#u %#o %#06x";}
|
||||
lo {out "%d %(VAL)d %06d %x %06X %b %06b %.6b %B.! %06B.!";}
|
||||
bcd {out "%D %6D %.2D %.4D %.6D %.8D %#D %#6D %#.2D %#.4D %#.6D";}
|
||||
chksum {out "%s%<xor>";
|
||||
out "%s%0<sum>";
|
||||
out "%s%0<crc8>";
|
||||
out "%s%0<crc16>";
|
||||
out "%s%0<crc32>";
|
||||
out "%s%0<adler32>";
|
||||
}
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
# Some formats give different results on 32 bit and 64 bit machines.
|
||||
# This occurs when printing negative numbers with unsigned formats.
|
||||
# This is normal. E.g. -1 HAS a different number of 1 bits.
|
||||
# Specify the width field in the format if this is a problem.
|
||||
|
||||
ioccmd {dbpf DZ:ao 0}
|
||||
assure "0.00 0.00e+00 0.00E+00 0 0 32767 32767 32767 77777 7fff 0.00 0.00e+00 0.00E+00 0.0 0.0 32767 32767 32767 077777 0x7fff\n"
|
||||
ioccmd {dbpf DZ:ao 10}
|
||||
assure "10.00 1.00e+01 1.00E+01 10 10 65535 65535 65535 177777 ffff 10.00 1.00e+01 1.00E+01 10. 10. 65535 65535 65535 0177777 0xffff\n"
|
||||
ioccmd {dbpf DZ:ao -10}
|
||||
assure "-10.00 -1.00e+01 -1.00E+01 -10 -10 0 0 0 0 0000 -10.00 -1.00e+01 -1.00E+01 -10. -10. 0 0 0 0 000000\n"
|
||||
ioccmd {dbpf DZ:ao 1e-6}
|
||||
assure "0.00 1.00e-06 1.00E-06 1e-06 1E-06 32768 32768 32768 100000 8000 0.00 1.00e-06 1.00E-06 1.0e-06 1.0E-06 32768 32768 32768 0100000 0x8000\n"
|
||||
ioccmd {dbpf DZ:lo 0}
|
||||
assure "0 0 000000 0 000000 0 000000 000000 . ......\n"
|
||||
ioccmd {dbpf DZ:lo 12345}
|
||||
assure "12345 12345 012345 3039 003039 11000000111001 11000000111001 111001 !!......!!!..! !!......!!!..!\n"
|
||||
ioccmd {dbpf DZ:lo -1}
|
||||
if {$tcl_platform(machine) == "x86_64"} {
|
||||
assure "-1 -1 -00001 ffffffffffffffff FFFFFFFFFFFFFFFF 1111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111 111111 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||
} else {
|
||||
assure "-1 -1 -00001 ffffffff FFFFFFFF 11111111111111111111111111111111 11111111111111111111111111111111 111111 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||
}
|
||||
ioccmd {dbpf DZ:lo -1234}
|
||||
if {$tcl_platform(machine) == "x86_64"} {
|
||||
assure "-1234 -1234 -01234 fffffffffffffb2e FFFFFFFFFFFFFB2E 1111111111111111111111111111111111111111111111111111101100101110 1111111111111111111111111111111111111111111111111111101100101110 101110 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!.!!..!.!!!. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!.!!..!.!!!.\n"
|
||||
} else {
|
||||
assure "-1234 -1234 -01234 fffffb2e FFFFFB2E 11111111111111111111101100101110 11111111111111111111101100101110 101110 !!!!!!!!!!!!!!!!!!!!!.!!..!.!!!. !!!!!!!!!!!!!!!!!!!!!.!!..!.!!!.\n"
|
||||
}
|
||||
ioccmd {dbpf DZ:lo 255}
|
||||
assure "255 255 000255 ff 0000FF 11111111 11111111 111111 !!!!!!!! !!!!!!!!\n"
|
||||
ioccmd {dbpf DZ:lo 65535}
|
||||
assure "65535 65535 065535 ffff 00FFFF 1111111111111111 1111111111111111 111111 !!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!\n"
|
||||
ioccmd {dbpf DZ:bcd 1020304}
|
||||
if {$tcl_platform(machine) == "x86_64"} {
|
||||
assure "\0\0\0\0\1\2\3\4 \0\0\0\0\1\2\3\4 \4 \3\4 \2\3\4 \1\2\3\4 \4\3\2\1\0\0\0\0 \4\3\2\1\0\0\0\0 \4 \4\3 \4\3\2\n"
|
||||
} else {
|
||||
assure "\1\2\3\4 \0\0\1\2\3\4 \4 \3\4 \2\3\4 \1\2\3\4 \4\3\2\1 \4\3\2\1\0\0 \4 \4\3 \4\3\2\n"
|
||||
}
|
||||
ioccmd {dbpf DZ:chksum "123456789"}
|
||||
assure "1234567891\n"
|
||||
assure "123456789DD\n"
|
||||
assure "123456789F4\n"
|
||||
assure "123456789FEE8\n"
|
||||
assure "123456789FC891918\n"
|
||||
assure "123456789091E01DE\n"
|
||||
finish
|
44
streamApp/tests/testHalfInputTerminator
Executable file
44
streamApp/tests/testHalfInputTerminator
Executable file
@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (stringin, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test1 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = CR LF;
|
||||
test1 {out "Give input"; in "%s"; out "%s"; }
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
assure "Give input\r\n"
|
||||
send "abc\r\n"
|
||||
assure "abc\r\n"
|
||||
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
assure "Give input\r\n"
|
||||
send "x\r\n"
|
||||
assure "x\r\n"
|
||||
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
assure "Give input\r\n"
|
||||
send "\r\n"
|
||||
assure "\r\n"
|
||||
|
||||
finish
|
455
streamApp/tests/testInteger
Executable file
455
streamApp/tests/testInteger
Executable file
@ -0,0 +1,455 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (ai, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test1 device")
|
||||
}
|
||||
record (ai, "DZ:test2")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test2 device")
|
||||
}
|
||||
record (ai, "DZ:test3")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test3 device")
|
||||
}
|
||||
record (ai, "DZ:test4")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test4 device")
|
||||
}
|
||||
record (ai, "DZ:test5")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test5 device")
|
||||
}
|
||||
record (ai, "DZ:test6")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test6 device")
|
||||
}
|
||||
record (ai, "DZ:test7")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test7 device")
|
||||
}
|
||||
record (ai, "DZ:test8")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test8 device")
|
||||
}
|
||||
record (ai, "DZ:test9")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test9 device")
|
||||
}
|
||||
record (ai, "DZ:test10")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test10 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
extraInput=ignore;
|
||||
@mismatch {out "mismatch";}
|
||||
test1 {in "%i"; out "%i"; }
|
||||
test2 {in "%d"; out "%d"; }
|
||||
test3 {in "%u"; out "%u"; }
|
||||
test4 {in "%x"; out "%x"; }
|
||||
test5 {in "%o"; out "%o"; }
|
||||
test6 {in "%4i"; out "%i"; }
|
||||
test7 {in "% 4i"; out "%i"; }
|
||||
test8 {in "%#i"; out "%i"; }
|
||||
test9 {in "%-x"; out "%i"; }
|
||||
test10 {in "%-o"; out "%i"; }
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "12345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "-12345\n"
|
||||
assure "-12345\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send " 12345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send " -12345\n"
|
||||
assure "-12345\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "- 12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send " \n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send " 0x12345\n"
|
||||
assure "74565\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send " 012345\n"
|
||||
assure "5349\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "-0x12345\n"
|
||||
assure "-74565\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "0xffffffff\n"
|
||||
assure "-1\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "-0xffffffff\n"
|
||||
assure "1\n"
|
||||
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "12345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "-12345\n"
|
||||
assure "-12345\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send " 12345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send " -12345\n"
|
||||
assure "-12345\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "- 12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send " \n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send " 0x12345\n"
|
||||
assure "0\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send " 012345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "-0x12345\n"
|
||||
assure "0\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "0xffffffff\n"
|
||||
assure "0\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "-0xffffffff\n"
|
||||
assure "0\n"
|
||||
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "12345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "-12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send " 12345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send " -12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "- 12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send " \n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send " 0x12345\n"
|
||||
assure "0\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send " 012345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "-0x12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "0xffffffff\n"
|
||||
assure "0\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "-0xffffffff\n"
|
||||
assure "mismatch\n"
|
||||
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "12345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "-12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send " 12345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send " -12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "- 12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send " \n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send " 0x12345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send " 012345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "-0x12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "0xffffffff\n"
|
||||
assure "ffffffff\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "-0xffffffff\n"
|
||||
assure "mismatch\n"
|
||||
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "12345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "-12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send " 12345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send " -12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "- 12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send " \n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send " 0x12345\n"
|
||||
assure "0\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send " 012345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "-0x12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "0xffffffff\n"
|
||||
assure "0\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "-0xffffffff\n"
|
||||
assure "mismatch\n"
|
||||
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send "12345\n"
|
||||
assure "1234\n"
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send "-12345\n"
|
||||
assure "-123\n"
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send " 12345\n"
|
||||
assure "1234\n"
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send " -12345\n"
|
||||
assure "-123\n"
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send "- 12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send "\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send " \n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send " 0x12345\n"
|
||||
assure "18\n"
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send " 012345\n"
|
||||
assure "83\n"
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send "-0x12345\n"
|
||||
assure "-1\n"
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send "0xffffffff\n"
|
||||
assure "255\n"
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send "-0xffffffff\n"
|
||||
assure "-15\n"
|
||||
|
||||
ioccmd {dbpf DZ:test7.PROC 1}
|
||||
send "12345\n"
|
||||
assure "1234\n"
|
||||
ioccmd {dbpf DZ:test7.PROC 1}
|
||||
send "-12345\n"
|
||||
assure "-123\n"
|
||||
ioccmd {dbpf DZ:test7.PROC 1}
|
||||
send " 12345\n"
|
||||
assure "1\n"
|
||||
ioccmd {dbpf DZ:test7.PROC 1}
|
||||
send " -12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test7.PROC 1}
|
||||
send "- 12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test7.PROC 1}
|
||||
send "\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test7.PROC 1}
|
||||
send " \n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test7.PROC 1}
|
||||
send " 0x12345\n"
|
||||
assure "1\n"
|
||||
ioccmd {dbpf DZ:test7.PROC 1}
|
||||
send " 012345\n"
|
||||
assure "10\n"
|
||||
ioccmd {dbpf DZ:test7.PROC 1}
|
||||
send "-0x12345\n"
|
||||
assure "-1\n"
|
||||
ioccmd {dbpf DZ:test7.PROC 1}
|
||||
send "0xffffffff\n"
|
||||
assure "255\n"
|
||||
ioccmd {dbpf DZ:test7.PROC 1}
|
||||
send "-0xffffffff\n"
|
||||
assure "-15\n"
|
||||
|
||||
ioccmd {dbpf DZ:test8.PROC 1}
|
||||
send "12345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test8.PROC 1}
|
||||
send "-12345\n"
|
||||
assure "-12345\n"
|
||||
ioccmd {dbpf DZ:test8.PROC 1}
|
||||
send " 12345\n"
|
||||
assure "12345\n"
|
||||
ioccmd {dbpf DZ:test8.PROC 1}
|
||||
send " -12345\n"
|
||||
assure "-12345\n"
|
||||
ioccmd {dbpf DZ:test8.PROC 1}
|
||||
send "- 12345\n"
|
||||
assure "-12345\n"
|
||||
ioccmd {dbpf DZ:test8.PROC 1}
|
||||
send "\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test8.PROC 1}
|
||||
send " \n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test8.PROC 1}
|
||||
send " 0x12345\n"
|
||||
assure "74565\n"
|
||||
ioccmd {dbpf DZ:test8.PROC 1}
|
||||
send " 012345\n"
|
||||
assure "5349\n"
|
||||
ioccmd {dbpf DZ:test8.PROC 1}
|
||||
send "-0x12345\n"
|
||||
assure "-74565\n"
|
||||
ioccmd {dbpf DZ:test8.PROC 1}
|
||||
send "0xffffffff\n"
|
||||
assure "-1\n"
|
||||
ioccmd {dbpf DZ:test8.PROC 1}
|
||||
send "-0xffffffff\n"
|
||||
assure "1\n"
|
||||
|
||||
ioccmd {dbpf DZ:test9.PROC 1}
|
||||
send "12345\n"
|
||||
assure "74565\n"
|
||||
ioccmd {dbpf DZ:test9.PROC 1}
|
||||
send "-12345\n"
|
||||
assure "-74565\n"
|
||||
ioccmd {dbpf DZ:test9.PROC 1}
|
||||
send " 12345\n"
|
||||
assure "74565\n"
|
||||
ioccmd {dbpf DZ:test9.PROC 1}
|
||||
send " -12345\n"
|
||||
assure "-74565\n"
|
||||
ioccmd {dbpf DZ:test9.PROC 1}
|
||||
send "- 12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test9.PROC 1}
|
||||
send "\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test9.PROC 1}
|
||||
send " \n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test9.PROC 1}
|
||||
send " 0x12345\n"
|
||||
assure "74565\n"
|
||||
ioccmd {dbpf DZ:test9.PROC 1}
|
||||
send " 012345\n"
|
||||
assure "74565\n"
|
||||
ioccmd {dbpf DZ:test9.PROC 1}
|
||||
send "-0x12345\n"
|
||||
assure "-74565\n"
|
||||
ioccmd {dbpf DZ:test9.PROC 1}
|
||||
send "0xffffffff\n"
|
||||
assure "-1\n"
|
||||
ioccmd {dbpf DZ:test9.PROC 1}
|
||||
send "-0xffffffff\n"
|
||||
assure "1\n"
|
||||
|
||||
ioccmd {dbpf DZ:test10.PROC 1}
|
||||
send "12345\n"
|
||||
assure "5349\n"
|
||||
ioccmd {dbpf DZ:test10.PROC 1}
|
||||
send "-12345\n"
|
||||
assure "-5349\n"
|
||||
ioccmd {dbpf DZ:test10.PROC 1}
|
||||
send " 12345\n"
|
||||
assure "5349\n"
|
||||
ioccmd {dbpf DZ:test10.PROC 1}
|
||||
send " -12345\n"
|
||||
assure "-5349\n"
|
||||
ioccmd {dbpf DZ:test10.PROC 1}
|
||||
send "- 12345\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test10.PROC 1}
|
||||
send "\n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test10.PROC 1}
|
||||
send " \n"
|
||||
assure "mismatch\n"
|
||||
ioccmd {dbpf DZ:test10.PROC 1}
|
||||
send " 0x12345\n"
|
||||
assure "0\n"
|
||||
ioccmd {dbpf DZ:test10.PROC 1}
|
||||
send " 012345\n"
|
||||
assure "5349\n"
|
||||
ioccmd {dbpf DZ:test10.PROC 1}
|
||||
send "-0x12345\n"
|
||||
assure "0\n"
|
||||
ioccmd {dbpf DZ:test10.PROC 1}
|
||||
send "0xffffffff\n"
|
||||
assure "0\n"
|
||||
ioccmd {dbpf DZ:test10.PROC 1}
|
||||
send "-0xffffffff\n"
|
||||
assure "0\n"
|
||||
|
||||
finish
|
81
streamApp/tests/testIoIntrPollTimeout
Executable file
81
streamApp/tests/testIoIntrPollTimeout
Executable file
@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (bo, "DZ:ready")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto ready device")
|
||||
field (PINI, "YES")
|
||||
}
|
||||
record (longin, "DZ:read")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto readintr device")
|
||||
field (SCAN, "I/O Intr")
|
||||
field (FLNK, "DZ:count")
|
||||
}
|
||||
record (calc, "DZ:count")
|
||||
{
|
||||
field (INPA, "DZ:count")
|
||||
field (CALC, "A+1")
|
||||
field (FLNK, "DZ:errorcount")
|
||||
}
|
||||
record (calc, "DZ:errorcount")
|
||||
{
|
||||
field (INPA, "DZ:errorcount")
|
||||
field (INPB, "DZ:read")
|
||||
field (INPC, "DZ:count")
|
||||
field (CALC, "A+(B#C)")
|
||||
}
|
||||
record (longout, "DZ:printresult")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (DOL, "DZ:read")
|
||||
field (OMSL, "closed_loop")
|
||||
field (OUT, "@test.proto printresult device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
PollPeriod=10;
|
||||
ReadTimeout=50;
|
||||
ready {out "ready"; }
|
||||
readintr {in "This is a line in chunks with number %d"; }
|
||||
printresult {out "Last line received: %d";
|
||||
out "Line count: %(DZ:count)d";
|
||||
out "Error count: %(DZ:errorcount)d"; }
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
set rep 10
|
||||
|
||||
assure "ready\n"
|
||||
for {set i 1} {$i <= $rep} {incr i} {
|
||||
send "This "
|
||||
after 10
|
||||
send "is a "
|
||||
after 10
|
||||
send "line in chunks "
|
||||
after 10
|
||||
send "with number $i\n"
|
||||
after 100
|
||||
}
|
||||
ioccmd {dbpf "DZ:printresult.PROC" 1}
|
||||
assure "Last line received: $rep\n"
|
||||
assure "Line count: $rep\n"
|
||||
assure "Error count: 0\n"
|
||||
finish
|
||||
|
45
streamApp/tests/testLongInputTerminator
Executable file
45
streamApp/tests/testLongInputTerminator
Executable file
@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (stringin, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test1 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
InTerminator = CR CR CR;
|
||||
OutTerminator = LF;
|
||||
test1 {out "Give input"; in "%39c"; out "%s"; }
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
assure "Give input\n"
|
||||
send "abc\r\r\r"
|
||||
assure "abc\n"
|
||||
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
assure "Give input\n"
|
||||
send "klm\rxyz\r\r\r"
|
||||
assure "klm\rxyz\n"
|
||||
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
assure "Give input\n"
|
||||
send "123\r\rxyz\r\r\r"
|
||||
assure "123\r\rxyz\n"
|
||||
|
||||
finish
|
73
streamApp/tests/testLongUnsolicitedInput
Executable file
73
streamApp/tests/testLongUnsolicitedInput
Executable file
@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (bo, "DZ:ready")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto ready device")
|
||||
field (PINI, "YES")
|
||||
}
|
||||
record (stringin, "DZ:read")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto readintr device")
|
||||
field (SCAN, "I/O Intr")
|
||||
field (FLNK, "DZ:count")
|
||||
}
|
||||
record (calc, "DZ:count")
|
||||
{
|
||||
field (INPA, "DZ:count")
|
||||
field (CALC, "A+1")
|
||||
}
|
||||
record (longout, "DZ:countout")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (DOL, "DZ:count")
|
||||
field (OMSL, "closed_loop")
|
||||
field (OUT, "@test.proto printnum device")
|
||||
}
|
||||
record (stringout, "DZ:stringout")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (DOL, "DZ:read")
|
||||
field (OMSL, "closed_loop")
|
||||
field (OUT, "@test.proto printstr device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
ready {out "ready"; }
|
||||
readintr {extraInput=ignore; in "%39c"; }
|
||||
printnum {out "%d";}
|
||||
printstr {out "%s";}
|
||||
}
|
||||
|
||||
set startup {
|
||||
var streamDebug 1
|
||||
}
|
||||
|
||||
set debug 0
|
||||
set rep 500
|
||||
|
||||
startioc
|
||||
|
||||
assure "ready\n"
|
||||
after 1000
|
||||
for {set i 1} {$i <= $rep} {incr i} {
|
||||
append output "This is line $i.\n"
|
||||
}
|
||||
send $output
|
||||
after 2000
|
||||
ioccmd {dbpf "DZ:stringout.PROC" 1}
|
||||
assure "This is line $rep.\n"
|
||||
ioccmd {dbpf "DZ:countout.PROC" 1}
|
||||
assure "$rep\n"
|
||||
|
||||
finish
|
454
streamApp/tests/testMultiLineFormatString
Executable file
454
streamApp/tests/testMultiLineFormatString
Executable file
@ -0,0 +1,454 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
#
|
||||
# Simple database for Dawn RuSH system monitor
|
||||
#
|
||||
|
||||
record(bo, "DZ:SetPower")
|
||||
{
|
||||
field(DESC, "Control power supplies")
|
||||
field(DTYP, "stream")
|
||||
field(OUT, "@test.proto ps() device 0")
|
||||
field(ZNAM, "OFF")
|
||||
field(ONAM, "ON")
|
||||
field(FLNK, "DZ:VP3")
|
||||
}
|
||||
record(bo, "DZ:SetPower1")
|
||||
{
|
||||
field(DESC, "Control power supply 1")
|
||||
field(DTYP, "stream")
|
||||
field(OUT, "@test.proto ps(1) device 0")
|
||||
field(ZNAM, "OFF")
|
||||
field(ONAM, "ON")
|
||||
field(FLNK, "DZ:VP3")
|
||||
}
|
||||
record(bo, "DZ:SetPower2")
|
||||
{
|
||||
field(DESC, "Control power supply 2")
|
||||
field(DTYP, "stream")
|
||||
field(OUT, "@test.proto ps(2) device 0")
|
||||
field(ZNAM, "OFF")
|
||||
field(ONAM, "ON")
|
||||
field(FLNK, "DZ:VP3")
|
||||
}
|
||||
|
||||
record(ai, "DZ:VP3")
|
||||
{
|
||||
field(DESC, "+3.3V supply")
|
||||
field(DTYP, "stream")
|
||||
field(INP, "@test.proto query(DZ:) device 0")
|
||||
field(EGU, "V")
|
||||
field(PREC, "3")
|
||||
field(LINR, "SLOPE")
|
||||
field(ESLO, "1e-3")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "5")
|
||||
field(LOLO, "2.97")
|
||||
field(LOW, "3.135")
|
||||
field(HIGH, "3.465")
|
||||
field(HIHI, "3.63")
|
||||
field(LLSV, "MAJOR")
|
||||
field(LSV, "MINOR")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "0.033")
|
||||
field(FLNK, "DZ:VP5")
|
||||
}
|
||||
record(ai, "DZ:VP5")
|
||||
{
|
||||
field(DESC, "+5V supply")
|
||||
field(DTYP, "Raw Soft Channel")
|
||||
field(EGU, "V")
|
||||
field(PREC, "3")
|
||||
field(LINR, "SLOPE")
|
||||
field(ESLO, "1e-3")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "5")
|
||||
field(LOLO, "4.5")
|
||||
field(LOW, "4.75")
|
||||
field(HIGH, "5.25")
|
||||
field(HIHI, "5.5")
|
||||
field(LLSV, "MAJOR")
|
||||
field(LSV, "MINOR")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "0.05")
|
||||
field(FLNK, "DZ:VP12")
|
||||
}
|
||||
record(ai, "DZ:VP12")
|
||||
{
|
||||
field(DESC, "+12V supply")
|
||||
field(DTYP, "Raw Soft Channel")
|
||||
field(EGU, "V")
|
||||
field(PREC, "3")
|
||||
field(LINR, "SLOPE")
|
||||
field(ESLO, "1e-3")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "12")
|
||||
field(LOLO, "10.8")
|
||||
field(LOW, "11.4")
|
||||
field(HIGH, "12.6")
|
||||
field(HIHI, "13.2")
|
||||
field(LLSV, "MAJOR")
|
||||
field(LSV, "MINOR")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "0.12")
|
||||
field(FLNK, "DZ:VM12")
|
||||
}
|
||||
record(ai, "DZ:VM12")
|
||||
{
|
||||
field(DESC, "-12V supply")
|
||||
field(DTYP, "Raw Soft Channel")
|
||||
field(EGU, "V")
|
||||
field(PREC, "3")
|
||||
field(LINR, "SLOPE")
|
||||
field(ESLO, "-1e-3")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "12")
|
||||
field(LOLO, "-13.2")
|
||||
field(LOW, "-12.6")
|
||||
field(HIGH, "-11.4")
|
||||
field(HIHI, "-10.8")
|
||||
field(LLSV, "MAJOR")
|
||||
field(LSV, "MINOR")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "-0.12")
|
||||
field(FLNK, "DZ:Temp1")
|
||||
}
|
||||
record(longin, "DZ:Temp1")
|
||||
{
|
||||
field(DESC, "Sensor 1 temperature")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(EGU, "Degrees C")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "100")
|
||||
field(HIGH, "45")
|
||||
field(HIHI, "55")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "2")
|
||||
field(FLNK, "DZ:Temp2")
|
||||
}
|
||||
record(longin, "DZ:Temp2")
|
||||
{
|
||||
field(DESC, "Sensor 2 temperature")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(EGU, "Degrees C")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "100")
|
||||
field(HIGH, "45")
|
||||
field(HIHI, "55")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "2")
|
||||
field(FLNK, "DZ:Temp3")
|
||||
}
|
||||
record(longin, "DZ:Temp3")
|
||||
{
|
||||
field(DESC, "Sensor 3 temperature")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(EGU, "Degrees C")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "100")
|
||||
field(HIGH, "45")
|
||||
field(HIHI, "55")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "2")
|
||||
field(FLNK, "DZ:Temp4")
|
||||
}
|
||||
record(longin, "DZ:Temp4")
|
||||
{
|
||||
field(DESC, "Sensor 4 temperature")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(EGU, "Degrees C")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "100")
|
||||
field(HIGH, "45")
|
||||
field(HIHI, "55")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "2")
|
||||
field(FLNK, "DZ:Fan1")
|
||||
}
|
||||
record(longin, "DZ:Fan1")
|
||||
{
|
||||
field(DESC, "Fan 1 speed")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(EGU, "RPM")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "2500")
|
||||
field(LOLO, "900")
|
||||
field(LOW, "1050")
|
||||
field(HIGH, "2500")
|
||||
field(HIHI, "2600")
|
||||
field(LLSV, "MAJOR")
|
||||
field(LSV, "MINOR")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "10")
|
||||
field(FLNK, "DZ:Fan2")
|
||||
}
|
||||
record(longin, "DZ:Fan2")
|
||||
{
|
||||
field(DESC, "Fan 2 speed")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(EGU, "RPM")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "2500")
|
||||
field(LOLO, "900")
|
||||
field(LOW, "1050")
|
||||
field(HIGH, "2500")
|
||||
field(HIHI, "2600")
|
||||
field(LLSV, "MAJOR")
|
||||
field(LSV, "MINOR")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "10")
|
||||
field(FLNK, "DZ:Fan3")
|
||||
}
|
||||
record(longin, "DZ:Fan3")
|
||||
{
|
||||
field(DESC, "Fan 3 speed")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(EGU, "RPM")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "2500")
|
||||
field(LOLO, "900")
|
||||
field(LOW, "1050")
|
||||
field(HIGH, "2500")
|
||||
field(HIHI, "2600")
|
||||
field(LLSV, "MAJOR")
|
||||
field(LSV, "MINOR")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "10")
|
||||
field(FLNK, "DZ:Fan4")
|
||||
}
|
||||
record(longin, "DZ:Fan4")
|
||||
{
|
||||
field(DESC, "Fan 4 speed")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(EGU, "RPM")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "2500")
|
||||
field(LOLO, "900")
|
||||
field(LOW, "1050")
|
||||
field(HIGH, "2500")
|
||||
field(HIHI, "2600")
|
||||
field(LLSV, "MAJOR")
|
||||
field(LSV, "MINOR")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "10")
|
||||
field(FLNK, "DZ:Fan5")
|
||||
}
|
||||
record(longin, "DZ:Fan5")
|
||||
{
|
||||
field(DESC, "Fan 5 speed")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(EGU, "RPM")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "2500")
|
||||
field(LOLO, "900")
|
||||
field(LOW, "1050")
|
||||
field(HIGH, "2500")
|
||||
field(HIHI, "2600")
|
||||
field(LLSV, "MAJOR")
|
||||
field(LSV, "MINOR")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "10")
|
||||
field(FLNK, "DZ:Fan6")
|
||||
}
|
||||
record(longin, "DZ:Fan6")
|
||||
{
|
||||
field(DESC, "Fan 6 speed")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(EGU, "RPM")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "2500")
|
||||
field(LOLO, "900")
|
||||
field(LOW, "1050")
|
||||
field(HIGH, "2500")
|
||||
field(HIHI, "2600")
|
||||
field(LLSV, "MAJOR")
|
||||
field(LSV, "MINOR")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "10")
|
||||
field(FLNK, "DZ:Fan7")
|
||||
}
|
||||
record(longin, "DZ:Fan7")
|
||||
{
|
||||
field(DESC, "Fan 7 speed")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(EGU, "RPM")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "2500")
|
||||
field(LOLO, "900")
|
||||
field(LOW, "1050")
|
||||
field(HIGH, "2500")
|
||||
field(HIHI, "2600")
|
||||
field(LLSV, "MAJOR")
|
||||
field(LSV, "MINOR")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "10")
|
||||
field(FLNK, "DZ:Fan8")
|
||||
}
|
||||
record(longin, "DZ:Fan8")
|
||||
{
|
||||
field(DESC, "Fan 8 speed")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(EGU, "RPM")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "2500")
|
||||
field(LOLO, "900")
|
||||
field(LOW, "1050")
|
||||
field(HIGH, "2500")
|
||||
field(HIHI, "2600")
|
||||
field(LLSV, "MAJOR")
|
||||
field(LSV, "MINOR")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "10")
|
||||
field(FLNK, "DZ:Fan9")
|
||||
}
|
||||
record(longin, "DZ:Fan9")
|
||||
{
|
||||
field(DESC, "Fan 9 speed")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(EGU, "RPM")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "2500")
|
||||
field(LOLO, "900")
|
||||
field(LOW, "1050")
|
||||
field(HIGH, "2500")
|
||||
field(HIHI, "2600")
|
||||
field(LLSV, "MAJOR")
|
||||
field(LSV, "MINOR")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HYST, "10")
|
||||
field(FLNK, "DZ:PS1status")
|
||||
}
|
||||
record(bi, "DZ:PS1status")
|
||||
{
|
||||
field(DESC, "Power supply 1 status")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(ZNAM, "Off")
|
||||
field(ONAM, "On")
|
||||
field(FLNK, "DZ:PS2status")
|
||||
}
|
||||
record(bi, "DZ:PS2status")
|
||||
{
|
||||
field(DESC, "Power supply 2 status")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(ZNAM, "Off")
|
||||
field(ONAM, "On")
|
||||
field(FLNK, "DZ:HoursOn")
|
||||
}
|
||||
record(ai, "DZ:HoursOn")
|
||||
{
|
||||
field(DESC, "Power on time")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(EGU, "Hours")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "50000")
|
||||
field(PREC, "1")
|
||||
field(FLNK, "DZ:MaxTemp")
|
||||
}
|
||||
record(longin, "DZ:MaxTemp")
|
||||
{
|
||||
field(DESC, "Maximum recorded temperature")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(EGU, "Degrees C")
|
||||
field(LOPR, "0")
|
||||
field(HOPR, "100")
|
||||
field(HIGH, "45")
|
||||
field(HIHI, "55")
|
||||
field(HSV, "MINOR")
|
||||
field(HHSV, "MAJOR")
|
||||
field(FLNK, "DZ:Serial")
|
||||
}
|
||||
record(longin, "DZ:Serial")
|
||||
{
|
||||
field(DESC, "Serial number")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(FLNK, "DZ:Name")
|
||||
}
|
||||
record(stringin, "DZ:Name")
|
||||
{
|
||||
field(DESC, "Unit name")
|
||||
field(DTYP, "Soft Channel")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
InTerminator = "\r\n";
|
||||
OutTerminator = "";
|
||||
|
||||
ps {
|
||||
out "PS\$1%{OFF|ON}";
|
||||
}
|
||||
|
||||
query {
|
||||
out "Q";
|
||||
in "Q:"
|
||||
"V3=%d,"
|
||||
"V5=%(\$1VP5.RVAL)d,"
|
||||
"V+12=%(\$1VP12.RVAL)d,"
|
||||
"V12=%(\$1VM12.RVAL)d,"
|
||||
"T1=%(\$1Temp1.VAL)d,"
|
||||
"T2=%(\$1Temp2.VAL)d,"
|
||||
"T3=%(\$1Temp3.VAL)d,"
|
||||
"T4=%(\$1Temp4.VAL)d,"
|
||||
"F1=%(\$1Fan1.VAL)d,"
|
||||
"F2=%(\$1Fan2.VAL)d,"
|
||||
"F3=%(\$1Fan3.VAL)d,"
|
||||
"F4=%(\$1Fan4.VAL)d,"
|
||||
"F5=%(\$1Fan5.VAL)d,"
|
||||
"F6=%(\$1Fan6.VAL)d,"
|
||||
"F7=%(\$1Fan7.VAL)d,"
|
||||
"F8=%(\$1Fan8.VAL)d,"
|
||||
"F9=%(\$1Fan9.VAL)d,"
|
||||
"PS1=%(\$1PS1status.VAL)d,"
|
||||
"PS2=%(\$1PS2status.VAL)d,"
|
||||
"POH=%(\$1HoursOn.VAL)g,"
|
||||
"MAXTMP=%(\$1MaxTemp.VAL)g,"
|
||||
"PS1=%*d,"
|
||||
"PS2=%*d,"
|
||||
"MSG=%*d,"
|
||||
"SW=%*d,"
|
||||
"SN=%(\$1Serial.VAL)d,"
|
||||
"UN=%(\$1Name.VAL)39[^,],";
|
||||
# in ";";
|
||||
out "%d\n";
|
||||
@mismatch {out "mismatch\n"; }
|
||||
ExtraInput = Ignore;
|
||||
}
|
||||
}
|
||||
|
||||
set startup {
|
||||
var streamDebug 1
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:VP3.PROC 1}
|
||||
assure "Q"
|
||||
send "Q:V3=0,V5=0,V+12=0,V12=0,T1=38,T2=40,T3=43,T4=45,F1=1350,F2=1361,F3=1373,F4=1384,F5=1396,F6=1407,F7=1419,F8=1430,F9=1442,PS1=0,PS2=0,POH=23.5,MAXTMP=45,PS1=0,PS2=0,MSG=0,SW=1,SN=8765,UN=APEX1,IP=128.12\r\n"
|
||||
assure "0\n"
|
||||
finish
|
40
streamApp/tests/testOutTerminators
Executable file
40
streamApp/tests/testOutTerminators
Executable file
@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (stringout, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto test1 device")
|
||||
}
|
||||
record (stringout, "DZ:test2")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto test2 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
test1 {out "%s";}
|
||||
Terminator = "S" CR LF;
|
||||
test2 { out "%s";}
|
||||
}
|
||||
|
||||
set startup {
|
||||
asynOctetSetOutputEos device -1 "A\n"
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
ioccmd {dbpf DZ:test1 "string 1"}
|
||||
assure "string 1A\n"
|
||||
ioccmd {dbpf DZ:test2 "string 2"}
|
||||
assure "string 2S\r\n"
|
||||
|
||||
finish
|
57
streamApp/tests/testPINI
Executable file
57
streamApp/tests/testPINI
Executable file
@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
foreach rtype {ao bo mbbo mbboDirect longout stringout calcout} {
|
||||
append records "
|
||||
record ($rtype, \"DZ:$rtype\")
|
||||
{
|
||||
field (DTYP, \"stream\")
|
||||
field (OUT, \"@test.proto init($rtype) device\")
|
||||
field (PINI, \"YES\")
|
||||
field (VAL, \"0\")
|
||||
}
|
||||
"
|
||||
}
|
||||
foreach rtype {ai bi mbbi mbbiDirect longin stringin waveform} {
|
||||
append records "
|
||||
record ($rtype, \"DZ:$rtype\")
|
||||
{
|
||||
field (DTYP, \"stream\")
|
||||
field (INP, \"@test.proto init($rtype) device\")
|
||||
field (PINI, \"YES\")
|
||||
}
|
||||
"
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
init {out "init \$1"; }
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
assure "init ao\n" \
|
||||
"init bo\n" \
|
||||
"init mbbo\n" \
|
||||
"init mbboDirect\n" \
|
||||
"init longout\n" \
|
||||
"init stringout\n" \
|
||||
"init ai\n" \
|
||||
"init bi\n" \
|
||||
"init mbbi\n" \
|
||||
"init mbbiDirect\n" \
|
||||
"init longin\n" \
|
||||
"init stringin\n" \
|
||||
"init calcout\n" \
|
||||
"init waveform\n" \
|
||||
|
||||
finish
|
41
streamApp/tests/testParallelAccess
Executable file
41
streamApp/tests/testParallelAccess
Executable file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (ao, "DZ:slow")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto slow device")
|
||||
}
|
||||
record (ao, "DZ:fast")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto fast device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
slow { out "slow start"; wait 1000; out "slow finished";}
|
||||
fast { out "fast"; }
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:slow 1}
|
||||
ioccmd {dbpf DZ:fast 1}
|
||||
assure "slow start\n"
|
||||
assure "slow finished\n"
|
||||
assure "fast\n"
|
||||
|
||||
finish
|
33
streamApp/tests/testPercent
Executable file
33
streamApp/tests/testPercent
Executable file
@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (longout, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto test1 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
test1 {out "\%\e%d\e\e\%";}
|
||||
}
|
||||
|
||||
set startup {
|
||||
var streamDebug 1
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1 1}
|
||||
assure "%\0331\033\033%\n"
|
||||
|
||||
finish
|
55
streamApp/tests/testPerformance
Executable file
55
streamApp/tests/testPerformance
Executable file
@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (waveform, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (FTVL, "DOUBLE")
|
||||
field (NELM, "1048576")
|
||||
field (INP, "@test.proto test1 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
replyTimeout =600000;
|
||||
Terminator = LF;
|
||||
Separator = ",";
|
||||
test1 {in "%f"; out "%(NORD)d";}
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
set message "3.1415"
|
||||
set size 1
|
||||
set timeout 600000
|
||||
|
||||
startioc
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "$message\n"
|
||||
assure "$size\n"
|
||||
|
||||
ioccmd {var streamDebug 0}
|
||||
for {set log 1} {$log <= 21} {incr log} {
|
||||
set output "$message\n"
|
||||
set starttime [clock clicks]
|
||||
send $output
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
assure "$size\n"
|
||||
set duration [expr [clock clicks] - $starttime]
|
||||
set performance($size) [expr $duration*1.0/$size]
|
||||
puts [format "size %7d duration: %8d time/element: %6.1f" $size $duration $performance($size)]
|
||||
if {$performance($size) > $performance(1)} {incr faults}
|
||||
set message "$message,$message"
|
||||
set size [expr $size*2]
|
||||
}
|
||||
|
||||
finish
|
40
streamApp/tests/testQuotes
Executable file
40
streamApp/tests/testQuotes
Executable file
@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (stringout, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto test1 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
test1 {
|
||||
out "Escaped \"double\" quotes";
|
||||
out 'Escaped \'single\' quotes';
|
||||
out "Single 'quotes' in double quotes";
|
||||
out 'Double "quotes" in single quotes'; }
|
||||
}
|
||||
|
||||
set startup {
|
||||
var streamDebug 1
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1 "X"}
|
||||
assure "Escaped \"double\" quotes\n"
|
||||
assure "Escaped 'single' quotes\n"
|
||||
assure "Single 'quotes' in double quotes\n"
|
||||
assure "Double \"quotes\" in single quotes\n"
|
||||
|
||||
finish
|
254
streamApp/tests/testRaw
Executable file
254
streamApp/tests/testRaw
Executable file
@ -0,0 +1,254 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (longout, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto test1 device")
|
||||
}
|
||||
record (longin, "DZ:test2")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test2 device")
|
||||
}
|
||||
record (longin, "DZ:test3")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test3 device")
|
||||
}
|
||||
record (longin, "DZ:test4")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test4 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
OutTerminator = LF;
|
||||
MaxInput = 4;
|
||||
test1 {
|
||||
out "%r"; out "%.1r"; out "%.2r"; out "%.3r"; out "%.4r"; out "%.5r";
|
||||
out "%#r"; out "%#.1r"; out "%#.2r"; out "%#.3r"; out "%#.4r"; out "%#.5r";
|
||||
out "%r"; out "%1r"; out "%2r"; out "%3r"; out "%4r"; out "%5r";
|
||||
out "%0r"; out "%01r"; out "%02r"; out "%03r"; out "%04r"; out "%05r";
|
||||
out "%#0r"; out "%#01r"; out "%#02r"; out "%#03r"; out "%#04r"; out "%#05r";
|
||||
};
|
||||
test2 {
|
||||
in "%04.4r";
|
||||
out "%08x";
|
||||
}
|
||||
test3{
|
||||
in "%#3r\?";
|
||||
out "%08x";
|
||||
}
|
||||
test4{
|
||||
in "%#03r\?";
|
||||
out "%08x";
|
||||
}
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1 0}
|
||||
assure "\x00\n"
|
||||
assure "\x00\n"
|
||||
assure "\x00\x00\n"
|
||||
assure "\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\x00\n"
|
||||
assure "\x00\n"
|
||||
assure "\x00\n"
|
||||
assure "\x00\x00\n"
|
||||
assure "\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\x00\n"
|
||||
assure "\x00\n"
|
||||
assure "\x00\n"
|
||||
assure "\x00\x00\n"
|
||||
assure "\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\x00\n"
|
||||
assure "\x00\n"
|
||||
assure "\x00\n"
|
||||
assure "\x00\x00\n"
|
||||
assure "\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\x00\n"
|
||||
assure "\x00\n"
|
||||
assure "\x00\n"
|
||||
assure "\x00\x00\n"
|
||||
assure "\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\x00\n"
|
||||
|
||||
ioccmd {dbpf DZ:test1 1}
|
||||
assure "\x01\n"
|
||||
assure "\x01\n"
|
||||
assure "\x00\x01\n"
|
||||
assure "\x00\x00\x01\n"
|
||||
assure "\x00\x00\x00\x01\n"
|
||||
assure "\x00\x00\x00\x00\x01\n"
|
||||
assure "\x01\n"
|
||||
assure "\x01\n"
|
||||
assure "\x01\x00\n"
|
||||
assure "\x01\x00\x00\n"
|
||||
assure "\x01\x00\x00\x00\n"
|
||||
assure "\x01\x00\x00\x00\x00\n"
|
||||
assure "\x01\n"
|
||||
assure "\x01\n"
|
||||
assure "\x00\x01\n"
|
||||
assure "\x00\x00\x01\n"
|
||||
assure "\x00\x00\x00\x01\n"
|
||||
assure "\x00\x00\x00\x00\x01\n"
|
||||
assure "\x01\n"
|
||||
assure "\x01\n"
|
||||
assure "\x00\x01\n"
|
||||
assure "\x00\x00\x01\n"
|
||||
assure "\x00\x00\x00\x01\n"
|
||||
assure "\x00\x00\x00\x00\x01\n"
|
||||
assure "\x01\n"
|
||||
assure "\x01\n"
|
||||
assure "\x01\x00\n"
|
||||
assure "\x01\x00\x00\n"
|
||||
assure "\x01\x00\x00\x00\n"
|
||||
assure "\x01\x00\x00\x00\x00\n"
|
||||
|
||||
ioccmd {dbpf DZ:test1 -1}
|
||||
assure "\xff\n"
|
||||
assure "\xff\n"
|
||||
assure "\xff\xff\n"
|
||||
assure "\xff\xff\xff\n"
|
||||
assure "\xff\xff\xff\xff\n"
|
||||
assure "\xff\xff\xff\xff\xff\n"
|
||||
assure "\xff\n"
|
||||
assure "\xff\n"
|
||||
assure "\xff\xff\n"
|
||||
assure "\xff\xff\xff\n"
|
||||
assure "\xff\xff\xff\xff\n"
|
||||
assure "\xff\xff\xff\xff\xff\n"
|
||||
assure "\xff\n"
|
||||
assure "\xff\n"
|
||||
assure "\xff\xff\n"
|
||||
assure "\xff\xff\xff\n"
|
||||
assure "\xff\xff\xff\xff\n"
|
||||
assure "\xff\xff\xff\xff\xff\n"
|
||||
assure "\xff\n"
|
||||
assure "\xff\n"
|
||||
assure "\x00\xff\n"
|
||||
assure "\x00\x00\xff\n"
|
||||
assure "\x00\x00\x00\xff\n"
|
||||
assure "\x00\x00\x00\x00\xff\n"
|
||||
assure "\xff\n"
|
||||
assure "\xff\n"
|
||||
assure "\xff\x00\n"
|
||||
assure "\xff\x00\x00\n"
|
||||
assure "\xff\x00\x00\x00\n"
|
||||
assure "\xff\x00\x00\x00\x00\n"
|
||||
|
||||
ioccmd {dbpf DZ:test1 269554195}
|
||||
assure "\x13\n"
|
||||
assure "\x13\n"
|
||||
assure "\x12\x13\n"
|
||||
assure "\x11\x12\x13\n"
|
||||
assure "\x10\x11\x12\x13\n"
|
||||
assure "\x00\x10\x11\x12\x13\n"
|
||||
assure "\x13\n"
|
||||
assure "\x13\n"
|
||||
assure "\x13\x12\n"
|
||||
assure "\x13\x12\x11\n"
|
||||
assure "\x13\x12\x11\x10\n"
|
||||
assure "\x13\x12\x11\x10\x00\n"
|
||||
assure "\x13\n"
|
||||
assure "\x13\n"
|
||||
assure "\x00\x13\n"
|
||||
assure "\x00\x00\x13\n"
|
||||
assure "\x00\x00\x00\x13\n"
|
||||
assure "\x00\x00\x00\x00\x13\n"
|
||||
assure "\x13\n"
|
||||
assure "\x13\n"
|
||||
assure "\x00\x13\n"
|
||||
assure "\x00\x00\x13\n"
|
||||
assure "\x00\x00\x00\x13\n"
|
||||
assure "\x00\x00\x00\x00\x13\n"
|
||||
assure "\x13\n"
|
||||
assure "\x13\n"
|
||||
assure "\x13\x00\n"
|
||||
assure "\x13\x00\x00\n"
|
||||
assure "\x13\x00\x00\x00\n"
|
||||
assure "\x13\x00\x00\x00\x00\n"
|
||||
|
||||
ioccmd {dbpf DZ:test1 -559038737}
|
||||
assure "\xef\n"
|
||||
assure "\xef\n"
|
||||
assure "\xbe\xef\n"
|
||||
assure "\xad\xbe\xef\n"
|
||||
assure "\xde\xad\xbe\xef\n"
|
||||
assure "\xff\xde\xad\xbe\xef\n"
|
||||
assure "\xef\n"
|
||||
assure "\xef\n"
|
||||
assure "\xef\xbe\n"
|
||||
assure "\xef\xbe\xad\n"
|
||||
assure "\xef\xbe\xad\xde\n"
|
||||
assure "\xef\xbe\xad\xde\xff\n"
|
||||
assure "\xef\n"
|
||||
assure "\xef\n"
|
||||
assure "\xff\xef\n"
|
||||
assure "\xff\xff\xef\n"
|
||||
assure "\xff\xff\xff\xef\n"
|
||||
assure "\xff\xff\xff\xff\xef\n"
|
||||
assure "\xef\n"
|
||||
assure "\xef\n"
|
||||
assure "\x00\xef\n"
|
||||
assure "\x00\x00\xef\n"
|
||||
assure "\x00\x00\x00\xef\n"
|
||||
assure "\x00\x00\x00\x00\xef\n"
|
||||
assure "\xef\n"
|
||||
assure "\xef\n"
|
||||
assure "\xef\x00\n"
|
||||
assure "\xef\x00\x00\n"
|
||||
assure "\xef\x00\x00\x00\n"
|
||||
assure "\xef\x00\x00\x00\x00\n"
|
||||
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "\x01\x02\x03\x04"
|
||||
assure "01020304\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "\xde\xad\xbe\xef"
|
||||
assure "deadbeef\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "\x00\x00\x00\x00"
|
||||
assure "00000000\n"
|
||||
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "\x04\x03\x02\x01"
|
||||
assure "00020304\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "\xde\xad\xbe\xef"
|
||||
assure "ffbeadde\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "\x00\x00\x00\x00"
|
||||
assure "00000000\n"
|
||||
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "\x04\x03\x02\x01"
|
||||
assure "00020304\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "\xde\xad\xbe\xef"
|
||||
assure "00beadde\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "\x00\x00\x00\x00"
|
||||
assure "00000000\n"
|
||||
|
||||
|
||||
finish
|
61
streamApp/tests/testRawFloat
Executable file
61
streamApp/tests/testRawFloat
Executable file
@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (ao, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto test1 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
test1 {out "%R"; out "%#R"; out "%4R"; out "%#4R"; out "%8R"; out "%#8R";}
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1 "0"}
|
||||
assure "\x00\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\x00\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\x00\x00\x00\x00\n"
|
||||
|
||||
ioccmd {dbpf DZ:test1 "1"}
|
||||
assure "\x3f\x80\x00\x00\n"
|
||||
assure "\x00\x00\x80\x3f\n"
|
||||
assure "\x3f\x80\x00\x00\n"
|
||||
assure "\x00\x00\x80\x3f\n"
|
||||
assure "\x3f\xf0\x00\x00\x00\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\x00\x00\xf0\x3f\n"
|
||||
|
||||
ioccmd {dbpf DZ:test1 "-1"}
|
||||
assure "\xbf\x80\x00\x00\n"
|
||||
assure "\x00\x00\x80\xbf\n"
|
||||
assure "\xbf\x80\x00\x00\n"
|
||||
assure "\x00\x00\x80\xbf\n"
|
||||
assure "\xbf\xf0\x00\x00\x00\x00\x00\x00\n"
|
||||
assure "\x00\x00\x00\x00\x00\x00\xf0\xbf\n"
|
||||
|
||||
ioccmd {dbpf DZ:test1 "3.1415"}
|
||||
assure "\x40\x49\x0e\x56\n"
|
||||
assure "\x56\x0e\x49\x40\n"
|
||||
assure "\x40\x49\x0e\x56\n"
|
||||
assure "\x56\x0e\x49\x40\n"
|
||||
assure "\x40\x09\x21\xca\xc0\x83\x12\x6f\n"
|
||||
assure "\x6f\x12\x83\xc0\xca\x21\x09\x40\n"
|
||||
|
||||
finish
|
76
streamApp/tests/testSeverityAndStatus
Executable file
76
streamApp/tests/testSeverityAndStatus
Executable file
@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (stringin, "DZ:readTimeout")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto read device")
|
||||
}
|
||||
record (bo, "DZ:echo")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto print(DZ:readTimeout) device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
read {out "Give me input"; in "%s";}
|
||||
print {out "Text:'%(\$1.VAL)s' SEVR=%(\$1.SEVR)d STAT=%(\$1.STAT)d";}
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
# reply timeout
|
||||
ioccmd {dbpf DZ:readTimeout.PROC 1}
|
||||
assure "Give me input\n"
|
||||
after 1100
|
||||
ioccmd {dbpf DZ:echo.PROC 1}
|
||||
ioccmd {dbpr DZ:echo 1}
|
||||
assure "Text:'' SEVR=3 STAT=10\n"
|
||||
|
||||
# read timeout
|
||||
ioccmd {dbpf DZ:readTimeout.PROC 1}
|
||||
assure "Give me input\n"
|
||||
send "Trulala"
|
||||
after 200
|
||||
ioccmd {dbpf DZ:echo.PROC 1}
|
||||
assure "Text:'Trulala' SEVR=3 STAT=1\n"
|
||||
|
||||
# reply timeout again, old input stays
|
||||
ioccmd {dbpf DZ:readTimeout.PROC 1}
|
||||
assure "Give me input\n"
|
||||
after 1100
|
||||
ioccmd {dbpf DZ:echo.PROC 1}
|
||||
assure "Text:'Trulala' SEVR=3 STAT=10\n"
|
||||
|
||||
# mismatch, partially parsed
|
||||
ioccmd {dbpf DZ:readTimeout.PROC 1}
|
||||
assure "Give me input\n"
|
||||
send "bla extra\n"
|
||||
after 200
|
||||
ioccmd {dbpf DZ:echo.PROC 1}
|
||||
assure "Text:'bla' SEVR=3 STAT=12\n"
|
||||
|
||||
# success
|
||||
ioccmd {dbpf DZ:readTimeout.PROC 1}
|
||||
assure "Give me input\n"
|
||||
send "Input\n"
|
||||
after 200
|
||||
ioccmd {dbpf DZ:echo.PROC 1}
|
||||
assure "Text:'Input' SEVR=0 STAT=0\n"
|
||||
|
||||
|
||||
|
||||
finish
|
32
streamApp/tests/testSkeleton
Normal file
32
streamApp/tests/testSkeleton
Normal file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (stringout, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto test1 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
test1 {out "%s";}
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1 "string 1"}
|
||||
assure "string 1\n"
|
||||
|
||||
finish
|
81
streamApp/tests/testSpyOnLongInput
Executable file
81
streamApp/tests/testSpyOnLongInput
Executable file
@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (stringin, "DZ:request")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto read device")
|
||||
}
|
||||
record (stringout, "DZ:echo")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (DOL, "DZ:request")
|
||||
field (OMSL, "closed_loop")
|
||||
field (OUT, "@test.proto printstr device")
|
||||
}
|
||||
record (stringin, "DZ:spy")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto readintr device")
|
||||
field (SCAN, "I/O Intr")
|
||||
field (FLNK, "DZ:count")
|
||||
}
|
||||
record (calc, "DZ:count")
|
||||
{
|
||||
field (INPA, "DZ:count")
|
||||
field (CALC, "A+1")
|
||||
}
|
||||
record (longout, "DZ:countout")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (DOL, "DZ:count")
|
||||
field (OMSL, "closed_loop")
|
||||
field (OUT, "@test.proto printnum device")
|
||||
}
|
||||
record (stringout, "DZ:stringout")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (DOL, "DZ:spy")
|
||||
field (OMSL, "closed_loop")
|
||||
field (OUT, "@test.proto printstr device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
read {extraInput=ignore; InTerminator = ""; out "Give input"; in "%/.*253.*/"; }
|
||||
readintr {extraInput=ignore; in "%39c"; }
|
||||
printnum {out "%d";}
|
||||
printstr {out "%s";}
|
||||
}
|
||||
|
||||
set startup {
|
||||
var streamDebug 1
|
||||
}
|
||||
|
||||
set debug 0
|
||||
set rep 500
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf "DZ:request.PROC" 1}
|
||||
assure "Give input\n"
|
||||
for {set i 1} {$i <= $rep} {incr i} {
|
||||
append output "This is line $i.\n"
|
||||
}
|
||||
send $output
|
||||
after 2000
|
||||
ioccmd {dbpf "DZ:echo.PROC" 1}
|
||||
assure "This is line 253.\n"
|
||||
ioccmd {dbpf "DZ:stringout.PROC" 1}
|
||||
assure "This is line $rep.\n"
|
||||
ioccmd {dbpf "DZ:countout.PROC" 1}
|
||||
assure "$rep\n"
|
||||
|
||||
finish
|
65
streamApp/tests/testStreamBuffer
Executable file
65
streamApp/tests/testStreamBuffer
Executable file
@ -0,0 +1,65 @@
|
||||
rm -f test.*
|
||||
|
||||
cat > test.cc << EOF
|
||||
#include <StreamBuffer.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
int main () {
|
||||
StreamBuffer haystack = "12345abc123xyz123";
|
||||
StreamBuffer needle = "1n4m6p7q";
|
||||
needle.remove(2,4);
|
||||
assert (needle.startswith("1n7q"));
|
||||
needle.append("2x3y");
|
||||
assert (needle.startswith("1n7q2x3y"));
|
||||
needle.remove(4);
|
||||
assert (needle.startswith("2x3y"));
|
||||
needle.remove(1,1);
|
||||
assert (needle.startswith("23y"));
|
||||
needle.truncate(-1);
|
||||
assert (needle.startswith("23"));
|
||||
assert (haystack.find(needle) == 1);
|
||||
assert (haystack.find(needle, 2) == 9);
|
||||
assert (haystack.find(needle, -5) == 15);
|
||||
assert (haystack.find("23", -5) == 15);
|
||||
assert (haystack.find((char*)NULL, 10) == 10);
|
||||
assert (haystack.find(needle, -1) == -1);
|
||||
assert (haystack.find(needle, 100) == -1);
|
||||
assert (haystack.find(needle, 0) == 1);
|
||||
assert (haystack.find(needle, -100) == 1);
|
||||
haystack.set("12345xy67890xy");
|
||||
needle.set("xy");
|
||||
assert (haystack.find(needle) == 5);
|
||||
needle.set("x");
|
||||
assert (haystack.find(needle) == 5);
|
||||
haystack.set("12345\n67890\n");
|
||||
needle.set("\n");
|
||||
assert (haystack.find(needle) == 5);
|
||||
haystack.set("12341234567890\n");
|
||||
needle.set("2345");
|
||||
assert (haystack.find(needle) == 5);
|
||||
needle="7890";
|
||||
assert (haystack.find(needle) == 10);
|
||||
needle.append('\0');
|
||||
assert (haystack.find(needle) == -1);
|
||||
haystack.clear();
|
||||
assert (haystack.find(needle) == -1);
|
||||
haystack.set("deadbeef");
|
||||
needle.clear();
|
||||
assert (haystack.find(needle) == 0);
|
||||
haystack.clear();
|
||||
assert (haystack.find(needle) == 0);
|
||||
haystack.reserve(10000);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
g++ -I ../../src ../../src/O.$EPICS_HOST_ARCH/StreamBuffer.o test.cc -o test.exe
|
||||
|
||||
test.exe
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
echo -e "\033[31;7mTest failed.\033[0m"
|
||||
exit 1
|
||||
fi
|
||||
rm test.*
|
||||
echo -e "\033[32mTest passed.\033[0m"
|
124
streamApp/tests/testString
Executable file
124
streamApp/tests/testString
Executable file
@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (stringin, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test1 device")
|
||||
}
|
||||
record (stringin, "DZ:test2")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test2 device")
|
||||
}
|
||||
record (stringin, "DZ:test3")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test3 device")
|
||||
}
|
||||
record (stringin, "DZ:test4")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test4 device")
|
||||
}
|
||||
record (stringin, "DZ:test5")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test5 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
extraInput=ignore;
|
||||
@mismatch {out "mismatch";}
|
||||
test1 {in "%s%(DESC) #s"; out "%s|%(DESC)s" }
|
||||
test2 {in "% s%(DESC) #s"; out "%s|%(DESC)s" }
|
||||
test3 {in "%#s%(DESC) #s"; out "%s|%(DESC)s" }
|
||||
test4 {in "%# s%(DESC) #s"; out "%s|%(DESC)s" }
|
||||
test5 {in "% #s%(DESC) #s"; out "%s|%(DESC)s" }
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "foobar\n"
|
||||
assure "foobar|\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send " foobar \n"
|
||||
assure "foobar| \n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send " foo bar \n"
|
||||
assure "foo| bar \n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send " \n"
|
||||
assure "|\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "ThisIsAVeryLongInputStringThatExceedsFouryCharacters right?\n"
|
||||
assure "ThisIsAVeryLongInputStringThatExceedsFo| right?\n"
|
||||
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "foobar\n"
|
||||
assure "foobar|\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send " foobar \n"
|
||||
assure " foobar| \n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send " foo bar \n"
|
||||
assure " foo| bar \n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send " \n"
|
||||
assure " |\n"
|
||||
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "foobar\n"
|
||||
assure "foobar|\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send " foobar \n"
|
||||
assure "foobar |\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send " foo bar \n"
|
||||
assure "foo bar |\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send " \n"
|
||||
assure "|\n"
|
||||
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "foobar\n"
|
||||
assure "foobar|\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send " foobar \n"
|
||||
assure " foobar |\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send " foo bar \n"
|
||||
assure " foo bar |\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send " \n"
|
||||
assure " |\n"
|
||||
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "foobar\n"
|
||||
assure "foobar|\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send " foobar \n"
|
||||
assure " foobar |\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send " foo bar \n"
|
||||
assure " foo bar |\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send " \n"
|
||||
assure " |\n"
|
||||
|
||||
finish
|
||||
|
152
streamApp/tests/testTimestamp
Executable file
152
streamApp/tests/testTimestamp
Executable file
@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (ao, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (OUT, "@test.proto test1 device")
|
||||
}
|
||||
record (ai, "DZ:test2")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test2 device")
|
||||
}
|
||||
record (ai, "DZ:test3")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test3 device")
|
||||
}
|
||||
record (ai, "DZ:test4")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test4 device")
|
||||
}
|
||||
record (ai, "DZ:test5")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test5 device")
|
||||
}
|
||||
record (ai, "DZ:test6")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test6 device")
|
||||
}
|
||||
record (ai, "DZ:test7")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto test7 device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
test1 {out "%T(%d.%m.%Y %H:%M:%.2S %z)"; }
|
||||
test2 {in "%T"; out "%.0f %T"; }
|
||||
test3 {in "%(TIME)T(%Ed. %B %Y %H:%M:%.S) %f"; out "%(TIME)T(%d.%m.%Y %H:%M:%.2S %z)"; }
|
||||
test4 {in "%(TIME)T(%c) %f"; out "%(TIME)T(%a %d.%m.%Y %H:%M:%.2S %z)"; }
|
||||
test5 {in "%T(%H %p)"; out "%T(%H)"; }
|
||||
test6 {in "%T(%p %H)"; out "%T(%H)"; }
|
||||
test7 {in "%T(%d.%m.%Y %T %z)"; out "%T(%d.%m.%Y %T %z) %.6f"; }
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
package require Epics
|
||||
proc checkTS {pv timestamp} {
|
||||
global faults
|
||||
pvget $pv
|
||||
array set PV [pvinfo $pv]
|
||||
if {$PV(TIME) != $timestamp} {
|
||||
puts "expected timestamp: $timestamp"
|
||||
puts "received timestamp: $PV(TIME)"
|
||||
incr faults
|
||||
}
|
||||
}
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1 1044068706.789}
|
||||
assure "01.02.2003 04:05:06.79 +0100\n"
|
||||
|
||||
ioccmd {dbpf DZ:test1 1057025106.789}
|
||||
assure "01.07.2003 04:05:06.79 +0200\n"
|
||||
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "2003-02-01 04:05:06\n"
|
||||
assure "1044068706 2003-02-01 04:05:06\n";
|
||||
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "1. February 2003 04:05:06.789 3.1415\n"
|
||||
assure "01.02.2003 04:05:06.79 +0100\n";
|
||||
checkTS DZ:test3 "02/01/03 04:05:06.789000000"
|
||||
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "1. July 2003 04:05:06.789123 3.1415\n"
|
||||
assure "01.07.2003 04:05:06.79 +0200\n";
|
||||
checkTS DZ:test3 "07/01/03 04:05:06.789123000"
|
||||
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "mon jan 2 04:05:06 2003 3.1415\n"
|
||||
assure "Thu 02.01.2003 04:05:06.00 +0100\n";
|
||||
checkTS DZ:test4 "01/02/03 04:05:06.000000000"
|
||||
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "12 a\n"
|
||||
assure "00\n";
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "01 a\n"
|
||||
assure "01\n";
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "2 a\n"
|
||||
assure "02\n";
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "11 a\n"
|
||||
assure "11\n";
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "12 p\n"
|
||||
assure "12\n";
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "01 p\n"
|
||||
assure "13\n";
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "11 p\n"
|
||||
assure "23\n";
|
||||
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send "am 12\n"
|
||||
assure "00\n";
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send "Am 01\n"
|
||||
assure "01\n";
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send "aM 2\n"
|
||||
assure "02\n";
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send "AM 11\n"
|
||||
assure "11\n";
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send "p 12\n"
|
||||
assure "12\n";
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send "P 01\n"
|
||||
assure "13\n";
|
||||
ioccmd {dbpf DZ:test6.PROC 1}
|
||||
send "PM 11\n"
|
||||
assure "23\n";
|
||||
|
||||
ioccmd {dbpf DZ:test7.PROC 1}
|
||||
send "1.2.2010 12:56:32 +0000\n"
|
||||
assure "01.02.2010 13:56:32 +0100 1265028992.000000\n";
|
||||
ioccmd {dbpf DZ:test7.PROC 1}
|
||||
send "1.7.2010 12:56:32 +0000\n"
|
||||
assure "01.07.2010 14:56:32 +0200 1277988992.000000\n";
|
||||
finish
|
56
streamApp/tests/testWaage
Executable file
56
streamApp/tests/testWaage
Executable file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
|
||||
record (bi, "DZ:sign")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (INP, "@test.proto m(DZ:weight.A) device")
|
||||
}
|
||||
|
||||
record (calc, "DZ:weight")
|
||||
{
|
||||
field (INPB, "DZ:sign")
|
||||
field (CALC, "B?A:-A")
|
||||
field (FLNK, "DZ:out")
|
||||
}
|
||||
|
||||
record (ao, "DZ:out")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (DOL, "DZ:weight")
|
||||
field (OMSL, "closed_loop")
|
||||
field (OUT, "@test.proto out device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
m {out "w"; in "%*/ */%{-|}%(\$1)f Kg";}
|
||||
out {out "%.2f";}
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:sign.PROC 1}
|
||||
assure "w\n"
|
||||
send " - 15.20 Kg\n"
|
||||
assure "-15.20\n"
|
||||
|
||||
ioccmd {dbpf DZ:sign.PROC 1}
|
||||
assure "w\n"
|
||||
send " 15.00 Kg\n"
|
||||
assure "15.00\n"
|
||||
|
||||
finish
|
124
streamApp/tests/testWaveform
Executable file
124
streamApp/tests/testWaveform
Executable file
@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env tclsh
|
||||
source streamtestlib.tcl
|
||||
|
||||
# Define records, protocol and startup (text goes to files)
|
||||
# The asynPort "device" is connected to a network TCP socket
|
||||
# Talk to the socket with send/receive/assure
|
||||
# Send commands to the ioc shell with ioccmd
|
||||
|
||||
set records {
|
||||
record (waveform, "DZ:test1")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (FTVL, "DOUBLE")
|
||||
field (NELM, "3")
|
||||
field (INP, "@test.proto testd device")
|
||||
}
|
||||
record (waveform, "DZ:test2")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (FTVL, "FLOAT")
|
||||
field (NELM, "3")
|
||||
field (INP, "@test.proto testd device")
|
||||
}
|
||||
record (waveform, "DZ:test3")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (FTVL, "LONG")
|
||||
field (NELM, "3")
|
||||
field (INP, "@test.proto testi device")
|
||||
}
|
||||
record (waveform, "DZ:test4")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (FTVL, "SHORT")
|
||||
field (NELM, "3")
|
||||
field (INP, "@test.proto testi device")
|
||||
}
|
||||
record (waveform, "DZ:test5")
|
||||
{
|
||||
field (DTYP, "stream")
|
||||
field (FTVL, "STRING")
|
||||
field (NELM, "3")
|
||||
field (INP, "@test.proto tests device")
|
||||
}
|
||||
}
|
||||
|
||||
set protocol {
|
||||
Terminator = LF;
|
||||
testd {
|
||||
Separator = ",";
|
||||
@mismatch {out "mismatch after %(NORD)d elements: %.1f\n"}
|
||||
in "text %f end"; out "%(NORD)d elements: %.1f";
|
||||
}
|
||||
testi {
|
||||
Separator = "\_";
|
||||
@mismatch {out "mismatch after %(NORD)d elements: %i\n"}
|
||||
in "%3i\_"; out "%(NORD)d elements: %i";
|
||||
}
|
||||
tests {
|
||||
Separator = "\_...\_";
|
||||
@mismatch {out "mismatch after %(NORD)d elements: %s\n"}
|
||||
in "%s\_"; out "%(NORD)d elements: %s";
|
||||
}
|
||||
}
|
||||
|
||||
set startup {
|
||||
}
|
||||
|
||||
set debug 0
|
||||
|
||||
startioc
|
||||
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "text 1.0,2.0,3.0 end\n"
|
||||
assure "3 elements: 1.0,2.0,3.0\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "text 3, 2, 1 end\n"
|
||||
assure "3 elements: 3.0,2.0,1.0\n"
|
||||
ioccmd {dbpf DZ:test1.PROC 1}
|
||||
send "text 7 end\n"
|
||||
assure "1 elements: 7.0\n"
|
||||
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "text 1.0,2.0,3.0 end\n"
|
||||
assure "3 elements: 1.0,2.0,3.0\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "text 3, 2, 1 end\n"
|
||||
assure "3 elements: 3.0,2.0,1.0\n"
|
||||
ioccmd {dbpf DZ:test2.PROC 1}
|
||||
send "text 7 end\n"
|
||||
assure "1 elements: 7.0\n"
|
||||
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "1 2 3\n"
|
||||
assure "3 elements: 1 2 3\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send " 3 2 1 \n"
|
||||
assure "3 elements: 3 2 1\n"
|
||||
ioccmd {dbpf DZ:test3.PROC 1}
|
||||
send "12345\n"
|
||||
assure "2 elements: 123 45\n"
|
||||
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "1 2 3\n"
|
||||
assure "3 elements: 1 2 3\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send " 3 2 1 \n"
|
||||
assure "3 elements: 3 2 1\n"
|
||||
ioccmd {dbpf DZ:test4.PROC 1}
|
||||
send "12345\n"
|
||||
assure "2 elements: 123 45\n"
|
||||
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send "1...2...3\n"
|
||||
assure "1 elements: 1...2...3\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send " 3 ... 2 ... 1\n"
|
||||
assure "3 elements: 3 ... 2 ... 1\n"
|
||||
ioccmd {dbpf DZ:test5.PROC 1}
|
||||
send " 7 \n"
|
||||
assure "1 elements: 7\n"
|
||||
|
||||
|
||||
finish
|
19
streamApp/tests/testall
Executable file
19
streamApp/tests/testall
Executable file
@ -0,0 +1,19 @@
|
||||
rm -f test.* *.out *.ioclog StreamDebug.log
|
||||
for i in test*
|
||||
do
|
||||
if [ $i != testall -a -x $i ]
|
||||
then
|
||||
echo $i "$@"
|
||||
if ! $i "$@"
|
||||
then
|
||||
echo -e "\033[31;7mFailed.\033[0m"
|
||||
(( fail+=1 ))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$fail" ]
|
||||
then echo -e "\033[31;7m$fail tests failed\033[0m"
|
||||
else echo -e "\033[32;7mAll tests passed.\033[0m"
|
||||
fi
|
||||
exit $fail
|
Reference in New Issue
Block a user