Compare commits
13 Commits
stream_2_5
...
Release-2-
Author | SHA1 | Date | |
---|---|---|---|
79a17788f2 | |||
9f0a2d2fb6 | |||
66f6ce9bd2 | |||
e5dfe7b816 | |||
6efb17be64 | |||
0310b30446 | |||
863cdf3d7f | |||
e51bb2555e | |||
9e0157d679 | |||
3e91eb4fc1 | |||
caf811c23a | |||
de116c9e5a | |||
eef38b0557 |
@ -88,11 +88,11 @@ many process variables distributed over many records.
|
|||||||
|
|
||||||
<h2>Recommended Readings</h2>
|
<h2>Recommended Readings</h2>
|
||||||
<p>
|
<p>
|
||||||
<a href="http://www.aps.anl.gov/epics/base/R3-14/8-docs/AppDevGuide.pdf"
|
<a href="http://www.aps.anl.gov/epics/base/R3-14/12-docs/AppDevGuide"
|
||||||
target="ex">IOC Application Developer's Guide (PDF)</a>
|
target="ex">IOC Application Developer's Guide</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="http://www.aps.anl.gov/asd/controls/epics/EpicsDocumentation/AppDevManuals/RecordRef/Recordref-1.html"
|
<a href="https://wiki-ext.aps.anl.gov/epics/index.php/RRM_3-14"
|
||||||
target="ex">EPICS Record Reference Manual</a>
|
target="ex">EPICS Record Reference Manual</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -23,18 +23,18 @@
|
|||||||
#include "StreamBuffer.h"
|
#include "StreamBuffer.h"
|
||||||
|
|
||||||
#include <epicsVersion.h>
|
#include <epicsVersion.h>
|
||||||
#if (EPICS_VERSION == 3 && EPICS_REVISION == 14)
|
#ifdef BASE_VERSION
|
||||||
#define EPICS_3_14
|
#define EPICS_3_13
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
#include <epicsAssert.h>
|
|
||||||
#include <epicsTime.h>
|
|
||||||
#include <epicsTimer.h>
|
|
||||||
#else
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <wdLib.h>
|
#include <wdLib.h>
|
||||||
#include <sysLib.h>
|
#include <sysLib.h>
|
||||||
|
#else
|
||||||
|
#include <epicsAssert.h>
|
||||||
|
#include <epicsTime.h>
|
||||||
|
#include <epicsTimer.h>
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <callback.h>
|
#include <callback.h>
|
||||||
}
|
}
|
||||||
@ -139,7 +139,7 @@ static const char* eomReasonStr[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class AsynDriverInterface : StreamBusInterface
|
class AsynDriverInterface : StreamBusInterface
|
||||||
#ifdef EPICS_3_14
|
#ifndef EPICS_3_13
|
||||||
, epicsTimerNotify
|
, epicsTimerNotify
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
@ -169,12 +169,12 @@ class AsynDriverInterface : StreamBusInterface
|
|||||||
const char* outputBuffer;
|
const char* outputBuffer;
|
||||||
size_t outputSize;
|
size_t outputSize;
|
||||||
int peeksize;
|
int peeksize;
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
epicsTimerQueueActive* timerQueue;
|
|
||||||
epicsTimer* timer;
|
|
||||||
#else
|
|
||||||
WDOG_ID timer;
|
WDOG_ID timer;
|
||||||
CALLBACK timeoutCallback;
|
CALLBACK timeoutCallback;
|
||||||
|
#else
|
||||||
|
epicsTimerQueueActive* timerQueue;
|
||||||
|
epicsTimer* timer;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
AsynDriverInterface(Client* client);
|
AsynDriverInterface(Client* client);
|
||||||
@ -194,11 +194,11 @@ class AsynDriverInterface : StreamBusInterface
|
|||||||
bool disconnectRequest();
|
bool disconnectRequest();
|
||||||
void finish();
|
void finish();
|
||||||
|
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
|
static void expire(CALLBACK *pcallback);
|
||||||
|
#else
|
||||||
// epicsTimerNotify methods
|
// epicsTimerNotify methods
|
||||||
epicsTimerNotify::expireStatus expire(const epicsTime &);
|
epicsTimerNotify::expireStatus expire(const epicsTime &);
|
||||||
#else
|
|
||||||
static void expire(CALLBACK *pcallback);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// local methods
|
// local methods
|
||||||
@ -216,22 +216,22 @@ class AsynDriverInterface : StreamBusInterface
|
|||||||
(StreamBusInterface::priority());
|
(StreamBusInterface::priority());
|
||||||
}
|
}
|
||||||
void startTimer(double timeout) {
|
void startTimer(double timeout) {
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
timer->start(*this, timeout
|
|
||||||
+epicsThreadSleepQuantum()*0.5
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
callbackSetPriority(priority(), &timeoutCallback);
|
callbackSetPriority(priority(), &timeoutCallback);
|
||||||
wdStart(timer, (int)((timeout+1)*sysClkRateGet())-1,
|
wdStart(timer, (int)((timeout+1)*sysClkRateGet())-1,
|
||||||
reinterpret_cast<FUNCPTR>(callbackRequest),
|
reinterpret_cast<FUNCPTR>(callbackRequest),
|
||||||
reinterpret_cast<int>(&timeoutCallback));
|
reinterpret_cast<int>(&timeoutCallback));
|
||||||
|
#else
|
||||||
|
timer->start(*this, timeout
|
||||||
|
+epicsThreadSleepQuantum()*0.5
|
||||||
|
);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
void cancelTimer() {
|
void cancelTimer() {
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
timer->cancel();
|
|
||||||
#else
|
|
||||||
wdCancel(timer);
|
wdCancel(timer);
|
||||||
|
#else
|
||||||
|
timer->cancel();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,15 +270,15 @@ AsynDriverInterface(Client* client) : StreamBusInterface(client)
|
|||||||
handleTimeout);
|
handleTimeout);
|
||||||
assert(pasynUser);
|
assert(pasynUser);
|
||||||
pasynUser->userPvt = this;
|
pasynUser->userPvt = this;
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
|
timer = wdCreate();
|
||||||
|
callbackSetCallback(expire, &timeoutCallback);
|
||||||
|
callbackSetUser(this, &timeoutCallback);
|
||||||
|
#else
|
||||||
timerQueue = &epicsTimerQueueActive::allocate(true);
|
timerQueue = &epicsTimerQueueActive::allocate(true);
|
||||||
assert(timerQueue);
|
assert(timerQueue);
|
||||||
timer = &timerQueue->createTimer();
|
timer = &timerQueue->createTimer();
|
||||||
assert(timer);
|
assert(timer);
|
||||||
#else
|
|
||||||
timer = wdCreate();
|
|
||||||
callbackSetCallback(expire, &timeoutCallback);
|
|
||||||
callbackSetUser(this, &timeoutCallback);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,11 +313,11 @@ AsynDriverInterface::
|
|||||||
}
|
}
|
||||||
// Now, no handler is running any more and none will start.
|
// Now, no handler is running any more and none will start.
|
||||||
|
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
|
wdDelete(timer);
|
||||||
|
#else
|
||||||
timer->destroy();
|
timer->destroy();
|
||||||
timerQueue->release();
|
timerQueue->release();
|
||||||
#else
|
|
||||||
wdDelete(timer);
|
|
||||||
#endif
|
#endif
|
||||||
pasynManager->disconnect(pasynUser);
|
pasynManager->disconnect(pasynUser);
|
||||||
pasynManager->freeAsynUser(pasynUser);
|
pasynManager->freeAsynUser(pasynUser);
|
||||||
@ -617,19 +617,26 @@ writeHandler()
|
|||||||
clientName());
|
clientName());
|
||||||
asynStatus status;
|
asynStatus status;
|
||||||
size_t written = 0;
|
size_t written = 0;
|
||||||
pasynUser->timeout = writeTimeout;
|
|
||||||
|
|
||||||
// discard any early input or early events
|
// discard any early input, but forward it to potential async records
|
||||||
status = pasynOctet->flush(pvtOctet, pasynUser);
|
// thus do not use pasynOctet->flush()
|
||||||
|
pasynUser->timeout = 0;
|
||||||
|
do {
|
||||||
|
char buffer [256];
|
||||||
|
size_t received = sizeof(buffer);
|
||||||
|
int eomReason = 0;
|
||||||
|
status = pasynOctet->read(pvtOctet, pasynUser,
|
||||||
|
buffer, received, &received, &eomReason);
|
||||||
|
#ifndef NO_TEMPORARY
|
||||||
|
if (received) debug("AsynDriverInterface::writeHandler(%s): flushing %ld bytes: \"%s\"\n",
|
||||||
|
clientName(), (long)received, StreamBuffer(buffer, received).expand()());
|
||||||
|
#endif
|
||||||
|
} while (status != asynTimeout);
|
||||||
|
|
||||||
|
// discard any early events
|
||||||
receivedEvent = 0;
|
receivedEvent = 0;
|
||||||
|
|
||||||
if (status != asynSuccess)
|
pasynUser->timeout = writeTimeout;
|
||||||
{
|
|
||||||
error("%s: pasynOctet->flush() failed: %s\n",
|
|
||||||
clientName(), pasynUser->errorMessage);
|
|
||||||
writeCallback(StreamIoFault);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// has stream already added a terminator or should
|
// has stream already added a terminator or should
|
||||||
// asyn do so?
|
// asyn do so?
|
||||||
@ -739,7 +746,7 @@ readRequest(unsigned long replyTimeout_ms, unsigned long readTimeout_ms,
|
|||||||
long _expectedLength, bool async)
|
long _expectedLength, bool async)
|
||||||
{
|
{
|
||||||
debug("AsynDriverInterface::readRequest(%s, %ld msec reply, "
|
debug("AsynDriverInterface::readRequest(%s, %ld msec reply, "
|
||||||
"%ld msec read, expect %ld bytes, asyn=%s)\n",
|
"%ld msec read, expect %ld bytes, async=%s)\n",
|
||||||
clientName(), replyTimeout_ms, readTimeout_ms,
|
clientName(), replyTimeout_ms, readTimeout_ms,
|
||||||
_expectedLength, async?"yes":"no");
|
_expectedLength, async?"yes":"no");
|
||||||
|
|
||||||
@ -978,6 +985,9 @@ readHandler()
|
|||||||
// reply timeout
|
// reply timeout
|
||||||
if (ioAction == AsyncRead)
|
if (ioAction == AsyncRead)
|
||||||
{
|
{
|
||||||
|
debug("AsynDriverInterface::readHandler(%s): "
|
||||||
|
"no async input, retry in in %g seconds\n",
|
||||||
|
clientName(), replyTimeout);
|
||||||
// start next poll after timer expires
|
// start next poll after timer expires
|
||||||
if (replyTimeout != 0.0) startTimer(replyTimeout);
|
if (replyTimeout != 0.0) startTimer(replyTimeout);
|
||||||
// continues with:
|
// continues with:
|
||||||
@ -1255,6 +1265,9 @@ timerExpired()
|
|||||||
int autoconnect, connected;
|
int autoconnect, connected;
|
||||||
switch (ioAction)
|
switch (ioAction)
|
||||||
{
|
{
|
||||||
|
case None:
|
||||||
|
// Timeout of async poll crossed with parasitic input
|
||||||
|
return;
|
||||||
case ReceiveEvent:
|
case ReceiveEvent:
|
||||||
// timeout while waiting for event
|
// timeout while waiting for event
|
||||||
ioAction = None;
|
ioAction = None;
|
||||||
@ -1304,14 +1317,7 @@ timerExpired()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
epicsTimerNotify::expireStatus AsynDriverInterface::
|
|
||||||
expire(const epicsTime &)
|
|
||||||
{
|
|
||||||
timerExpired();
|
|
||||||
return noRestart;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void AsynDriverInterface::
|
void AsynDriverInterface::
|
||||||
expire(CALLBACK *pcallback)
|
expire(CALLBACK *pcallback)
|
||||||
{
|
{
|
||||||
@ -1319,6 +1325,13 @@ expire(CALLBACK *pcallback)
|
|||||||
static_cast<AsynDriverInterface*>(pcallback->user);
|
static_cast<AsynDriverInterface*>(pcallback->user);
|
||||||
interface->timerExpired();
|
interface->timerExpired();
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
epicsTimerNotify::expireStatus AsynDriverInterface::
|
||||||
|
expire(const epicsTime &)
|
||||||
|
{
|
||||||
|
timerExpired();
|
||||||
|
return noRestart;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool AsynDriverInterface::
|
bool AsynDriverInterface::
|
||||||
|
@ -79,12 +79,11 @@ include $(TOP)/configure/RULES
|
|||||||
|
|
||||||
# Update version string (contains __DATE__ and __TIME__)
|
# Update version string (contains __DATE__ and __TIME__)
|
||||||
# each time make runs.
|
# each time make runs.
|
||||||
StreamVersion$(OBJ): FORCE
|
StreamVersion$(OBJ): ../*.c ../*.h ../*.cc ../CONFIG_STREAM ../Makefile
|
||||||
FORCE:
|
|
||||||
|
|
||||||
# Add references to all registrars to main file to avoid
|
# Add references to all registrars to main file to avoid
|
||||||
# missing initialization.
|
# missing initialization.
|
||||||
StreamCore$(OBJ): streamReferences
|
StreamCore$(OBJ) StreamCore$(DEP): streamReferences
|
||||||
|
|
||||||
streamReferences: ../CONFIG_STREAM
|
streamReferences: ../CONFIG_STREAM
|
||||||
$(PERL) ../makeref.pl Interface $(BUSSES) > $@
|
$(PERL) ../makeref.pl Interface $(BUSSES) > $@
|
||||||
@ -94,4 +93,7 @@ streamReferences: ../CONFIG_STREAM
|
|||||||
$(COMMON_DIR)/$(LIBRARY_DEFAULT).dbd: ../CONFIG_STREAM
|
$(COMMON_DIR)/$(LIBRARY_DEFAULT).dbd: ../CONFIG_STREAM
|
||||||
$(PERL) ../makedbd.pl $(RECORDS) > $@
|
$(PERL) ../makedbd.pl $(RECORDS) > $@
|
||||||
|
|
||||||
|
$(LIBRARY_DEFAULT).dbd$(DEP): ../CONFIG_STREAM
|
||||||
|
echo $(LIBRARY_DEFAULT).dbd: $< > $@
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
@ -52,42 +52,62 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
StreamBusInterface* businterface;
|
StreamBusInterface* businterface;
|
||||||
bool busSupportsEvent() {
|
bool busSupportsEvent() {
|
||||||
return businterface->supportsEvent();
|
if (businterface)
|
||||||
|
return businterface->supportsEvent();
|
||||||
|
else return false;
|
||||||
}
|
}
|
||||||
bool busSupportsAsyncRead() {
|
bool busSupportsAsyncRead() {
|
||||||
return businterface->supportsAsyncRead();
|
if (businterface)
|
||||||
|
return businterface->supportsAsyncRead();
|
||||||
|
else return false;
|
||||||
}
|
}
|
||||||
bool busAcceptEvent(unsigned long mask,
|
bool busAcceptEvent(unsigned long mask,
|
||||||
unsigned long replytimeout_ms) {
|
unsigned long replytimeout_ms) {
|
||||||
return businterface->acceptEvent(mask, replytimeout_ms);
|
if (businterface)
|
||||||
|
return businterface->acceptEvent(mask, replytimeout_ms);
|
||||||
|
else return false;
|
||||||
}
|
}
|
||||||
void busRelease() {
|
void busRelease() {
|
||||||
businterface->release();
|
if (businterface)
|
||||||
|
businterface->release();
|
||||||
}
|
}
|
||||||
bool busLockRequest(unsigned long timeout_ms) {
|
bool busLockRequest(unsigned long timeout_ms) {
|
||||||
return businterface->lockRequest(timeout_ms);
|
if (businterface)
|
||||||
|
return businterface->lockRequest(timeout_ms);
|
||||||
|
else return false;
|
||||||
}
|
}
|
||||||
bool busUnlock() {
|
bool busUnlock() {
|
||||||
return businterface->unlock();
|
if (businterface)
|
||||||
|
return businterface->unlock();
|
||||||
|
else return false;
|
||||||
}
|
}
|
||||||
bool busWriteRequest(const void* output, size_t size,
|
bool busWriteRequest(const void* output, size_t size,
|
||||||
unsigned long timeout_ms) {
|
unsigned long timeout_ms) {
|
||||||
return businterface->writeRequest(output, size, timeout_ms);
|
if (businterface)
|
||||||
|
return businterface->writeRequest(output, size, timeout_ms);
|
||||||
|
else return false;
|
||||||
}
|
}
|
||||||
bool busReadRequest(unsigned long replytimeout_ms,
|
bool busReadRequest(unsigned long replytimeout_ms,
|
||||||
unsigned long readtimeout_ms, long expectedLength,
|
unsigned long readtimeout_ms, long expectedLength,
|
||||||
bool async) {
|
bool async) {
|
||||||
return businterface->readRequest(replytimeout_ms,
|
if (businterface)
|
||||||
readtimeout_ms, expectedLength, async);
|
return businterface->readRequest(replytimeout_ms,
|
||||||
|
readtimeout_ms, expectedLength, async);
|
||||||
|
else return false;
|
||||||
}
|
}
|
||||||
void busFinish() {
|
void busFinish() {
|
||||||
businterface->finish();
|
if (businterface)
|
||||||
|
businterface->finish();
|
||||||
}
|
}
|
||||||
bool busConnectRequest(unsigned long timeout_ms) {
|
bool busConnectRequest(unsigned long timeout_ms) {
|
||||||
return businterface->connectRequest(timeout_ms);
|
if (businterface)
|
||||||
|
return businterface->connectRequest(timeout_ms);
|
||||||
|
else return false;
|
||||||
}
|
}
|
||||||
bool busDisconnect() {
|
bool busDisconnect() {
|
||||||
return businterface->disconnectRequest();
|
if (businterface)
|
||||||
|
return businterface->disconnectRequest();
|
||||||
|
else return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,11 +23,11 @@
|
|||||||
#include "StreamError.h"
|
#include "StreamError.h"
|
||||||
|
|
||||||
#include <epicsVersion.h>
|
#include <epicsVersion.h>
|
||||||
#if (EPICS_VERSION == 3 && EPICS_REVISION == 14)
|
#ifdef BASE_VERSION
|
||||||
#define EPICS_3_14
|
#define EPICS_3_13
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -39,10 +39,11 @@ extern "C" {
|
|||||||
#include <recSup.h>
|
#include <recSup.h>
|
||||||
#include <recGbl.h>
|
#include <recGbl.h>
|
||||||
#include <devLib.h>
|
#include <devLib.h>
|
||||||
|
#define epicsAlarmGLOBAL
|
||||||
#include <alarm.h>
|
#include <alarm.h>
|
||||||
#include <callback.h>
|
#include <callback.h>
|
||||||
|
|
||||||
#ifndef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
|
|
||||||
#include <semLib.h>
|
#include <semLib.h>
|
||||||
#include <wdLib.h>
|
#include <wdLib.h>
|
||||||
@ -92,24 +93,24 @@ extern "C" void streamRecordProcessCallback(CALLBACK *pcallback);
|
|||||||
extern "C" long streamReload(char* recordname);
|
extern "C" long streamReload(char* recordname);
|
||||||
|
|
||||||
class Stream : protected StreamCore
|
class Stream : protected StreamCore
|
||||||
#ifdef EPICS_3_14
|
#ifndef EPICS_3_13
|
||||||
, epicsTimerNotify
|
, epicsTimerNotify
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
dbCommon* record;
|
dbCommon* record;
|
||||||
struct link *ioLink;
|
const struct link *ioLink;
|
||||||
streamIoFunction readData;
|
streamIoFunction readData;
|
||||||
streamIoFunction writeData;
|
streamIoFunction writeData;
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
epicsTimerQueueActive* timerQueue;
|
|
||||||
epicsTimer* timer;
|
|
||||||
epicsMutex mutex;
|
|
||||||
epicsEvent initDone;
|
|
||||||
#else
|
|
||||||
WDOG_ID timer;
|
WDOG_ID timer;
|
||||||
CALLBACK timeoutCallback;
|
CALLBACK timeoutCallback;
|
||||||
SEM_ID mutex;
|
SEM_ID mutex;
|
||||||
SEM_ID initDone;
|
SEM_ID initDone;
|
||||||
|
#else
|
||||||
|
epicsTimerQueueActive* timerQueue;
|
||||||
|
epicsTimer* timer;
|
||||||
|
epicsMutex mutex;
|
||||||
|
epicsEvent initDone;
|
||||||
#endif
|
#endif
|
||||||
StreamBuffer fieldBuffer;
|
StreamBuffer fieldBuffer;
|
||||||
int status;
|
int status;
|
||||||
@ -120,11 +121,11 @@ class Stream : protected StreamCore
|
|||||||
CALLBACK processCallback;
|
CALLBACK processCallback;
|
||||||
|
|
||||||
|
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
|
static void expire(CALLBACK *pcallback);
|
||||||
|
#else
|
||||||
// epicsTimerNotify method
|
// epicsTimerNotify method
|
||||||
expireStatus expire(const epicsTime&);
|
expireStatus expire(const epicsTime&);
|
||||||
#else
|
|
||||||
static void expire(CALLBACK *pcallback);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// StreamCore methods
|
// StreamCore methods
|
||||||
@ -144,16 +145,19 @@ class Stream : protected StreamCore
|
|||||||
friend void streamRecordProcessCallback(CALLBACK *pcallback);
|
friend void streamRecordProcessCallback(CALLBACK *pcallback);
|
||||||
|
|
||||||
// Stream Epics methods
|
// Stream Epics methods
|
||||||
long initRecord();
|
Stream(dbCommon* record, const struct link *ioLink,
|
||||||
Stream(dbCommon* record, struct link *ioLink,
|
|
||||||
streamIoFunction readData, streamIoFunction writeData);
|
streamIoFunction readData, streamIoFunction writeData);
|
||||||
~Stream();
|
~Stream();
|
||||||
|
long parseLink(const struct link *ioLink, char* filename, char* protocol,
|
||||||
|
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);
|
||||||
bool scan(format_t *format, void* pvalue, size_t maxStringSize);
|
bool scan(format_t *format, void* pvalue, size_t maxStringSize);
|
||||||
bool process();
|
bool process();
|
||||||
|
|
||||||
// device support functions
|
// device support functions
|
||||||
friend long streamInitRecord(dbCommon *record, struct link *ioLink,
|
friend long streamInitRecord(dbCommon *record, const struct link *ioLink,
|
||||||
streamIoFunction readData, streamIoFunction writeData);
|
streamIoFunction readData, streamIoFunction writeData);
|
||||||
friend long streamReadWrite(dbCommon *record);
|
friend long streamReadWrite(dbCommon *record);
|
||||||
friend long streamGetIointInfo(int cmd, dbCommon *record,
|
friend long streamGetIointInfo(int cmd, dbCommon *record,
|
||||||
@ -171,7 +175,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
// shell functions ///////////////////////////////////////////////////////
|
// shell functions ///////////////////////////////////////////////////////
|
||||||
#ifdef EPICS_3_14
|
#ifndef EPICS_3_13
|
||||||
extern "C" {
|
extern "C" {
|
||||||
epicsExportAddress(int, streamDebug);
|
epicsExportAddress(int, streamDebug);
|
||||||
}
|
}
|
||||||
@ -230,7 +234,7 @@ extern "C" long streamReload(char* recordname)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EPICS_3_14
|
#ifndef EPICS_3_13
|
||||||
static const iocshArg streamReloadArg0 =
|
static const iocshArg streamReloadArg0 =
|
||||||
{ "recordname", iocshArgString };
|
{ "recordname", iocshArgString };
|
||||||
static const iocshArg * const streamReloadArgs[] =
|
static const iocshArg * const streamReloadArgs[] =
|
||||||
@ -256,7 +260,7 @@ static void streamRegistrar ()
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
epicsExportRegistrar(streamRegistrar);
|
epicsExportRegistrar(streamRegistrar);
|
||||||
}
|
}
|
||||||
#endif // EPICS_3_14
|
#endif
|
||||||
|
|
||||||
// driver support ////////////////////////////////////////////////////////
|
// driver support ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -270,19 +274,13 @@ struct stream_drvsup {
|
|||||||
Stream::drvInit
|
Stream::drvInit
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef EPICS_3_14
|
#ifndef EPICS_3_13
|
||||||
extern "C" {
|
extern "C" {
|
||||||
epicsExportAddress(drvet, stream);
|
epicsExportAddress(drvet, stream);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void streamEpicsPrintTimestamp(char* buffer, int size)
|
#ifdef EPICS_3_13
|
||||||
{
|
|
||||||
int tlen;
|
|
||||||
epicsTime tm = epicsTime::getCurrent();
|
|
||||||
tlen = tm.strftime(buffer, size, "%Y/%m/%d %H:%M:%S.%03f");
|
|
||||||
sprintf(buffer+tlen, " %.*s", size-tlen-2, epicsThreadGetNameSelf());
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void streamEpicsPrintTimestamp(char* buffer, int size)
|
void streamEpicsPrintTimestamp(char* buffer, int size)
|
||||||
{
|
{
|
||||||
int tlen;
|
int tlen;
|
||||||
@ -297,6 +295,14 @@ void streamEpicsPrintTimestamp(char* buffer, int size)
|
|||||||
tlen = strlen(buffer);
|
tlen = strlen(buffer);
|
||||||
sprintf(buffer+tlen, " %.*s", size-tlen-2, taskName(0));
|
sprintf(buffer+tlen, " %.*s", size-tlen-2, taskName(0));
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
void streamEpicsPrintTimestamp(char* buffer, int size)
|
||||||
|
{
|
||||||
|
int tlen;
|
||||||
|
epicsTime tm = epicsTime::getCurrent();
|
||||||
|
tlen = tm.strftime(buffer, size, "%Y/%m/%d %H:%M:%S.%06f");
|
||||||
|
sprintf(buffer+tlen, " %.*s", size-tlen-2, epicsThreadGetNameSelf());
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
long Stream::
|
long Stream::
|
||||||
@ -398,9 +404,16 @@ long streamInit(int after)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
long streamInitRecord(dbCommon* record, struct link *ioLink,
|
long streamInitRecord(dbCommon* record, const struct link *ioLink,
|
||||||
streamIoFunction readData, streamIoFunction writeData)
|
streamIoFunction readData, streamIoFunction writeData)
|
||||||
{
|
{
|
||||||
|
char filename[80];
|
||||||
|
char protocol[80];
|
||||||
|
char busname[80];
|
||||||
|
int addr = -1;
|
||||||
|
char busparam[80];
|
||||||
|
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* pstream = (Stream*)record->dpvt;
|
Stream* pstream = (Stream*)record->dpvt;
|
||||||
if (!pstream)
|
if (!pstream)
|
||||||
@ -412,8 +425,12 @@ long streamInitRecord(dbCommon* record, struct link *ioLink,
|
|||||||
// stop any running protocol
|
// stop any running protocol
|
||||||
pstream->finishProtocol(Stream::Abort);
|
pstream->finishProtocol(Stream::Abort);
|
||||||
}
|
}
|
||||||
|
// scan the i/o link
|
||||||
|
pstream->parseLink(ioLink, filename, protocol,
|
||||||
|
busname, &addr, busparam);
|
||||||
// (re)initialize bus and protocol
|
// (re)initialize bus and protocol
|
||||||
long status = pstream->initRecord();
|
long status = pstream->initRecord(filename, protocol,
|
||||||
|
busname, addr, busparam);
|
||||||
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);
|
||||||
@ -441,7 +458,8 @@ long streamGetIointInfo(int cmd, dbCommon *record, IOSCANPVT *ppvt)
|
|||||||
{
|
{
|
||||||
Stream* pstream = (Stream*)record->dpvt;
|
Stream* pstream = (Stream*)record->dpvt;
|
||||||
debug("streamGetIointInfo(%s,cmd=%d): pstream=%p, ioscanpvt=%p\n",
|
debug("streamGetIointInfo(%s,cmd=%d): pstream=%p, ioscanpvt=%p\n",
|
||||||
record->name, cmd, (void*)pstream, pstream ? pstream->ioscanpvt : NULL);
|
record->name, cmd,
|
||||||
|
(void*)pstream, pstream ? pstream->ioscanpvt : NULL);
|
||||||
if (!pstream)
|
if (!pstream)
|
||||||
{
|
{
|
||||||
error("streamGetIointInfo called without stream instance\n");
|
error("streamGetIointInfo called without stream instance\n");
|
||||||
@ -500,20 +518,20 @@ long streamScanfN(dbCommon* record, format_t *format,
|
|||||||
// Stream methods ////////////////////////////////////////////////////////
|
// Stream methods ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Stream::
|
Stream::
|
||||||
Stream(dbCommon* _record, struct link *ioLink,
|
Stream(dbCommon* _record, const struct link *ioLink,
|
||||||
streamIoFunction readData, streamIoFunction writeData)
|
streamIoFunction readData, streamIoFunction writeData)
|
||||||
:record(_record), ioLink(ioLink), readData(readData), writeData(writeData)
|
:record(_record), ioLink(ioLink), readData(readData), writeData(writeData)
|
||||||
{
|
{
|
||||||
streamname = record->name;
|
streamname = record->name;
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
timerQueue = &epicsTimerQueueActive::allocate(true);
|
|
||||||
timer = &timerQueue->createTimer();
|
|
||||||
#else
|
|
||||||
timer = wdCreate();
|
timer = wdCreate();
|
||||||
mutex = semMCreate(SEM_INVERSION_SAFE | SEM_Q_PRIORITY);
|
mutex = semMCreate(SEM_INVERSION_SAFE | SEM_Q_PRIORITY);
|
||||||
initDone = semBCreate(SEM_Q_FIFO, SEM_EMPTY);
|
initDone = semBCreate(SEM_Q_FIFO, SEM_EMPTY);
|
||||||
callbackSetCallback(expire, &timeoutCallback);
|
callbackSetCallback(expire, &timeoutCallback);
|
||||||
callbackSetUser(this, &timeoutCallback);
|
callbackSetUser(this, &timeoutCallback);
|
||||||
|
#else
|
||||||
|
timerQueue = &epicsTimerQueueActive::allocate(true);
|
||||||
|
timer = &timerQueue->createTimer();
|
||||||
#endif
|
#endif
|
||||||
callbackSetCallback(streamExecuteCommand, &commandCallback);
|
callbackSetCallback(streamExecuteCommand, &commandCallback);
|
||||||
callbackSetUser(this, &commandCallback);
|
callbackSetUser(this, &commandCallback);
|
||||||
@ -537,57 +555,57 @@ Stream::
|
|||||||
record->dpvt = NULL;
|
record->dpvt = NULL;
|
||||||
debug("~Stream(%s): dpvt cleared\n", name());
|
debug("~Stream(%s): dpvt cleared\n", name());
|
||||||
}
|
}
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
|
wdDelete(timer);
|
||||||
|
debug("~Stream(%s): watchdog destroyed\n", name());
|
||||||
|
#else
|
||||||
timer->destroy();
|
timer->destroy();
|
||||||
debug("~Stream(%s): timer destroyed\n", name());
|
debug("~Stream(%s): timer destroyed\n", name());
|
||||||
timerQueue->release();
|
timerQueue->release();
|
||||||
debug("~Stream(%s): timer queue released\n", name());
|
debug("~Stream(%s): timer queue released\n", name());
|
||||||
#else
|
|
||||||
wdDelete(timer);
|
|
||||||
debug("~Stream(%s): watchdog destroyed\n", name());
|
|
||||||
#endif
|
#endif
|
||||||
releaseMutex();
|
releaseMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
long Stream::
|
long Stream::
|
||||||
initRecord()
|
parseLink(const struct link *ioLink, char* filename,
|
||||||
|
char* protocol, char* busname, int* addr, char* busparam)
|
||||||
{
|
{
|
||||||
// scan link parameters: filename protocol busname addr busparam
|
// parse link parameters: filename protocol busname addr busparam
|
||||||
// It is safe to call this function again with different
|
|
||||||
// link text or different protocol file.
|
|
||||||
|
|
||||||
char filename[80];
|
|
||||||
char protocol[80];
|
|
||||||
char busname[80];
|
|
||||||
int addr = -1;
|
|
||||||
char busparam[80];
|
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if (ioLink->type != INST_IO)
|
if (ioLink->type != INST_IO)
|
||||||
{
|
{
|
||||||
error("%s: Wrong link type %s\n", name(),
|
error("%s: Wrong I/O link type %s\n", name(),
|
||||||
pamaplinkType[ioLink->type].strvalue);
|
pamaplinkType[ioLink->type].strvalue);
|
||||||
return S_dev_badInitRet;
|
return S_dev_badInitRet;
|
||||||
}
|
}
|
||||||
int items = sscanf(ioLink->value.instio.string, "%79s%79s%79s%n%i%n",
|
int items = sscanf(ioLink->value.instio.string, "%s%s%s%n%i%n",
|
||||||
filename, protocol, busname, &n, &addr, &n);
|
filename, protocol, busname, &n, addr, &n);
|
||||||
if (items <= 0)
|
if (items <= 0)
|
||||||
{
|
{
|
||||||
error("%s: Empty link. Forgot the leading '@' or confused INP with OUT ?\n",
|
error("%s: Empty I/O link. "
|
||||||
|
"Forgot the leading '@' or confused INP with OUT ?\n",
|
||||||
name());
|
name());
|
||||||
return S_dev_badInitRet;
|
return S_dev_badInitRet;
|
||||||
}
|
}
|
||||||
if (items < 3)
|
if (items < 3)
|
||||||
{
|
{
|
||||||
error("%s: Wrong link format\n"
|
error("%s: Wrong I/O link format\n"
|
||||||
" expect \"@file protocol bus addr params\"\n"
|
" expect \"@file protocol bus addr params\"\n"
|
||||||
" in \"@%s\"\n", name(),
|
" in \"@%s\"\n", name(),
|
||||||
ioLink->value.instio.string);
|
ioLink->value.instio.string);
|
||||||
return S_dev_badInitRet;
|
return S_dev_badInitRet;
|
||||||
}
|
}
|
||||||
memset(busparam, 0 ,80);
|
while (isspace((unsigned char)ioLink->value.instio.string[n])) n++;
|
||||||
for (n = 0; isspace((unsigned char)ioLink->value.instio.string[n]); n++);
|
strcpy (busparam, ioLink->value.constantStr+n);
|
||||||
strncpy (busparam, ioLink->value.constantStr+n, 79);
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
long Stream::
|
||||||
|
initRecord(const char* filename, const char* protocol,
|
||||||
|
const char* busname, int addr, const char* busparam)
|
||||||
|
{
|
||||||
|
// It is safe to call this function again with different arguments
|
||||||
|
|
||||||
// attach to bus interface
|
// attach to bus interface
|
||||||
if (!attachBus(busname, addr, busparam))
|
if (!attachBus(busname, addr, busparam))
|
||||||
@ -615,7 +633,8 @@ initRecord()
|
|||||||
name());
|
name());
|
||||||
if (record->scan == SCAN_IO_EVENT)
|
if (record->scan == SCAN_IO_EVENT)
|
||||||
{
|
{
|
||||||
debug("Stream::initRecord %s: restarting \"I/O Intr\" after reload\n",
|
debug("Stream::initRecord %s: "
|
||||||
|
"restarting \"I/O Intr\" after reload\n",
|
||||||
name());
|
name());
|
||||||
if (!startProtocol(StartAsync))
|
if (!startProtocol(StartAsync))
|
||||||
{
|
{
|
||||||
@ -640,10 +659,10 @@ initRecord()
|
|||||||
}
|
}
|
||||||
debug("Stream::initRecord %s: waiting for initDone\n",
|
debug("Stream::initRecord %s: waiting for initDone\n",
|
||||||
name());
|
name());
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
initDone.wait();
|
|
||||||
#else
|
|
||||||
semTake(initDone, WAIT_FOREVER);
|
semTake(initDone, WAIT_FOREVER);
|
||||||
|
#else
|
||||||
|
initDone.wait();
|
||||||
#endif
|
#endif
|
||||||
debug("Stream::initRecord %s: initDone\n",
|
debug("Stream::initRecord %s: initDone\n",
|
||||||
name());
|
name());
|
||||||
@ -669,8 +688,11 @@ process()
|
|||||||
{
|
{
|
||||||
if (status != NO_ALARM)
|
if (status != NO_ALARM)
|
||||||
{
|
{
|
||||||
debug("Stream::process(%s) error status=%d\n",
|
debug("Stream::process(%s) error status=%s (%d)\n",
|
||||||
name(), status);
|
name(),
|
||||||
|
status >= 0 && status < ALARM_NSTATUS ?
|
||||||
|
epicsAlarmConditionStrings[status] : "ERROR",
|
||||||
|
status);
|
||||||
(void) recGblSetSevr(record, status, INVALID_ALARM);
|
(void) recGblSetSevr(record, status, INVALID_ALARM);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -749,7 +771,8 @@ scan(format_t *format, void* value, size_t maxStringSize)
|
|||||||
break;
|
break;
|
||||||
case DBF_STRING:
|
case DBF_STRING:
|
||||||
sptr = (char*)value;
|
sptr = (char*)value;
|
||||||
currentValueLength = scanValue(*format->priv, sptr, maxStringSize);
|
currentValueLength = scanValue(*format->priv, sptr,
|
||||||
|
maxStringSize);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error("INTERNAL ERROR (%s): Illegal format type\n", name());
|
error("INTERNAL ERROR (%s): Illegal format type\n", name());
|
||||||
@ -767,20 +790,20 @@ scan(format_t *format, void* value, size_t maxStringSize)
|
|||||||
|
|
||||||
// epicsTimerNotify virtual method ///////////////////////////////////////
|
// epicsTimerNotify virtual method ///////////////////////////////////////
|
||||||
|
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
epicsTimerNotify::expireStatus Stream::
|
|
||||||
expire(const epicsTime&)
|
|
||||||
{
|
|
||||||
timerCallback();
|
|
||||||
return noRestart;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void Stream::
|
void Stream::
|
||||||
expire(CALLBACK *pcallback)
|
expire(CALLBACK *pcallback)
|
||||||
{
|
{
|
||||||
Stream* pstream = static_cast<Stream*>(pcallback->user);
|
Stream* pstream = static_cast<Stream*>(pcallback->user);
|
||||||
pstream->timerCallback();
|
pstream->timerCallback();
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
epicsTimerNotify::expireStatus Stream::
|
||||||
|
expire(const epicsTime&)
|
||||||
|
{
|
||||||
|
timerCallback();
|
||||||
|
return noRestart;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// StreamCore virtual methods ////////////////////////////////////////////
|
// StreamCore virtual methods ////////////////////////////////////////////
|
||||||
@ -840,10 +863,10 @@ protocolFinishHook(ProtocolResult result)
|
|||||||
}
|
}
|
||||||
if (flags & InitRun)
|
if (flags & InitRun)
|
||||||
{
|
{
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
initDone.signal();
|
|
||||||
#else
|
|
||||||
semGive(initDone);
|
semGive(initDone);
|
||||||
|
#else
|
||||||
|
initDone.signal();
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -896,13 +919,13 @@ startTimer(unsigned long timeout)
|
|||||||
{
|
{
|
||||||
debug("Stream::startTimer(stream=%s, timeout=%lu) = %f seconds\n",
|
debug("Stream::startTimer(stream=%s, timeout=%lu) = %f seconds\n",
|
||||||
name(), timeout, timeout * 0.001);
|
name(), timeout, timeout * 0.001);
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
timer->start(*this, timeout * 0.001);
|
|
||||||
#else
|
|
||||||
callbackSetPriority(priority(), &timeoutCallback);
|
callbackSetPriority(priority(), &timeoutCallback);
|
||||||
wdStart(timer, (timeout+1)*sysClkRateGet()/1000-1,
|
wdStart(timer, (timeout+1)*sysClkRateGet()/1000-1,
|
||||||
reinterpret_cast<FUNCPTR>(callbackRequest),
|
reinterpret_cast<FUNCPTR>(callbackRequest),
|
||||||
reinterpret_cast<int>(&timeoutCallback));
|
reinterpret_cast<int>(&timeoutCallback));
|
||||||
|
#else
|
||||||
|
timer->start(*this, timeout * 0.001);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -962,7 +985,8 @@ formatValue(const StreamFormat& format, const void* fieldaddress)
|
|||||||
|
|
||||||
if (format.type != double_format)
|
if (format.type != double_format)
|
||||||
{
|
{
|
||||||
error ("%s: can only read double values from TIME field\n", name());
|
error ("%s: can only read double values from TIME field\n",
|
||||||
|
name());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (pdbaddr->precord == record)
|
if (pdbaddr->precord == record)
|
||||||
@ -970,8 +994,10 @@ formatValue(const StreamFormat& format, const void* fieldaddress)
|
|||||||
/* if getting time from own record, update timestamp first */
|
/* if getting time from own record, update timestamp first */
|
||||||
recGblGetTimeStamp(record);
|
recGblGetTimeStamp(record);
|
||||||
}
|
}
|
||||||
time = pdbaddr->precord->time.secPastEpoch + 631152000u + pdbaddr->precord->time.nsec * 1e-9;
|
time = pdbaddr->precord->time.secPastEpoch +
|
||||||
debug("Stream::formatValue(%s): read %f from TIME field\n", name(), time);
|
631152000u + pdbaddr->precord->time.nsec * 1e-9;
|
||||||
|
debug("Stream::formatValue(%s): read %f from TIME field\n",
|
||||||
|
name(), time);
|
||||||
return printValue(format, time);
|
return printValue(format, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1009,7 +1035,8 @@ formatValue(const StreamFormat& format, const void* fieldaddress)
|
|||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
case pseudo_format:
|
case pseudo_format:
|
||||||
error("%s: %%(FIELD) syntax not allowed with pseudo formats\n",
|
error("%s: %%(FIELD) syntax not allowed "
|
||||||
|
"with pseudo formats\n",
|
||||||
name());
|
name());
|
||||||
default:
|
default:
|
||||||
error("INTERNAL ERROR %s: Illegal format.type=%d\n",
|
error("INTERNAL ERROR %s: Illegal format.type=%d\n",
|
||||||
@ -1059,7 +1086,8 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
|
|||||||
buffer = fieldBuffer.clear().reserve(size);
|
buffer = fieldBuffer.clear().reserve(size);
|
||||||
for (nord = 0; nord < nelem; nord++)
|
for (nord = 0; nord < nelem; nord++)
|
||||||
{
|
{
|
||||||
debug("Stream::matchValue(%s): buffer before: %s\n", name(), fieldBuffer.expand()());
|
debug("Stream::matchValue(%s): buffer before: %s\n",
|
||||||
|
name(), fieldBuffer.expand()());
|
||||||
switch (format.type)
|
switch (format.type)
|
||||||
{
|
{
|
||||||
case long_format:
|
case long_format:
|
||||||
@ -1073,7 +1101,8 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
|
|||||||
case enum_format:
|
case enum_format:
|
||||||
{
|
{
|
||||||
consumed = scanValue(format, lval);
|
consumed = scanValue(format, lval);
|
||||||
if (consumed >= 0) ((epicsUInt16*)buffer)[nord] = (epicsUInt16)lval;
|
if (consumed >= 0)
|
||||||
|
((epicsUInt16*)buffer)[nord] = (epicsUInt16)lval;
|
||||||
debug("Stream::matchValue(%s): %s[%li] = %li\n",
|
debug("Stream::matchValue(%s): %s[%li] = %li\n",
|
||||||
name(), pdbaddr->precord->name, nord, lval);
|
name(), pdbaddr->precord->name, nord, lval);
|
||||||
break;
|
break;
|
||||||
@ -1081,10 +1110,13 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
|
|||||||
case double_format:
|
case double_format:
|
||||||
{
|
{
|
||||||
consumed = scanValue(format, dval);
|
consumed = scanValue(format, dval);
|
||||||
// Direct assignment to buffer fails fith gcc 3.4.3 for xscale_be
|
// Direct assignment to buffer fails with
|
||||||
|
// gcc 3.4.3 for xscale_be
|
||||||
// Optimization bug?
|
// Optimization bug?
|
||||||
epicsFloat64 f64=dval;
|
epicsFloat64 f64=dval;
|
||||||
if (consumed >= 0) memcpy(((epicsFloat64*)buffer)+nord, &f64, sizeof(f64));
|
if (consumed >= 0)
|
||||||
|
memcpy(((epicsFloat64*)buffer)+nord,
|
||||||
|
&f64, sizeof(f64));
|
||||||
debug("Stream::matchValue(%s): %s[%li] = %#g %#g\n",
|
debug("Stream::matchValue(%s): %s[%li] = %#g %#g\n",
|
||||||
name(), pdbaddr->precord->name, nord, dval,
|
name(), pdbaddr->precord->name, nord, dval,
|
||||||
((epicsFloat64*)buffer)[nord]);
|
((epicsFloat64*)buffer)[nord]);
|
||||||
@ -1095,7 +1127,8 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
|
|||||||
consumed = scanValue(format,
|
consumed = scanValue(format,
|
||||||
buffer+MAX_STRING_SIZE*nord, MAX_STRING_SIZE);
|
buffer+MAX_STRING_SIZE*nord, MAX_STRING_SIZE);
|
||||||
debug("Stream::matchValue(%s): %s[%li] = \"%.*s\"\n",
|
debug("Stream::matchValue(%s): %s[%li] = \"%.*s\"\n",
|
||||||
name(), pdbaddr->precord->name, nord, MAX_STRING_SIZE, buffer+MAX_STRING_SIZE*nord);
|
name(), pdbaddr->precord->name, nord,
|
||||||
|
MAX_STRING_SIZE, buffer+MAX_STRING_SIZE*nord);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -1103,7 +1136,8 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
|
|||||||
"Illegal format type\n", name());
|
"Illegal format type\n", name());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
debug("Stream::matchValue(%s): buffer after: %s\n", name(), fieldBuffer.expand()());
|
debug("Stream::matchValue(%s): buffer after: %s\n",
|
||||||
|
name(), fieldBuffer.expand()());
|
||||||
if (consumed < 0) break;
|
if (consumed < 0) break;
|
||||||
consumedInput += consumed;
|
consumedInput += consumed;
|
||||||
}
|
}
|
||||||
@ -1112,7 +1146,8 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
|
|||||||
// scan error: set other record to alarm status
|
// scan error: set other record to alarm status
|
||||||
if (pdbaddr->precord != record)
|
if (pdbaddr->precord != record)
|
||||||
{
|
{
|
||||||
(void) recGblSetSevr(pdbaddr->precord, CALC_ALARM, INVALID_ALARM);
|
(void) recGblSetSevr(pdbaddr->precord,
|
||||||
|
CALC_ALARM, INVALID_ALARM);
|
||||||
if (!INIT_RUN)
|
if (!INIT_RUN)
|
||||||
{
|
{
|
||||||
// process other record to send alarm monitor
|
// process other record to send alarm monitor
|
||||||
@ -1126,19 +1161,24 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
|
|||||||
#ifdef epicsTimeEventDeviceTime
|
#ifdef epicsTimeEventDeviceTime
|
||||||
if (format.type != double_format)
|
if (format.type != double_format)
|
||||||
{
|
{
|
||||||
error ("%s: can only write double values to TIME field\n", name());
|
error ("%s: can only write double values to TIME field\n",
|
||||||
|
name());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
dval = dval-631152000u;
|
dval = dval-631152000u;
|
||||||
pdbaddr->precord->time.secPastEpoch = (long)dval;
|
pdbaddr->precord->time.secPastEpoch = (long)dval;
|
||||||
/* rouding: we don't have 9 digits precision in a double of today's number of seconds */
|
// 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;
|
pdbaddr->precord->time.nsec = (long)((dval-(long)dval)*1e6)*1000;
|
||||||
debug("Stream::matchValue(%s): writing %i.%i to TIME field\n", name(),
|
debug("Stream::matchValue(%s): writing %i.%i to TIME field\n",
|
||||||
pdbaddr->precord->time.secPastEpoch, pdbaddr->precord->time.nsec);
|
name(),
|
||||||
|
pdbaddr->precord->time.secPastEpoch,
|
||||||
|
pdbaddr->precord->time.nsec);
|
||||||
pdbaddr->precord->tse = epicsTimeEventDeviceTime;
|
pdbaddr->precord->tse = epicsTimeEventDeviceTime;
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
error ("%s: writing TIME field is not supported in this EPICS version\n", name());
|
error ("%s: writing TIME field is not supported "
|
||||||
|
"in this EPICS version\n", name());
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -1171,7 +1211,8 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
|
|||||||
((dbFldDes*)pdbaddr->pfldDes)->name,
|
((dbFldDes*)pdbaddr->pfldDes)->name,
|
||||||
fieldBuffer.expand()());
|
fieldBuffer.expand()());
|
||||||
putfunc = "dbPutField";
|
putfunc = "dbPutField";
|
||||||
status = dbPutField(pdbaddr, dbfMapping[format.type], buffer, nord);
|
status = dbPutField(pdbaddr, dbfMapping[format.type],
|
||||||
|
buffer, nord);
|
||||||
}
|
}
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
{
|
{
|
||||||
@ -1234,13 +1275,15 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
// Pass command to iocsh
|
// Pass command to vxWorks shell
|
||||||
|
extern "C" int execute(const char *cmd);
|
||||||
|
|
||||||
void streamExecuteCommand(CALLBACK *pcallback)
|
void streamExecuteCommand(CALLBACK *pcallback)
|
||||||
{
|
{
|
||||||
Stream* pstream = static_cast<Stream*>(pcallback->user);
|
Stream* pstream = static_cast<Stream*>(pcallback->user);
|
||||||
|
|
||||||
if (iocshCmd(pstream->outputLine()) != OK)
|
if (execute(pstream->outputLine()) != OK)
|
||||||
{
|
{
|
||||||
pstream->execCallback(StreamIoFault);
|
pstream->execCallback(StreamIoFault);
|
||||||
}
|
}
|
||||||
@ -1250,14 +1293,12 @@ void streamExecuteCommand(CALLBACK *pcallback)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// Pass command to vxWorks shell
|
// Pass command to iocsh
|
||||||
extern "C" int execute(const char *cmd);
|
|
||||||
|
|
||||||
void streamExecuteCommand(CALLBACK *pcallback)
|
void streamExecuteCommand(CALLBACK *pcallback)
|
||||||
{
|
{
|
||||||
Stream* pstream = static_cast<Stream*>(pcallback->user);
|
Stream* pstream = static_cast<Stream*>(pcallback->user);
|
||||||
|
|
||||||
if (execute(pstream->outputLine()) != OK)
|
if (iocshCmd(pstream->outputLine()) != OK)
|
||||||
{
|
{
|
||||||
pstream->execCallback(StreamIoFault);
|
pstream->execCallback(StreamIoFault);
|
||||||
}
|
}
|
||||||
@ -1279,19 +1320,19 @@ execute()
|
|||||||
void Stream::
|
void Stream::
|
||||||
lockMutex()
|
lockMutex()
|
||||||
{
|
{
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
mutex.lock();
|
|
||||||
#else
|
|
||||||
semTake(mutex, WAIT_FOREVER);
|
semTake(mutex, WAIT_FOREVER);
|
||||||
|
#else
|
||||||
|
mutex.lock();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::
|
void Stream::
|
||||||
releaseMutex()
|
releaseMutex()
|
||||||
{
|
{
|
||||||
#ifdef EPICS_3_14
|
#ifdef EPICS_3_13
|
||||||
mutex.unlock();
|
|
||||||
#else
|
|
||||||
semGive(mutex);
|
semGive(mutex);
|
||||||
|
#else
|
||||||
|
mutex.unlock();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
#define devStream_h
|
#define devStream_h
|
||||||
|
|
||||||
#define STREAM_MAJOR 2
|
#define STREAM_MAJOR 2
|
||||||
#define STREAM_MINOR 5
|
#define STREAM_MINOR 6
|
||||||
#define STREAM_PATCHLEVEL 11
|
#define STREAM_PATCHLEVEL 0
|
||||||
|
|
||||||
#if defined(__vxworks) || defined(vxWorks)
|
#if defined(__vxworks) || defined(vxWorks)
|
||||||
#include <vxWorks.h>
|
#include <vxWorks.h>
|
||||||
@ -41,11 +41,11 @@
|
|||||||
#define INIT_RUN (!interruptAccept)
|
#define INIT_RUN (!interruptAccept)
|
||||||
|
|
||||||
#include <epicsVersion.h>
|
#include <epicsVersion.h>
|
||||||
#if (EPICS_VERSION == 3 && EPICS_REVISION == 14)
|
#ifdef BASE_RELEASE
|
||||||
#define EPICS_3_14
|
#define EPICS_3_13
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__cplusplus) && !defined(EPICS_3_14)
|
#if defined(__cplusplus) && defined(EPICS_3_13)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ extern "C" {
|
|||||||
/* #include <dbFldTypes.h> */
|
/* #include <dbFldTypes.h> */
|
||||||
#include <dbAccess.h>
|
#include <dbAccess.h>
|
||||||
|
|
||||||
#if defined(__cplusplus) && !defined(EPICS_3_14)
|
#if defined(__cplusplus) && defined(EPICS_3_13)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -77,11 +77,13 @@ extern const char StreamVersion [];
|
|||||||
typedef long (*streamIoFunction) (dbCommon*, format_t*);
|
typedef long (*streamIoFunction) (dbCommon*, format_t*);
|
||||||
|
|
||||||
epicsShareExtern long streamInit(int after);
|
epicsShareExtern long streamInit(int after);
|
||||||
epicsShareExtern long streamInitRecord(dbCommon *record, struct link *ioLink,
|
epicsShareExtern long streamInitRecord(dbCommon *record,
|
||||||
|
const struct link *ioLink,
|
||||||
streamIoFunction readData, streamIoFunction writeData);
|
streamIoFunction readData, streamIoFunction writeData);
|
||||||
epicsShareExtern long streamReport(int interest);
|
epicsShareExtern long streamReport(int interest);
|
||||||
epicsShareExtern long streamReadWrite(dbCommon *record);
|
epicsShareExtern long streamReadWrite(dbCommon *record);
|
||||||
epicsShareExtern long streamGetIointInfo(int cmd, dbCommon *record, IOSCANPVT *ppvt);
|
epicsShareExtern long streamGetIointInfo(int cmd,
|
||||||
|
dbCommon *record, IOSCANPVT *ppvt);
|
||||||
epicsShareExtern long streamPrintf(dbCommon *record, format_t *format, ...);
|
epicsShareExtern long streamPrintf(dbCommon *record, format_t *format, ...);
|
||||||
epicsShareExtern long streamScanfN(dbCommon *record, format_t *format,
|
epicsShareExtern long streamScanfN(dbCommon *record, format_t *format,
|
||||||
void*, size_t maxStringSize);
|
void*, size_t maxStringSize);
|
||||||
|
@ -29,17 +29,10 @@ PROD_SRCS_vxWorks = -nil-
|
|||||||
PROD_LIBS = stream
|
PROD_LIBS = stream
|
||||||
|
|
||||||
ifdef ASYN
|
ifdef ASYN
|
||||||
# Which types of asyn busses do you have?
|
# edit asynRegistrars.dbd if necessary
|
||||||
|
streamApp_DBD += asynRegistrars.dbd
|
||||||
# asynDriver up to version 4-16 does not support serial port for Windows!
|
# add asyn.dbd if you want to have asyn Record and asyn device supports
|
||||||
#ifneq ($(OS_CLASS), WIN32)
|
# streamApp_DBD += asyn.dbd
|
||||||
streamApp_DBD += drvAsynSerialPort.dbd
|
|
||||||
#endif
|
|
||||||
|
|
||||||
streamApp_DBD += drvAsynIPPort.dbd
|
|
||||||
#streamApp_DBD += drvGsIP488.dbd
|
|
||||||
#streamApp_DBD += drvNi1014.dbd
|
|
||||||
streamApp_DBD += drvVxi11.dbd
|
|
||||||
PROD_LIBS += asyn
|
PROD_LIBS += asyn
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -73,7 +66,11 @@ CPPFLAGS += -DDEBUGFILE=StreamDebug.log
|
|||||||
|
|
||||||
include $(TOP)/configure/RULES
|
include $(TOP)/configure/RULES
|
||||||
|
|
||||||
|
ifeq ($(EPICS_REVISION),14)
|
||||||
clean:: myclean
|
clean:: myclean
|
||||||
|
else
|
||||||
|
clean: myclean
|
||||||
|
endif
|
||||||
|
|
||||||
myclean:
|
myclean:
|
||||||
$(RM) core* StreamDebug.log
|
$(RM) core* StreamDebug.log
|
||||||
|
9
streamApp/asynRegistrars.dbd
Normal file
9
streamApp/asynRegistrars.dbd
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
registrar(asynRegister)
|
||||||
|
registrar(asynInterposeFlushRegister)
|
||||||
|
registrar(asynInterposeEosRegister)
|
||||||
|
|
||||||
|
# asynDriver up to version 4-16 does not support serial port for Windows!
|
||||||
|
registrar(drvAsynSerialPortRegisterCommands)
|
||||||
|
registrar(drvAsynIPPortRegisterCommands)
|
||||||
|
registrar(drvAsynIPServerPortRegisterCommands)
|
||||||
|
registrar(vxi11RegisterCommands)
|
Reference in New Issue
Block a user