Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
75aa267875 | |||
7dda6ca773 | |||
1378a9fcbb | |||
4d3672994d | |||
967539c4e1 | |||
f072c217f3 | |||
a60ffd685f | |||
0803c94c79 | |||
b03726903d | |||
afe8cc9a3e | |||
277635c65f | |||
4180bbbdd9 | |||
d683969556 | |||
a62d4d1a40 | |||
aadecf1853 | |||
f172f3d0a0 | |||
08ac900eda | |||
53caf69f3a | |||
3eac2b804d | |||
9b9e7bf722 |
@ -69,7 +69,7 @@ class MyInterface : StreamBusInterface
|
|||||||
bool <a href="#lock">lockRequest</a>(unsigned long lockTimeout_ms);
|
bool <a href="#lock">lockRequest</a>(unsigned long lockTimeout_ms);
|
||||||
bool <a href="#lock">unlock</a>();
|
bool <a href="#lock">unlock</a>();
|
||||||
bool <a href="#write">writeRequest</a>(const void* output, size_t size, unsigned long writeTimeout_ms);
|
bool <a href="#write">writeRequest</a>(const void* output, size_t size, unsigned long writeTimeout_ms);
|
||||||
bool <a href="#read">readRequest</a>(unsigned long replyTimeout_ms, unsigned long readTimeout_ms, size_t expectedLength, bool async);
|
bool <a href="#read">readRequest</a>(unsigned long replyTimeout_ms, unsigned long readTimeout_ms, ssize_t expectedLength, bool async);
|
||||||
bool <a href="#read">supportsAsyncRead</a>();
|
bool <a href="#read">supportsAsyncRead</a>();
|
||||||
bool <a href="#event">supportsEvent</a>();
|
bool <a href="#event">supportsEvent</a>();
|
||||||
bool <a href="#event">acceptEvent</a>(unsigned long mask, unsigned long timeout_ms);
|
bool <a href="#event">acceptEvent</a>(unsigned long mask, unsigned long timeout_ms);
|
||||||
@ -118,7 +118,7 @@ bool <a href="#write">writeRequest</a>(const void* output,
|
|||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
bool <a href="#read">readRequest</a>(unsigned long replyTimeout_ms,
|
bool <a href="#read">readRequest</a>(unsigned long replyTimeout_ms,
|
||||||
unsigned long readTimeout_ms,
|
unsigned long readTimeout_ms,
|
||||||
size_t expectedLength, bool async);
|
ssize_t expectedLength, bool async);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
bool <a href="#read">supportsAsyncRead</a>();
|
bool <a href="#read">supportsAsyncRead</a>();
|
||||||
@ -460,7 +460,7 @@ The client may request more I/O or call <code>unlock()</code> after
|
|||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
bool readRequest(unsigned long replyTimeout_ms,
|
bool readRequest(unsigned long replyTimeout_ms,
|
||||||
unsigned long readTimeout_ms,
|
unsigned long readTimeout_ms,
|
||||||
size_t expectedLength, bool async);
|
ssize_t expectedLength, bool async);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
ssize_t readCallback(IoStatus status,
|
ssize_t readCallback(IoStatus status,
|
||||||
|
@ -482,12 +482,63 @@ To make this easier, <em>protocol arguments</em> can be used:
|
|||||||
move { out "\$1 GOTO %d"; }
|
move { out "\$1 GOTO %d"; }
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
Now, the protocol can be references in the <code>OUT</code> link
|
Now the same protocol can be used in the <code>OUT</code> link
|
||||||
of three different records as <code>move(X)</code>,
|
of three different records as <code>move(X)</code>,
|
||||||
<code>move(Y)</code> and <code>move(Z)</code>.
|
<code>move(Y)</code> and <code>move(Z)</code>.
|
||||||
Up to 9 parameters, referenced as <code>$1</code> ... <code>$9</code>
|
</p>
|
||||||
can be specified in parentheses, separated by comma.
|
<p>
|
||||||
The variable <code>$0</code> is replaced by the name of the protocol.
|
Up to 9 parameters can be specified in parentheses, separated by comma.
|
||||||
|
In the protocol, they are referenced as <code>$1</code> ...
|
||||||
|
<code>$9</code> outside quotes or <code>\$1</code> ... <code>\$9</code>
|
||||||
|
within quotes. The parameter <code>$0</code> resolves to the protocol name.
|
||||||
|
</p>
|
||||||
|
<div class="new">
|
||||||
|
<p>
|
||||||
|
To make links more readable, one space is allowed before and after each comma
|
||||||
|
and the enclosing parentheses. This space is not part of the parameter string.
|
||||||
|
Any additional space is part of the parameter.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
If a parameter contains matching pairs of parentheses, these and all commas
|
||||||
|
inside are part of the parameter.
|
||||||
|
This allows to pass parameter strings like <code>(1,2)</code> easily without
|
||||||
|
much escaping.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Unmatched parentheses must be escaped with double backslash <code>\\</code>
|
||||||
|
as well as must be commas outside pairs of parentheses.
|
||||||
|
Double backslash is necessary because one backslash is already consumed by
|
||||||
|
the db file parser.
|
||||||
|
To pass a literal backslash in a parameter string use 4 backslashes
|
||||||
|
<code>\\\\</code>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
Note that macros can be used in parameters. That makes it possible to
|
||||||
|
pass part of the record name to the protocol to be used in
|
||||||
|
<a href="formats.html#redirection">redirections</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4>Example:</h3>
|
||||||
|
<pre>
|
||||||
|
record(ai, "$(PREFIX)recX5") {
|
||||||
|
field(DTYP, "stream")
|
||||||
|
field(INP, "@$(PROTOCOLFILE) read(5, X\\,Y $(PREFIX)) $(PORT)")
|
||||||
|
}
|
||||||
|
record(ai, "$(PREFIX)recY5") {}
|
||||||
|
|
||||||
|
read { out 0x8$1 "READ \$2"; in "%f,%(\$3recY\$1)f" }
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
The protocol resolves to:
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
read { out 0x85 "READ X,Y"; in "%f,%($(PREFIX)recY5)f" }
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Here <code>$(PREFIX)</code> is replaced with its macro value.
|
||||||
|
But be aware that the macro is actually replaced before the link is parsed so
|
||||||
|
that macro values containing comma or parentheses may have unintended effects.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<a name="usrvar"></a>
|
<a name="usrvar"></a>
|
||||||
@ -565,7 +616,7 @@ There is a fixed set of exception handler names starting with
|
|||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<h3>Example:</h3>
|
<h4>Example:</h3>
|
||||||
<pre>
|
<pre>
|
||||||
setPosition {
|
setPosition {
|
||||||
out "POS %f";
|
out "POS %f";
|
||||||
|
@ -17,18 +17,6 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************/
|
***************************************************************/
|
||||||
|
|
||||||
#include "StreamBusInterface.h"
|
|
||||||
#include "StreamError.h"
|
|
||||||
#include "StreamBuffer.h"
|
|
||||||
|
|
||||||
#include "asynDriver.h"
|
|
||||||
#include "asynOctet.h"
|
|
||||||
#include "asynInt32.h"
|
|
||||||
#include "asynUInt32Digital.h"
|
|
||||||
#include "asynGpibDriver.h"
|
|
||||||
|
|
||||||
#include "devStream.h"
|
|
||||||
|
|
||||||
#ifdef EPICS_3_13
|
#ifdef EPICS_3_13
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <wdLib.h>
|
#include <wdLib.h>
|
||||||
@ -43,6 +31,18 @@ extern "C" {
|
|||||||
#include "iocsh.h"
|
#include "iocsh.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "StreamBusInterface.h"
|
||||||
|
#include "StreamError.h"
|
||||||
|
#include "StreamBuffer.h"
|
||||||
|
|
||||||
|
#include "asynDriver.h"
|
||||||
|
#include "asynOctet.h"
|
||||||
|
#include "asynInt32.h"
|
||||||
|
#include "asynUInt32Digital.h"
|
||||||
|
#include "asynGpibDriver.h"
|
||||||
|
|
||||||
|
#include "devStream.h"
|
||||||
|
|
||||||
#include "MacroMagic.h"
|
#include "MacroMagic.h"
|
||||||
|
|
||||||
#define Z PRINTF_SIZE_T_PREFIX
|
#define Z PRINTF_SIZE_T_PREFIX
|
||||||
@ -162,7 +162,7 @@ class AsynDriverInterface : StreamBusInterface
|
|||||||
double writeTimeout;
|
double writeTimeout;
|
||||||
double readTimeout;
|
double readTimeout;
|
||||||
double replyTimeout;
|
double replyTimeout;
|
||||||
size_t expectedLength;
|
ssize_t expectedLength;
|
||||||
unsigned long eventMask;
|
unsigned long eventMask;
|
||||||
unsigned long receivedEvent;
|
unsigned long receivedEvent;
|
||||||
StreamBuffer inputBuffer;
|
StreamBuffer inputBuffer;
|
||||||
@ -187,7 +187,7 @@ class AsynDriverInterface : StreamBusInterface
|
|||||||
bool writeRequest(const void* output, size_t size,
|
bool writeRequest(const void* output, size_t size,
|
||||||
unsigned long writeTimeout_ms);
|
unsigned long writeTimeout_ms);
|
||||||
bool readRequest(unsigned long replyTimeout_ms,
|
bool readRequest(unsigned long replyTimeout_ms,
|
||||||
unsigned long readTimeout_ms, size_t expectedLength, bool async);
|
unsigned long readTimeout_ms, ssize_t expectedLength, bool async);
|
||||||
bool acceptEvent(unsigned long mask, unsigned long replytimeout_ms);
|
bool acceptEvent(unsigned long mask, unsigned long replytimeout_ms);
|
||||||
bool supportsEvent();
|
bool supportsEvent();
|
||||||
bool supportsAsyncRead();
|
bool supportsAsyncRead();
|
||||||
@ -800,7 +800,7 @@ writeHandler()
|
|||||||
// interface function: we want to read something
|
// interface function: we want to read something
|
||||||
bool AsynDriverInterface::
|
bool AsynDriverInterface::
|
||||||
readRequest(unsigned long replyTimeout_ms, unsigned long readTimeout_ms,
|
readRequest(unsigned long replyTimeout_ms, unsigned long readTimeout_ms,
|
||||||
size_t _expectedLength, bool async)
|
ssize_t _expectedLength, bool async)
|
||||||
{
|
{
|
||||||
debug("AsynDriverInterface::readRequest(%s, %ld msec reply, "
|
debug("AsynDriverInterface::readRequest(%s, %ld msec reply, "
|
||||||
"%ld msec read, expect %" Z "u bytes, async=%s)\n",
|
"%ld msec read, expect %" Z "u bytes, async=%s)\n",
|
||||||
|
29
src/ChecksumConverter.cc
Normal file → Executable file
29
src/ChecksumConverter.cc
Normal file → Executable file
@ -504,6 +504,18 @@ static uint32_t leybold(const uint8_t* data, size_t len, uint32_t sum)
|
|||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checksum used by Brooks Cryopumps
|
||||||
|
static uint32_t brksCryo(const uint8_t* data, size_t len, uint32_t sum)
|
||||||
|
{
|
||||||
|
uint32_t xsum;
|
||||||
|
while (len--) {
|
||||||
|
sum += (*data++) & 0x7F;
|
||||||
|
}
|
||||||
|
xsum = (((sum >> 6) ^ sum) & 0x3F) + 0x30;
|
||||||
|
return xsum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct checksum
|
struct checksum
|
||||||
{
|
{
|
||||||
const char* name;
|
const char* name;
|
||||||
@ -521,8 +533,13 @@ static checksum checksumMap[] =
|
|||||||
{"sum8", sum, 0x00, 0x00, 1}, // 0xDD
|
{"sum8", sum, 0x00, 0x00, 1}, // 0xDD
|
||||||
{"sum16", sum, 0x0000, 0x0000, 2}, // 0x01DD
|
{"sum16", sum, 0x0000, 0x0000, 2}, // 0x01DD
|
||||||
{"sum32", sum, 0x00000000, 0x00000000, 4}, // 0x000001DD
|
{"sum32", sum, 0x00000000, 0x00000000, 4}, // 0x000001DD
|
||||||
|
{"nsum8", sum, 0xFF, 0xFF, 1}, // 0x23
|
||||||
|
{"nsum16", sum, 0xFFFF, 0xFFFF, 2}, // 0xFE23
|
||||||
|
{"nsum32", sum, 0xFFFFFFFF, 0xFFFFFFFF, 4}, // 0xFFFFFE23
|
||||||
|
{"notsum", sum, 0x00, 0xFF, 1}, // 0x22
|
||||||
{"xor", xor8, 0x00, 0x00, 1}, // 0x31
|
{"xor", xor8, 0x00, 0x00, 1}, // 0x31
|
||||||
{"xor8", xor8, 0x00, 0x00, 1}, // 0x31
|
{"xor8", xor8, 0x00, 0x00, 1}, // 0x31
|
||||||
|
{"xor8ff", xor8, 0x00, 0xFF, 1}, // 0xCE
|
||||||
{"xor7", xor7, 0x00, 0x00, 1}, // 0x31
|
{"xor7", xor7, 0x00, 0x00, 1}, // 0x31
|
||||||
{"crc8", crc_0x07, 0x00, 0x00, 1}, // 0xF4
|
{"crc8", crc_0x07, 0x00, 0x00, 1}, // 0xF4
|
||||||
{"ccitt8", crc_0x31, 0x00, 0x00, 1}, // 0xA1
|
{"ccitt8", crc_0x31, 0x00, 0x00, 1}, // 0xA1
|
||||||
@ -541,6 +558,7 @@ static checksum checksumMap[] =
|
|||||||
{"hexsum8", hexsum, 0x00, 0x00, 1}, // 0x2D
|
{"hexsum8", hexsum, 0x00, 0x00, 1}, // 0x2D
|
||||||
{"cpi", CPI, 0x00, 0x00, 1}, // 0x7E
|
{"cpi", CPI, 0x00, 0x00, 1}, // 0x7E
|
||||||
{"leybold", leybold, 0x00, 0x00, 1}, // 0x22
|
{"leybold", leybold, 0x00, 0x00, 1}, // 0x22
|
||||||
|
{"brksCryo",brksCryo, 0x00, 0x00, 1} // 0x4A
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint32_t mask[5] = {0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF};
|
static uint32_t mask[5] = {0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF};
|
||||||
@ -706,13 +724,14 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, size_t& cursor)
|
|||||||
debug("ChecksumConverter %s: input to check: \"%s\n",
|
debug("ChecksumConverter %s: input to check: \"%s\n",
|
||||||
checksumMap[fnum].name, input.expand(start,length)());
|
checksumMap[fnum].name, input.expand(start,length)());
|
||||||
|
|
||||||
uint_fast8_t expectedLength =
|
uint_fast8_t nDigits =
|
||||||
// get number of decimal digits from number of bytes: ceil(bytes*2.5)
|
// get number of decimal digits from number of bytes: ceil(bytes*2.5)
|
||||||
format.flags & sign_flag ? (checksumMap[fnum].bytes + 1) * 25 / 10 - 2 :
|
format.flags & sign_flag ? (checksumMap[fnum].bytes + 1) * 25 / 10 - 2 :
|
||||||
format.flags & (zero_flag|left_flag) ? 2 * checksumMap[fnum].bytes :
|
format.flags & (zero_flag|left_flag) ? 2 * checksumMap[fnum].bytes :
|
||||||
checksumMap[fnum].bytes;
|
checksumMap[fnum].bytes;
|
||||||
|
ssize_t expectedLength = nDigits;
|
||||||
|
|
||||||
if (input.length() - cursor < expectedLength)
|
if ((ssize_t)( input.length() - cursor ) < expectedLength)
|
||||||
{
|
{
|
||||||
debug("ChecksumConverter %s: Input '%s' too short for checksum\n",
|
debug("ChecksumConverter %s: Input '%s' too short for checksum\n",
|
||||||
checksumMap[fnum].name, input.expand(cursor)());
|
checksumMap[fnum].name, input.expand(cursor)());
|
||||||
@ -731,7 +750,7 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, size_t& cursor)
|
|||||||
if (format.flags & sign_flag) // decimal
|
if (format.flags & sign_flag) // decimal
|
||||||
{
|
{
|
||||||
uint32_t sumin = 0;
|
uint32_t sumin = 0;
|
||||||
size_t i;
|
ssize_t i;
|
||||||
for (i = 0; i < expectedLength; i++)
|
for (i = 0; i < expectedLength; i++)
|
||||||
{
|
{
|
||||||
inchar = input[cursor+i];
|
inchar = input[cursor+i];
|
||||||
@ -753,7 +772,7 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, size_t& cursor)
|
|||||||
{
|
{
|
||||||
if (format.flags & zero_flag) // ASCII
|
if (format.flags & zero_flag) // ASCII
|
||||||
{
|
{
|
||||||
if (sscanf(input(cursor+2*i), "%2" SCNx8, &inchar) != 1)
|
if (sscanf(input(cursor+2*i), "%2" SCNx8, (int8_t *) &inchar) != 1)
|
||||||
{
|
{
|
||||||
debug("ChecksumConverter %s: Input byte '%s' is not a hex byte\n",
|
debug("ChecksumConverter %s: Input byte '%s' is not a hex byte\n",
|
||||||
checksumMap[fnum].name, input.expand(cursor+2*i,2)());
|
checksumMap[fnum].name, input.expand(cursor+2*i,2)());
|
||||||
@ -797,7 +816,7 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, size_t& cursor)
|
|||||||
{
|
{
|
||||||
if (format.flags & zero_flag) // ASCII
|
if (format.flags & zero_flag) // ASCII
|
||||||
{
|
{
|
||||||
sscanf(input(cursor+2*i), "%2" SCNx8, &inchar);
|
sscanf(input(cursor+2*i), "%2" SCNx8, (int8_t *) &inchar);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (format.flags & left_flag) // poor man's hex: 0x30 - 0x3F
|
if (format.flags & left_flag) // poor man's hex: 0x30 - 0x3F
|
||||||
|
@ -37,7 +37,7 @@ class DebugInterface : StreamBusInterface
|
|||||||
bool writeRequest(const void* output, size_t size,
|
bool writeRequest(const void* output, size_t size,
|
||||||
unsigned long writeTimeout_ms);
|
unsigned long writeTimeout_ms);
|
||||||
bool readRequest(unsigned long replyTimeout_ms,
|
bool readRequest(unsigned long replyTimeout_ms,
|
||||||
unsigned long readTimeout_ms, size_t expectedLength, bool async);
|
unsigned long readTimeout_ms, ssize_t expectedLength, bool async);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~DebugInterface();
|
~DebugInterface();
|
||||||
@ -169,9 +169,9 @@ writeRequest(const void* output, size_t size, unsigned long writeTimeout_ms)
|
|||||||
// Return false if the read request cannot be accepted.
|
// Return false if the read request cannot be accepted.
|
||||||
bool DebugInterface::
|
bool DebugInterface::
|
||||||
readRequest(unsigned long replyTimeout_ms, unsigned long readTimeout_ms,
|
readRequest(unsigned long replyTimeout_ms, unsigned long readTimeout_ms,
|
||||||
size_t expectedLength, bool async)
|
ssize_t expectedLength, bool async)
|
||||||
{
|
{
|
||||||
debug("DebugInterface::readRequest(%s, %ld msec reply, %ld msec read, expect %" Z "u bytes, asyn=%s)\n",
|
debug("DebugInterface::readRequest(%s, %ld msec reply, %ld msec read, expect %" Z "d bytes, asyn=%s)\n",
|
||||||
clientName(), replyTimeout_ms, readTimeout_ms, expectedLength, async?"yes":"no");
|
clientName(), replyTimeout_ms, readTimeout_ms, expectedLength, async?"yes":"no");
|
||||||
|
|
||||||
// Debug interface does not support async mode.
|
// Debug interface does not support async mode.
|
||||||
|
@ -127,7 +127,7 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
|||||||
if (numEnums < 0) numEnums=-numEnums-1;
|
if (numEnums < 0) numEnums=-numEnums-1;
|
||||||
while (numEnums-- && (value != index))
|
while (numEnums-- && (value != index))
|
||||||
{
|
{
|
||||||
while(*s)
|
while (*s)
|
||||||
{
|
{
|
||||||
if (*s == esc) s++;
|
if (*s == esc) s++;
|
||||||
s++;
|
s++;
|
||||||
@ -140,7 +140,7 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
|||||||
error("Value %li not found in enum set\n", value);
|
error("Value %li not found in enum set\n", value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
while(*s)
|
while (*s)
|
||||||
{
|
{
|
||||||
if (*s == esc) s++;
|
if (*s == esc) s++;
|
||||||
output.append(*s++);
|
output.append(*s++);
|
||||||
@ -165,7 +165,7 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
|||||||
debug("EnumConverter::scanLong: check #%ld \"%s\"\n", index, s);
|
debug("EnumConverter::scanLong: check #%ld \"%s\"\n", index, s);
|
||||||
consumed = 0;
|
consumed = 0;
|
||||||
match = true;
|
match = true;
|
||||||
while(*s)
|
while (*s)
|
||||||
{
|
{
|
||||||
if (*s == StreamProtocolParser::skip)
|
if (*s == StreamProtocolParser::skip)
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
#define ENUM(type, args...) \
|
#define ENUM(type, args...) \
|
||||||
enum type { args }; \
|
enum type { args }; \
|
||||||
static inline const char* type##ToStr(int x) {switch(x){MACRO_FOR_EACH(_CASE_LINE,args)default: return "invalid";}}\
|
static inline const char* type##ToStr(int x) {switch(x) {MACRO_FOR_EACH(_CASE_LINE,args)default: return "invalid";}}\
|
||||||
_ENUM_CAST(type)
|
_ENUM_CAST(type)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -65,7 +65,7 @@ _ENUM_CAST(type)
|
|||||||
|
|
||||||
#define ENUM(type,...) \
|
#define ENUM(type,...) \
|
||||||
enum type { __VA_ARGS__ }; \
|
enum type { __VA_ARGS__ }; \
|
||||||
static inline const char* type##ToStr(int x) {switch(x){_EXPAND(MACRO_FOR_EACH(_CASE_LINE,__VA_ARGS__)) default: return "invalid";}} \
|
static inline const char* type##ToStr(int x) {switch(x) {_EXPAND(MACRO_FOR_EACH(_CASE_LINE,__VA_ARGS__)) default: return "invalid";}} \
|
||||||
_ENUM_CAST(type)
|
_ENUM_CAST(type)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -306,7 +306,7 @@ print(const char* fmt, ...)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
if (printed > -1) grow(len+printed);
|
if (printed > -1) grow(len+printed);
|
||||||
else grow(len);
|
else grow(cap*2-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,11 +199,10 @@ public:
|
|||||||
|
|
||||||
// find: get index of data in buffer or -1
|
// find: get index of data in buffer or -1
|
||||||
ssize_t find(char c, ssize_t start=0) const
|
ssize_t find(char c, ssize_t start=0) const
|
||||||
{char* p;
|
{if (start < 0 && (start -= len) < 0) start = 0;
|
||||||
|
char* p;
|
||||||
return (p = static_cast<char*>(
|
return (p = static_cast<char*>(
|
||||||
memchr(buffer+offs+(start<0?start+len:start),
|
memchr(buffer+offs+start, c, len-start)))? p-(buffer+offs) : -1;}
|
||||||
c, start<0?-start:len-start)))?
|
|
||||||
p-(buffer+offs) : -1;}
|
|
||||||
|
|
||||||
ssize_t find(const void* s, size_t size, ssize_t start=0) const;
|
ssize_t find(const void* s, size_t size, ssize_t start=0) const;
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ writeRequest(const void*, size_t, unsigned long)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool StreamBusInterface::
|
bool StreamBusInterface::
|
||||||
readRequest(unsigned long, unsigned long, size_t, bool)
|
readRequest(unsigned long, unsigned long, ssize_t, bool)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ public:
|
|||||||
return businterface && businterface->writeRequest(output, size, timeout_ms);
|
return businterface && businterface->writeRequest(output, size, timeout_ms);
|
||||||
}
|
}
|
||||||
bool busReadRequest(unsigned long replytimeout_ms,
|
bool busReadRequest(unsigned long replytimeout_ms,
|
||||||
unsigned long readtimeout_ms, size_t expectedLength,
|
unsigned long readtimeout_ms, ssize_t expectedLength,
|
||||||
bool async) {
|
bool async) {
|
||||||
return businterface && businterface->readRequest(replytimeout_ms,
|
return businterface && businterface->readRequest(replytimeout_ms,
|
||||||
readtimeout_ms, expectedLength, async);
|
readtimeout_ms, expectedLength, async);
|
||||||
@ -133,7 +133,7 @@ protected:
|
|||||||
virtual bool writeRequest(const void* output, size_t size,
|
virtual bool writeRequest(const void* output, size_t size,
|
||||||
unsigned long timeout_ms);
|
unsigned long timeout_ms);
|
||||||
virtual bool readRequest(unsigned long replytimeout_ms,
|
virtual bool readRequest(unsigned long replytimeout_ms,
|
||||||
unsigned long readtimeout_ms, size_t expectedLength,
|
unsigned long readtimeout_ms, ssize_t expectedLength,
|
||||||
bool async);
|
bool async);
|
||||||
virtual bool supportsEvent(); // defaults to false
|
virtual bool supportsEvent(); // defaults to false
|
||||||
virtual bool supportsAsyncRead(); // defaults to false
|
virtual bool supportsAsyncRead(); // defaults to false
|
||||||
|
@ -34,7 +34,7 @@ printCommands(StreamBuffer& buffer, const char* c)
|
|||||||
unsigned long eventnumber;
|
unsigned long eventnumber;
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
switch(*c++)
|
switch (*c++)
|
||||||
{
|
{
|
||||||
case end:
|
case end:
|
||||||
return buffer();
|
return buffer();
|
||||||
@ -189,14 +189,26 @@ parse(const char* filename, const char* _protocolname)
|
|||||||
ssize_t i = protocolname.find('(');
|
ssize_t i = protocolname.find('(');
|
||||||
if (i >= 0)
|
if (i >= 0)
|
||||||
{
|
{
|
||||||
while (i >= 0)
|
while (i < (ssize_t)protocolname.length())
|
||||||
{
|
{
|
||||||
if (protocolname[i-1] == ' ')
|
if (protocolname[i-1] == ' ')
|
||||||
protocolname.remove(--i, 1); // remove trailing space
|
protocolname.remove(--i, 1); // remove trailing space
|
||||||
protocolname[i] = '\0'; // replace '(' and ',' with '\0'
|
protocolname[i] = '\0'; // replace initial '(' and separating ',' with '\0'
|
||||||
if (protocolname[i+1] == ' ')
|
if (protocolname[i+1] == ' ')
|
||||||
protocolname.remove(i+1, 1); // remove leading space
|
protocolname.remove(i+1, 1); // remove leading space
|
||||||
i = protocolname.find(',', i+1);
|
int brackets = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
i += strcspn(protocolname(i), ",()\\");
|
||||||
|
char c = protocolname[i];
|
||||||
|
if (c == '(') brackets++;
|
||||||
|
else if (c == ')') brackets--;
|
||||||
|
else if (c == ',' && brackets <= 0) break;
|
||||||
|
else if (c == '\\') {
|
||||||
|
if (protocolname[i+1] == '\\') i++; // keep '\\'
|
||||||
|
else protocolname.remove(i, 1); // else skip over next char
|
||||||
|
}
|
||||||
|
} while (i < (ssize_t)protocolname.length());
|
||||||
}
|
}
|
||||||
// should have closing parentheses
|
// should have closing parentheses
|
||||||
if (protocolname[-1] != ')')
|
if (protocolname[-1] != ')')
|
||||||
@ -206,9 +218,8 @@ parse(const char* filename, const char* _protocolname)
|
|||||||
}
|
}
|
||||||
protocolname.truncate(-1); // remove ')'
|
protocolname.truncate(-1); // remove ')'
|
||||||
if (protocolname[-1] == ' ')
|
if (protocolname[-1] == ' ')
|
||||||
{
|
|
||||||
protocolname.truncate(-1); // remove trailing space
|
protocolname.truncate(-1); // remove trailing space
|
||||||
}
|
debug("StreamCore::parse \"%s\" -> \"%s\"\n", _protocolname, protocolname.expand()());
|
||||||
}
|
}
|
||||||
StreamProtocolParser::Protocol* protocol;
|
StreamProtocolParser::Protocol* protocol;
|
||||||
protocol = StreamProtocolParser::getProtocol(filename, protocolname);
|
protocol = StreamProtocolParser::getProtocol(filename, protocolname);
|
||||||
@ -975,8 +986,8 @@ readCallback(StreamIoStatus status,
|
|||||||
evalIn();
|
evalIn();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
debug("StreamCore::readCallback(%s): No reply from device within %ld ms\n",
|
error("%s: No reply within %ld ms to \"%s\"\n",
|
||||||
name(), replyTimeout);
|
name(), replyTimeout, outputLine.expand()());
|
||||||
inputBuffer.clear();
|
inputBuffer.clear();
|
||||||
finishProtocol(ReplyTimeout);
|
finishProtocol(ReplyTimeout);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
|
|
||||||
#ifdef EPICS_3_13
|
#ifdef EPICS_3_13
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
static char* epicsStrDup(const char *s) { char* c = (char*)malloc(strlen(s)+1); strcpy(c, s); return c; }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define epicsAlarmGLOBAL
|
#define epicsAlarmGLOBAL
|
||||||
@ -161,10 +164,7 @@ class Stream : protected StreamCore
|
|||||||
Stream(dbCommon* record, const struct link *ioLink,
|
Stream(dbCommon* record, const struct link *ioLink,
|
||||||
streamIoFunction readData, streamIoFunction writeData);
|
streamIoFunction readData, streamIoFunction writeData);
|
||||||
~Stream();
|
~Stream();
|
||||||
long parseLink(const struct link *ioLink, char* filename, char* protocol,
|
long initRecord(char* linkstring);
|
||||||
char* busname, int* addr, char* busparam);
|
|
||||||
long initRecord(const char* filename, const char* protocol,
|
|
||||||
const char* busname, int addr, const char* busparam);
|
|
||||||
bool print(format_t *format, va_list ap);
|
bool print(format_t *format, va_list ap);
|
||||||
ssize_t scan(format_t *format, void* pvalue, size_t maxStringSize);
|
ssize_t scan(format_t *format, void* pvalue, size_t maxStringSize);
|
||||||
bool process();
|
bool process();
|
||||||
@ -211,7 +211,7 @@ long streamReload(const char* recordname)
|
|||||||
int oldStreamError = streamError;
|
int oldStreamError = streamError;
|
||||||
streamError = 1;
|
streamError = 1;
|
||||||
|
|
||||||
if(!pdbbase) {
|
if (!pdbbase) {
|
||||||
error("No database has been loaded\n");
|
error("No database has been loaded\n");
|
||||||
streamError = oldStreamError;
|
streamError = oldStreamError;
|
||||||
return ERROR;
|
return ERROR;
|
||||||
@ -534,12 +534,7 @@ long streamInitRecord(dbCommon* record, const struct link *ioLink,
|
|||||||
streamIoFunction readData, streamIoFunction writeData)
|
streamIoFunction readData, streamIoFunction writeData)
|
||||||
{
|
{
|
||||||
long status;
|
long status;
|
||||||
char filename[256];
|
char* linkstring;
|
||||||
char protocol[256];
|
|
||||||
char busname[256];
|
|
||||||
int addr = -1;
|
|
||||||
char busparam[256];
|
|
||||||
memset(busparam, 0 ,sizeof(busparam));
|
|
||||||
|
|
||||||
debug("streamInitRecord(%s): SEVR=%d\n", record->name, record->sevr);
|
debug("streamInitRecord(%s): SEVR=%d\n", record->name, record->sevr);
|
||||||
Stream* stream = static_cast<Stream*>(record->dpvt);
|
Stream* stream = static_cast<Stream*>(record->dpvt);
|
||||||
@ -556,19 +551,30 @@ long streamInitRecord(dbCommon* record, const struct link *ioLink,
|
|||||||
record->name);
|
record->name);
|
||||||
stream->finishProtocol(Stream::Abort);
|
stream->finishProtocol(Stream::Abort);
|
||||||
}
|
}
|
||||||
// scan the i/o link
|
if (ioLink->type != INST_IO)
|
||||||
debug("streamInitRecord(%s): parse link \"%s\"\n",
|
|
||||||
record->name, ioLink->value.instio.string);
|
|
||||||
status = stream->parseLink(ioLink, filename, protocol,
|
|
||||||
busname, &addr, busparam);
|
|
||||||
// (re)initialize bus and protocol
|
|
||||||
if (status == 0)
|
|
||||||
{
|
{
|
||||||
|
error("%s: Wrong I/O link type %s\n", record->name,
|
||||||
|
pamaplinkType[ioLink->type].strvalue);
|
||||||
|
return S_dev_badInitRet;
|
||||||
|
}
|
||||||
|
if (!ioLink->value.instio.string[0])
|
||||||
|
{
|
||||||
|
error("%s: Empty I/O link. "
|
||||||
|
"Forgot the leading '@' or confused INP with OUT or link is too long ?\n",
|
||||||
|
record->name);
|
||||||
|
return S_dev_badInitRet;
|
||||||
|
}
|
||||||
|
// (re)initialize bus and protocol
|
||||||
|
linkstring = epicsStrDup(ioLink->value.instio.string);
|
||||||
|
if (!linkstring)
|
||||||
|
{
|
||||||
|
error("%s: Out of memory", record->name);
|
||||||
|
return S_dev_noMemory;
|
||||||
|
}
|
||||||
debug("streamInitRecord(%s): calling initRecord\n",
|
debug("streamInitRecord(%s): calling initRecord\n",
|
||||||
record->name);
|
record->name);
|
||||||
status = stream->initRecord(filename, protocol,
|
status = stream->initRecord(linkstring);
|
||||||
busname, addr, busparam);
|
free(linkstring);
|
||||||
}
|
|
||||||
if (status != OK && status != DO_NOT_CONVERT)
|
if (status != OK && status != DO_NOT_CONVERT)
|
||||||
{
|
{
|
||||||
error("%s: Record initialization failed\n", record->name);
|
error("%s: Record initialization failed\n", record->name);
|
||||||
@ -587,7 +593,6 @@ long streamReadWrite(dbCommon *record)
|
|||||||
if (!stream || stream->status == ERROR)
|
if (!stream || stream->status == ERROR)
|
||||||
{
|
{
|
||||||
(void) recGblSetSevr(record, UDF_ALARM, INVALID_ALARM);
|
(void) recGblSetSevr(record, UDF_ALARM, INVALID_ALARM);
|
||||||
error("%s: Record not initialised correctly\n", record->name);
|
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
return stream->process() ? stream->convert : ERROR;
|
return stream->process() ? stream->convert : ERROR;
|
||||||
@ -699,77 +704,77 @@ Stream::
|
|||||||
}
|
}
|
||||||
|
|
||||||
long Stream::
|
long Stream::
|
||||||
parseLink(const struct link *ioLink, char* filename,
|
initRecord(char* linkstring /* modifiable copy */)
|
||||||
char* protocol, char* busname, int* addr, char* busparam)
|
|
||||||
{
|
{
|
||||||
// parse link parameters: filename protocol busname addr busparam
|
char *filename;
|
||||||
int n1, n2;
|
char *protocol;
|
||||||
if (ioLink->type != INST_IO)
|
char *busname;
|
||||||
{
|
char *busparam;
|
||||||
error("%s: Wrong I/O link type %s\n", name(),
|
long addr = -1;
|
||||||
pamaplinkType[ioLink->type].strvalue);
|
|
||||||
return S_dev_badInitRet;
|
|
||||||
}
|
|
||||||
if (0 >= sscanf(ioLink->value.instio.string, "%s%n", filename, &n1))
|
|
||||||
{
|
|
||||||
error("%s: Empty I/O link. "
|
|
||||||
"Forgot the leading '@' or confused INP with OUT or link is too long ?\n",
|
|
||||||
name());
|
|
||||||
return S_dev_badInitRet;
|
|
||||||
}
|
|
||||||
if (0 >= sscanf(ioLink->value.instio.string+n1, " %[^ \t(] %n", protocol, &n2))
|
|
||||||
{
|
|
||||||
error("%s: Missing protocol name\n"
|
|
||||||
" expect \"@file protocol[(arg1,...)] bus [addr] [params]\"\n"
|
|
||||||
" in \"@%s\"\n", name(),
|
|
||||||
ioLink->value.instio.string);
|
|
||||||
return S_dev_badInitRet;
|
|
||||||
}
|
|
||||||
n1+=n2;
|
|
||||||
if (ioLink->value.instio.string[n1] == '(')
|
|
||||||
{
|
|
||||||
n2 = 0;
|
|
||||||
sscanf(ioLink->value.instio.string+n1, " %[^)] %n", protocol+strlen(protocol), &n2);
|
|
||||||
n1+=n2;
|
|
||||||
if (ioLink->value.instio.string[n1++] != ')')
|
|
||||||
{
|
|
||||||
error("%s: Missing ')' after protocol arguments '%s'\n"
|
|
||||||
" expect \"@file protocol(arg1,...) bus [addr] [params]\"\n"
|
|
||||||
" in \"@%s\"\n", name(), protocol,
|
|
||||||
ioLink->value.instio.string);
|
|
||||||
return S_dev_badInitRet;
|
|
||||||
}
|
|
||||||
strcat(protocol, ")");
|
|
||||||
}
|
|
||||||
if (0 >= sscanf(ioLink->value.instio.string+n1, "%s %i %99c", busname, addr, busparam))
|
|
||||||
{
|
|
||||||
error("%s: Missing bus name\n"
|
|
||||||
" expect \"@file protocol[(arg1,...)] bus [addr] [params]\"\n"
|
|
||||||
" in \"@%s\"\n", name(),
|
|
||||||
ioLink->value.instio.string);
|
|
||||||
return S_dev_badInitRet;
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
long Stream::
|
debug("Stream::initRecord %s: parse link string \"%s\"\n", name(), linkstring);
|
||||||
initRecord(const char* filename, const char* protocol,
|
|
||||||
const char* busname, int addr, const char* busparam)
|
while (isspace(*linkstring)) linkstring++;
|
||||||
{
|
filename = linkstring;
|
||||||
// It is safe to call this function again with different arguments
|
while (*linkstring && !isspace(*linkstring)) linkstring++;
|
||||||
|
if (*linkstring) *linkstring++ = 0;
|
||||||
|
|
||||||
|
while (isspace(*linkstring)) linkstring++;
|
||||||
|
protocol = linkstring;
|
||||||
|
while (*linkstring && !isspace(*linkstring) && *linkstring != '(') linkstring++;
|
||||||
|
while (isspace(*linkstring)) linkstring++;
|
||||||
|
if (*linkstring == '(') {
|
||||||
|
int brackets = 0;
|
||||||
|
while(*++linkstring) {
|
||||||
|
if (*linkstring == '(') brackets++;
|
||||||
|
else if (*linkstring == ')') brackets--;
|
||||||
|
else if (*linkstring == '\\' && !*++linkstring) break;
|
||||||
|
else if (isspace(*linkstring) && brackets < 0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*linkstring) linkstring--;
|
||||||
|
if (*linkstring) *linkstring++ = 0;
|
||||||
|
|
||||||
|
while (isspace(*linkstring)) linkstring++;
|
||||||
|
busname = linkstring;
|
||||||
|
while (*linkstring && !isspace(*linkstring)) linkstring++;
|
||||||
|
if (*linkstring) *linkstring++ = 0;
|
||||||
|
|
||||||
|
if (linkstring) addr = strtol(linkstring, &linkstring, 0);
|
||||||
|
while (isspace(*linkstring)) linkstring++;
|
||||||
|
busparam = linkstring;
|
||||||
|
|
||||||
|
debug("Stream::initRecord %s: filename=\"%s\" protocol=\"%s\" bus=\"%s\" addr=%ld params=\"%s\"\n",
|
||||||
|
name(), filename, protocol, busname, addr, busparam);
|
||||||
|
|
||||||
|
if (!*filename)
|
||||||
|
{
|
||||||
|
error("%s: Missing protocol file name\n", name());
|
||||||
|
return S_dev_badInitRet;
|
||||||
|
}
|
||||||
|
if (!*protocol)
|
||||||
|
{
|
||||||
|
error("%s: Missing protocol name\n", name());
|
||||||
|
return S_dev_badInitRet;
|
||||||
|
}
|
||||||
|
if (!*busname)
|
||||||
|
{
|
||||||
|
error("%s: Missing bus name\n", name());
|
||||||
|
return S_dev_badInitRet;
|
||||||
|
}
|
||||||
|
|
||||||
// attach to bus interface
|
// attach to bus interface
|
||||||
debug("Stream::initRecord %s: attachBus(%s, %d, \"%s\")\n",
|
debug("Stream::initRecord %s: attachBus(\"%s\", %ld, \"%s\")\n",
|
||||||
name(), busname, addr, busparam);
|
name(), busname, addr, busparam);
|
||||||
if (!attachBus(busname, addr, busparam))
|
if (!attachBus(busname, addr, busparam))
|
||||||
{
|
{
|
||||||
error("%s: Can't attach to bus %s %d\n",
|
error("%s: Can't attach to bus %s %ld\n",
|
||||||
name(), busname, addr);
|
name(), busname, addr);
|
||||||
return S_dev_noDevice;
|
return S_dev_noDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse protocol file
|
// parse protocol file
|
||||||
debug("Stream::initRecord %s: parse(%s, %s)\n",
|
debug("Stream::initRecord %s: parse(\"%s\", \"%s\")\n",
|
||||||
name(), filename, protocol);
|
name(), filename, protocol);
|
||||||
if (!parse(filename, protocol))
|
if (!parse(filename, protocol))
|
||||||
{
|
{
|
||||||
@ -1100,7 +1105,7 @@ getFieldAddress(const char* fieldname, StreamBuffer& address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const unsigned char dbfMapping[] =
|
static const unsigned char dbfMapping[] =
|
||||||
#ifdef DBF_INT64
|
#ifdef DBR_INT64
|
||||||
{0, DBF_UINT64, DBF_INT64, DBF_ENUM, DBF_DOUBLE, DBF_STRING};
|
{0, DBF_UINT64, DBF_INT64, DBF_ENUM, DBF_DOUBLE, DBF_STRING};
|
||||||
#else
|
#else
|
||||||
{0, DBF_ULONG, DBF_LONG, DBF_ENUM, DBF_DOUBLE, DBF_STRING};
|
{0, DBF_ULONG, DBF_LONG, DBF_ENUM, DBF_DOUBLE, DBF_STRING};
|
||||||
|
@ -27,12 +27,7 @@
|
|||||||
|
|
||||||
int streamDebug = 0;
|
int streamDebug = 0;
|
||||||
int streamError = 1;
|
int streamError = 1;
|
||||||
extern "C" {
|
|
||||||
#ifdef _WIN32
|
|
||||||
__declspec(dllexport)
|
|
||||||
#endif
|
|
||||||
FILE *StreamDebugFile = NULL;
|
FILE *StreamDebugFile = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef va_copy
|
#ifndef va_copy
|
||||||
#ifdef __va_copy
|
#ifdef __va_copy
|
||||||
|
@ -1039,7 +1039,7 @@ compileNumber(unsigned long& number, const char*& source, unsigned long max)
|
|||||||
*source, source);
|
*source, source);
|
||||||
if (*source == '$')
|
if (*source == '$')
|
||||||
{
|
{
|
||||||
if(!replaceVariable(buffer, source)) return false;
|
if (!replaceVariable(buffer, source)) return false;
|
||||||
debug("buffer=%s\n", buffer.expand()());
|
debug("buffer=%s\n", buffer.expand()());
|
||||||
buffer.truncate(-1-(int)sizeof(int));
|
buffer.truncate(-1-(int)sizeof(int));
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,12 @@
|
|||||||
#define DO_NOT_CONVERT 2
|
#define DO_NOT_CONVERT 2
|
||||||
#define INIT_RUN (!interruptAccept)
|
#define INIT_RUN (!interruptAccept)
|
||||||
|
|
||||||
|
#ifdef epicsExportSharedSymbols
|
||||||
|
# define devStream_epicsExportSharedSymbols
|
||||||
|
# undef epicsExportSharedSymbols
|
||||||
|
# include "shareLib.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "epicsVersion.h"
|
#include "epicsVersion.h"
|
||||||
#ifdef BASE_VERSION
|
#ifdef BASE_VERSION
|
||||||
#define EPICS_3_13
|
#define EPICS_3_13
|
||||||
@ -49,12 +55,6 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef epicsExportSharedSymbols
|
|
||||||
# define devStream_epicsExportSharedSymbols
|
|
||||||
# undef epicsExportSharedSymbols
|
|
||||||
# include <shareLib.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "dbCommon.h"
|
#include "dbCommon.h"
|
||||||
#include "dbScan.h"
|
#include "dbScan.h"
|
||||||
#include "devSup.h"
|
#include "devSup.h"
|
||||||
@ -65,12 +65,6 @@ extern "C" {
|
|||||||
#include "dbEvent.h"
|
#include "dbEvent.h"
|
||||||
#include "epicsMath.h"
|
#include "epicsMath.h"
|
||||||
|
|
||||||
#ifdef devStream_epicsExportSharedSymbols
|
|
||||||
# undef devStream_epicsExportSharedSymbols
|
|
||||||
# define epicsExportSharedSymbols
|
|
||||||
# include <shareLib.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef EPICS_3_13
|
#ifdef EPICS_3_13
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
@ -79,6 +73,12 @@ extern "C" {
|
|||||||
#include "epicsStdioRedirect.h"
|
#include "epicsStdioRedirect.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef devStream_epicsExportSharedSymbols
|
||||||
|
# undef devStream_epicsExportSharedSymbols
|
||||||
|
# define epicsExportSharedSymbols
|
||||||
|
# include "shareLib.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
typedef ptrdiff_t ssize_t;
|
typedef ptrdiff_t ssize_t;
|
||||||
#endif
|
#endif
|
||||||
@ -88,8 +88,7 @@ typedef const struct format_s {
|
|||||||
const struct StreamFormat* priv;
|
const struct StreamFormat* priv;
|
||||||
} format_t;
|
} format_t;
|
||||||
|
|
||||||
epicsShareExtern FILE* StreamDebugFile;
|
extern FILE* StreamDebugFile;
|
||||||
extern const char StreamVersion [];
|
|
||||||
|
|
||||||
typedef long (*streamIoFunction) (dbCommon*, format_t*);
|
typedef long (*streamIoFunction) (dbCommon*, format_t*);
|
||||||
|
|
||||||
@ -97,6 +96,8 @@ typedef long (*streamIoFunction) (dbCommon*, format_t*);
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern const char StreamVersion [];
|
||||||
|
|
||||||
long streamInit(int after);
|
long streamInit(int after);
|
||||||
long streamInitRecord(dbCommon *record,
|
long streamInitRecord(dbCommon *record,
|
||||||
const struct link *ioLink,
|
const struct link *ioLink,
|
||||||
|
@ -69,7 +69,7 @@ static long readData(dbCommon *record, format_t *format)
|
|||||||
case DBF_FLOAT:
|
case DBF_FLOAT:
|
||||||
((epicsFloat32 *)aai->bptr)[aai->nord] = (epicsFloat32)lval;
|
((epicsFloat32 *)aai->bptr)[aai->nord] = (epicsFloat32)lval;
|
||||||
break;
|
break;
|
||||||
#ifdef DBF_INT64
|
#ifdef DBR_INT64
|
||||||
case DBF_INT64:
|
case DBF_INT64:
|
||||||
case DBF_UINT64:
|
case DBF_UINT64:
|
||||||
((epicsInt64 *)aai->bptr)[aai->nord] = (epicsInt64)lval;
|
((epicsInt64 *)aai->bptr)[aai->nord] = (epicsInt64)lval;
|
||||||
@ -167,7 +167,7 @@ static long writeData(dbCommon *record, format_t *format)
|
|||||||
case DBF_FLOAT:
|
case DBF_FLOAT:
|
||||||
dval = ((epicsFloat32 *)aai->bptr)[nowd];
|
dval = ((epicsFloat32 *)aai->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
#ifdef DBF_INT64
|
#ifdef DBR_INT64
|
||||||
case DBF_INT64:
|
case DBF_INT64:
|
||||||
dval = ((epicsInt64 *)aai->bptr)[nowd];
|
dval = ((epicsInt64 *)aai->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
@ -210,12 +210,12 @@ static long writeData(dbCommon *record, format_t *format)
|
|||||||
{
|
{
|
||||||
switch (aai->ftvl)
|
switch (aai->ftvl)
|
||||||
{
|
{
|
||||||
#ifdef DBF_INT64
|
#ifdef DBR_INT64
|
||||||
case DBF_INT64:
|
case DBF_INT64:
|
||||||
lval = ((epicsInt64 *)aao->bptr)[nowd];
|
lval = ((epicsInt64 *)aai->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
case DBF_UINT64:
|
case DBF_UINT64:
|
||||||
lval = ((epicsUInt64 *)aao->bptr)[nowd];
|
lval = ((epicsUInt64 *)aai->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
|
@ -68,7 +68,7 @@ static long readData(dbCommon *record, format_t *format)
|
|||||||
case DBF_FLOAT:
|
case DBF_FLOAT:
|
||||||
((epicsFloat32 *)aao->bptr)[aao->nord] = (epicsFloat32)lval;
|
((epicsFloat32 *)aao->bptr)[aao->nord] = (epicsFloat32)lval;
|
||||||
break;
|
break;
|
||||||
#ifdef DBF_INT64
|
#ifdef DBR_INT64
|
||||||
case DBF_INT64:
|
case DBF_INT64:
|
||||||
case DBF_UINT64:
|
case DBF_UINT64:
|
||||||
((epicsInt64 *)aao->bptr)[aao->nord] = (epicsInt64)lval;
|
((epicsInt64 *)aao->bptr)[aao->nord] = (epicsInt64)lval;
|
||||||
@ -196,7 +196,7 @@ static long writeData(dbCommon *record, format_t *format)
|
|||||||
case DBF_FLOAT:
|
case DBF_FLOAT:
|
||||||
dval = ((epicsFloat32 *)aao->bptr)[nowd];
|
dval = ((epicsFloat32 *)aao->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
#ifdef DBF_INT64
|
#ifdef DBR_INT64
|
||||||
case DBF_INT64:
|
case DBF_INT64:
|
||||||
dval = ((epicsInt64 *)aao->bptr)[nowd];
|
dval = ((epicsInt64 *)aao->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
@ -239,7 +239,7 @@ static long writeData(dbCommon *record, format_t *format)
|
|||||||
{
|
{
|
||||||
switch (aao->ftvl)
|
switch (aao->ftvl)
|
||||||
{
|
{
|
||||||
#ifdef DBF_INT64
|
#ifdef DBR_INT64
|
||||||
case DBF_INT64:
|
case DBF_INT64:
|
||||||
lval = ((epicsInt64 *)aao->bptr)[nowd];
|
lval = ((epicsInt64 *)aao->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
|
@ -60,7 +60,7 @@ static long readData(dbCommon *record, format_t *format)
|
|||||||
monitor_mask |= DBE_LOG;
|
monitor_mask |= DBE_LOG;
|
||||||
co->alst = co->val;
|
co->alst = co->val;
|
||||||
}
|
}
|
||||||
if (monitor_mask){
|
if (monitor_mask) {
|
||||||
db_post_events(record, &co->val, monitor_mask);
|
db_post_events(record, &co->val, monitor_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
of the device support.
|
of the device support.
|
||||||
Fix: sCalcoutRecord.c, end of init_record() add
|
Fix: sCalcoutRecord.c, end of init_record() add
|
||||||
|
|
||||||
if(pscalcoutDSET->init_record ) {
|
if (pscalcoutDSET->init_record ) {
|
||||||
return (*pscalcoutDSET->init_record)(pcalc);
|
return (*pscalcoutDSET->init_record)(pcalc);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
@ -70,10 +70,10 @@ static long readData(dbCommon *record, format_t *format)
|
|||||||
case DBF_FLOAT:
|
case DBF_FLOAT:
|
||||||
((epicsFloat32 *)wf->bptr)[wf->nord] = (epicsFloat32)lval;
|
((epicsFloat32 *)wf->bptr)[wf->nord] = (epicsFloat32)lval;
|
||||||
break;
|
break;
|
||||||
#ifdef DBF_INT64
|
#ifdef DBR_INT64
|
||||||
case DBF_INT64:
|
case DBF_INT64:
|
||||||
case DBF_UINT64:
|
case DBF_UINT64:
|
||||||
((epicsInt64 *)wf->bptr)[aao->nord] = (epicsInt64)lval;
|
((epicsInt64 *)wf->bptr)[wf->nord] = (epicsInt64)lval;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
@ -168,7 +168,7 @@ static long writeData(dbCommon *record, format_t *format)
|
|||||||
case DBF_FLOAT:
|
case DBF_FLOAT:
|
||||||
dval = ((epicsFloat32 *)wf->bptr)[nowd];
|
dval = ((epicsFloat32 *)wf->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
#ifdef DBF_INT64
|
#ifdef DBR_INT64
|
||||||
case DBF_INT64:
|
case DBF_INT64:
|
||||||
dval = ((epicsInt64 *)wf->bptr)[nowd];
|
dval = ((epicsInt64 *)wf->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
@ -211,7 +211,7 @@ static long writeData(dbCommon *record, format_t *format)
|
|||||||
{
|
{
|
||||||
switch (wf->ftvl)
|
switch (wf->ftvl)
|
||||||
{
|
{
|
||||||
#ifdef DBF_INT64
|
#ifdef DBR_INT64
|
||||||
case DBF_INT64:
|
case DBF_INT64:
|
||||||
lval = ((epicsInt64 *)wf->bptr)[nowd];
|
lval = ((epicsInt64 *)wf->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
|
@ -62,14 +62,17 @@ proc startioc {} {
|
|||||||
puts $fd "streamApp_registerRecordDeviceDriver"
|
puts $fd "streamApp_registerRecordDeviceDriver"
|
||||||
}
|
}
|
||||||
puts $fd "streamSetLogfile StreamDebug.log"
|
puts $fd "streamSetLogfile StreamDebug.log"
|
||||||
|
puts $fd "var streamDebug 1"
|
||||||
|
puts $fd "var streamError 1"
|
||||||
puts $fd "epicsEnvSet STREAM_PROTOCOL_PATH ."
|
puts $fd "epicsEnvSet STREAM_PROTOCOL_PATH ."
|
||||||
puts $fd "drvAsynIPPortConfigure device localhost:$port"
|
puts $fd "drvAsynIPPortConfigure device localhost:$port"
|
||||||
puts $fd "dbLoadRecords test.db"
|
if [info exists startup] {
|
||||||
puts $fd $startup
|
puts $fd $startup
|
||||||
|
}
|
||||||
|
puts $fd "dbLoadRecords test.db"
|
||||||
puts $fd "iocInit"
|
puts $fd "iocInit"
|
||||||
puts $fd "dbl"
|
puts $fd "dbl"
|
||||||
puts $fd "dbior stream 2"
|
puts $fd "dbior stream 2"
|
||||||
puts $fd "var streamDebug 1"
|
|
||||||
close $fd
|
close $fd
|
||||||
if [info exists streamversion] {
|
if [info exists streamversion] {
|
||||||
set ioc [open "|iocsh test.cmd >& $testname.ioclog 2>@stderr" w]
|
set ioc [open "|iocsh test.cmd >& $testname.ioclog 2>@stderr" w]
|
||||||
|
61
streamApp/tests/testParenthesesInParameters
Executable file
61
streamApp/tests/testParenthesesInParameters
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(ARG(10),20,30) device")
|
||||||
|
}
|
||||||
|
|
||||||
|
record(ao, "DZ:test2")
|
||||||
|
{
|
||||||
|
field (DTYP, "stream")
|
||||||
|
field (OUT, "@test.proto test1 (ARG(10,20), 30) device")
|
||||||
|
}
|
||||||
|
record(ao, "DZ:test3")
|
||||||
|
{
|
||||||
|
field (DTYP, "stream")
|
||||||
|
field (OUT, "@test.proto test1 ( ARG ( 10 , 20 ) , 30 ) device")
|
||||||
|
}
|
||||||
|
record(ao, "DZ:test4")
|
||||||
|
{
|
||||||
|
field (DTYP, "stream")
|
||||||
|
field (OUT, "@test.proto test1( ARG \\( 10 , 20 , 30 ) device")
|
||||||
|
}
|
||||||
|
record(ao, "DZ:test5")
|
||||||
|
{
|
||||||
|
field (DTYP, "stream")
|
||||||
|
field (OUT, "@test.proto test1(\\ ARG\\,\\\\(10,20)\\,30) device")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set protocol {
|
||||||
|
Terminator = LF;
|
||||||
|
test1 { out "VAL:\$1:%d"}
|
||||||
|
}
|
||||||
|
|
||||||
|
set startup {
|
||||||
|
}
|
||||||
|
|
||||||
|
set debug 0
|
||||||
|
|
||||||
|
startioc
|
||||||
|
|
||||||
|
put DZ:test1 "1"
|
||||||
|
assure "VAL:ARG(10):1\n"
|
||||||
|
put DZ:test2 "1"
|
||||||
|
assure "VAL:ARG(10,20):1\n"
|
||||||
|
put DZ:test3 "1"
|
||||||
|
assure "VAL:ARG ( 10 , 20 ):1\n"
|
||||||
|
put DZ:test4 "1"
|
||||||
|
assure "VAL: ARG ( 10 :1\n"
|
||||||
|
put DZ:test5 "1"
|
||||||
|
assure "VAL: ARG,\\(10,20),30:1\n"
|
||||||
|
|
||||||
|
#finish
|
@ -16,7 +16,7 @@ set records {
|
|||||||
|
|
||||||
set protocol {
|
set protocol {
|
||||||
Terminator = LF;
|
Terminator = LF;
|
||||||
test1 {out "\%\e%d\e\e\%";}
|
test1 {out "\%\e%d%%\e\e\%";}
|
||||||
}
|
}
|
||||||
|
|
||||||
set startup {
|
set startup {
|
||||||
@ -28,6 +28,6 @@ set debug 0
|
|||||||
startioc
|
startioc
|
||||||
|
|
||||||
put DZ:test1 1
|
put DZ:test1 1
|
||||||
assure "%\0331\033\033%\n"
|
assure "%\0331%\033\033%\n"
|
||||||
|
|
||||||
finish
|
finish
|
||||||
|
@ -63,7 +63,7 @@ fi
|
|||||||
for o in $O
|
for o in $O
|
||||||
do
|
do
|
||||||
g++ -I ../../src $o test.cc -o test.exe
|
g++ -I ../../src $o test.cc -o test.exe
|
||||||
test.exe
|
./test.exe
|
||||||
if [ $? != 0 ]
|
if [ $? != 0 ]
|
||||||
then
|
then
|
||||||
echo -e "\033[31;7mTest failed.\033[0m"
|
echo -e "\033[31;7mTest failed.\033[0m"
|
||||||
|
Reference in New Issue
Block a user