diff -rc ../StreamDevice-2-1/src/AsynDriver4-3Interface.cc ./src/AsynDriver4-3Interface.cc *** ../StreamDevice-2-1/src/AsynDriver4-3Interface.cc Tue May 30 18:08:53 2006 --- ./src/AsynDriver4-3Interface.cc Wed Jun 14 16:32:53 2006 *************** *** 123,134 **** } enum IoAction { ! None, Lock, Write, Read, AsyncRead, AsyncReadMore, ReceiveEvent }; static const char* ioActionStr[] = { "None", "Lock", "Write", "Read", ! "AsyncRead", "AsyncReadMore", "ReceiveEvent" }; class AsynDriverInterface : StreamBusInterface , epicsTimerNotify --- 123,136 ---- } enum IoAction { ! None, Lock, Write, Read, AsyncRead, AsyncReadMore, ReceiveEvent, ! Connect, Disconnect }; static const char* ioActionStr[] = { "None", "Lock", "Write", "Read", ! "AsyncRead", "AsyncReadMore", "ReceiveEvent", ! "Connect", "Disconnect" }; class AsynDriverInterface : StreamBusInterface , epicsTimerNotify *************** *** 174,179 **** --- 176,183 ---- bool acceptEvent(unsigned long mask, unsigned long replytimeout_ms); bool supportsEvent(); bool supportsAsyncRead(); + bool connectRequest(unsigned long connecttimeout_ms); + bool disconnect(); // epicsTimerNotify methods epicsTimerNotify::expireStatus expire(const epicsTime &); *************** *** 183,188 **** --- 187,194 ---- void lockHandler(); void writeHandler(); void readHandler(); + void connectHandler(); + void disconnectHandler(); bool connectToAsynPort(); void asynReadHandler(char *data, size_t numchars); asynQueuePriority priority() { *************** *** 820,825 **** --- 826,832 ---- epicsTimerNotify::expireStatus AsynDriverInterface:: expire(const epicsTime &) { + int autoconnect, connected; debug("AsynDriverInterface::expire(%s)\n", clientName()); switch (ioAction) { *************** *** 837,845 **** case AsyncRead: // no async input for some time, thus let's poll // queueRequest might fail if another request just queued ! pasynManager->queueRequest(pasynUser, ! asynQueuePriorityLow, replyTimeout); ! // continues with handleRequest() or handleTimeout() return noRestart; default: error("INTERNAL ERROR (%s): expire() unexpected ioAction %s\n", --- 844,863 ---- case AsyncRead: // no async input for some time, thus let's poll // queueRequest might fail if another request just queued ! pasynManager->isAutoConnect(pasynUser, &autoconnect); ! pasynManager->isConnected(pasynUser, &connected); ! if (autoconnect && !connected) ! { ! // has explicitely been disconnected ! // a poll would autoConnect which is not what we want ! startTimer(replyTimeout); ! } ! else ! { ! pasynManager->queueRequest(pasynUser, ! asynQueuePriorityLow, replyTimeout); ! // continues with handleRequest() or handleTimeout() ! } return noRestart; default: error("INTERNAL ERROR (%s): expire() unexpected ioAction %s\n", *************** *** 848,853 **** --- 866,934 ---- } } + bool AsynDriverInterface:: + connectRequest(unsigned long connecttimeout_ms) + { + double queueTimeout = connecttimeout_ms*0.001; + asynStatus status; + ioAction = Connect; + status = pasynManager->queueRequest(pasynUser, + asynQueuePriorityConnect, queueTimeout); + if (status != asynSuccess) + { + error("%s connectRequest: pasynManager->queueRequest() failed: %s\n", + clientName(), pasynUser->errorMessage); + return false; + } + // continues with handleRequest() or handleTimeout() + return true; + } + + void AsynDriverInterface:: + connectHandler() + { + asynStatus status; + status = pasynCommon->connect(pvtCommon, pasynUser); + if (status != asynSuccess) + { + error("%s connectRequest: pasynCommon->connect() failed: %s\n", + clientName(), pasynUser->errorMessage); + connectCallback(ioFault); + return; + } + connectCallback(ioSuccess); + } + + bool AsynDriverInterface:: + disconnect() + { + asynStatus status; + ioAction = Disconnect; + status = pasynManager->queueRequest(pasynUser, + asynQueuePriorityConnect, 0.0); + if (status != asynSuccess) + { + error("%s disconnect: pasynManager->queueRequest() failed: %s\n", + clientName(), pasynUser->errorMessage); + return false; + } + // continues with handleRequest() or handleTimeout() + return true; + } + + void AsynDriverInterface:: + disconnectHandler() + { + asynStatus status; + status = pasynCommon->disconnect(pvtCommon, pasynUser); + if (status != asynSuccess) + { + error("%s connectRequest: pasynCommon->disconnect() failed: %s\n", + clientName(), pasynUser->errorMessage); + return; + } + } + // asynUser callbacks to pasynManager->queueRequest() void handleRequest(asynUser* pasynUser) *************** *** 870,875 **** --- 951,962 ---- case Read: // sync input interface->readHandler(); break; + case Connect: + interface->connectHandler(); + break; + case Disconnect: + interface->disconnectHandler(); + break; default: error("INTERNAL ERROR (%s): " "handleRequest() unexpected ioAction %s\n", *************** *** 895,904 **** interface->readCallback(AsynDriverInterface::ioFault, NULL, 0); break; case AsyncRead: // async poll failed, try later ! debug("AsynDriverInterface::handleTimeout(%s): " ! "restart timer(%g seconds)\n", ! interface->clientName(), interface->replyTimeout); ! interface->startTimer(interface->replyTimeout); break; default: error("INTERNAL ERROR (%s): handleTimeout() " --- 982,994 ---- interface->readCallback(AsynDriverInterface::ioFault, NULL, 0); break; case AsyncRead: // async poll failed, try later ! interface->startTimer(interface->replyTimeout); ! break; ! case Connect: ! interface->connectCallback(AsynDriverInterface::ioTimeout); ! break; ! case Disconnect: ! // not interested in callback break; default: error("INTERNAL ERROR (%s): handleTimeout() " diff -rc ../StreamDevice-2-1/src/StreamBusInterface.cc ./src/StreamBusInterface.cc *** ../StreamDevice-2-1/src/StreamBusInterface.cc Wed May 17 13:29:51 2006 --- ./src/StreamBusInterface.cc Wed Jun 14 15:54:31 2006 *************** *** 81,83 **** --- 81,106 ---- delete this; } + bool StreamBusInterface:: + connectRequest (unsigned long) + { + return false; + } + + bool StreamBusInterface:: + disconnect () + { + return false; + } + + bool StreamBusInterface:: + writeRequest(const void*, size_t, unsigned long) + { + return false; + } + + bool StreamBusInterface:: + readRequest(unsigned long, unsigned long, long, bool) + { + return false; + } diff -rc ../StreamDevice-2-1/src/StreamBusInterface.h ./src/StreamBusInterface.h *** ../StreamDevice-2-1/src/StreamBusInterface.h Wed May 17 13:29:51 2006 --- ./src/StreamBusInterface.h Wed Jun 14 16:43:13 2006 *************** *** 31,40 **** { friend class StreamBusInterface; virtual void lockCallback(IoStatus status) = 0; ! virtual void writeCallback(IoStatus status) = 0; virtual long readCallback(IoStatus status, ! const void* input, long size) = 0; ! virtual void eventCallback(IoStatus status) = 0; virtual long priority() = 0; virtual const char* name() = 0; --- 31,41 ---- { friend class StreamBusInterface; virtual void lockCallback(IoStatus status) = 0; ! virtual void writeCallback(IoStatus status) {} virtual long readCallback(IoStatus status, ! const void* input, long size) { return 0; } ! virtual void eventCallback(IoStatus status) {} ! virtual void connectCallback(StreamBusInterface::IoStatus status) {} virtual long priority() = 0; virtual const char* name() = 0; *************** *** 72,77 **** --- 73,84 ---- return businterface->readRequest(replytimeout_ms, readtimeout_ms, expectedLength, async); } + bool busConnectRequest(unsigned long timeout_ms) { + return businterface->connectRequest(timeout_ms); + } + bool busDisconnect() { + return businterface->disconnect(); + } }; private: *************** *** 86,91 **** --- 93,100 ---- const char* eos; size_t eoslen; StreamBusInterface(Client* client); + + // map client functions into StreamBusInterface namespace void lockCallback(IoStatus status) { client->lockCallback(status); } void writeCallback(IoStatus status) *************** *** 95,119 **** { return client->readCallback(status, input, size); } void eventCallback(IoStatus status) { client->eventCallback(status); } long priority() { return client->priority(); } const char* clientName() { return client->name(); } // default implementations virtual bool setEos(const char* eos, size_t eoslen); virtual bool supportsEvent(); // defaults to false virtual bool supportsAsyncRead(); // defaults to false virtual bool acceptEvent(unsigned long mask, // implement if unsigned long replytimeout_ms); // supportsEvents() returns true virtual void release(); // pure virtual virtual bool lockRequest(unsigned long timeout_ms) = 0; virtual bool unlock() = 0; - virtual bool writeRequest(const void* output, size_t size, - unsigned long timeout_ms) = 0; - virtual bool readRequest(unsigned long replytimeout_ms, - unsigned long readtimeout_ms, long expectedLength, - bool async) = 0; public: // static methods --- 104,132 ---- { return client->readCallback(status, input, size); } void eventCallback(IoStatus status) { client->eventCallback(status); } + void connectCallback(IoStatus status) + { client->connectCallback(status); } long priority() { return client->priority(); } const char* clientName() { return client->name(); } // default implementations + virtual bool writeRequest(const void* output, size_t size, + unsigned long timeout_ms); + virtual bool readRequest(unsigned long replytimeout_ms, + unsigned long readtimeout_ms, long expectedLength, + bool async); virtual bool setEos(const char* eos, size_t eoslen); virtual bool supportsEvent(); // defaults to false virtual bool supportsAsyncRead(); // defaults to false virtual bool acceptEvent(unsigned long mask, // implement if unsigned long replytimeout_ms); // supportsEvents() returns true virtual void release(); + virtual bool connectRequest(unsigned long connecttimeout_ms); + virtual bool disconnect(); // pure virtual virtual bool lockRequest(unsigned long timeout_ms) = 0; virtual bool unlock() = 0; public: // static methods diff -rc ../StreamDevice-2-1/src/StreamCore.cc ./src/StreamCore.cc *** ../StreamDevice-2-1/src/StreamCore.cc Tue May 30 18:09:12 2006 --- ./src/StreamCore.cc Wed Jun 14 16:44:06 2006 *************** *** 23,30 **** #include #include ! enum Commands { end_cmd, in_cmd, out_cmd, wait_cmd, event_cmd, exec_cmd }; ! const char* commandStr[] = { "end", "in", "out", "wait", "event", "exec" }; inline const char* commandName(unsigned char i) { --- 23,32 ---- #include #include ! enum Commands { end_cmd, in_cmd, out_cmd, wait_cmd, event_cmd, exec_cmd, ! connect_cmd, disconnect_cmd }; ! const char* commandStr[] = { "end", "in", "out", "wait", "event", "exec", ! "connect", "disconnect" }; inline const char* commandName(unsigned char i) { *************** *** 69,74 **** --- 71,83 ---- c = StreamProtocolParser::printString(buffer, c); buffer.append("\";\n"); break; + case connect_cmd: + timeout = extract(c); + buffer.append(" connect %ld;\n", timeout); + break; + case disconnect_cmd: + buffer.append(" disconnect;\n"); + break; default: buffer.append("\033[31;1mGARBAGE: "); c = StreamProtocolParser::printString(buffer, c-1); *************** *** 356,361 **** --- 365,386 ---- buffer.append(StreamProtocolParser::eos); return true; } + if (strcmp(command, commandStr[connect_cmd]) == 0) + { + buffer.append(connect_cmd); + if (!protocol->compileNumber(timeout, args)) + { + return false; + } + buffer.append(&timeout, sizeof(timeout)); + return true; + } + if (strcmp(command, commandStr[disconnect_cmd]) == 0) + { + buffer.append(disconnect_cmd); + return true; + } + protocol->errorMsg(getLineNumber(command), "Unknown command name '%s'\n", command); return false; *************** *** 510,515 **** --- 535,544 ---- case end_cmd: finishProtocol(Success); return true; + case connect_cmd: + return evalConnect(); + case disconnect_cmd: + return evalDisconnect(); default: error("INTERNAL ERROR (%s): illegal command code 0x%02x\n", name(), *activeCommand); *************** *** 1317,1319 **** --- 1346,1389 ---- name()); return false; } + + bool StreamCore::evalConnect() + { + unsigned long connectTimeout = extract(commandIndex); + if (!busConnectRequest(connectTimeout)) + { + error("%s: Connect not supported for this bus\n", + name()); + return false; + } + return true; + } + + void StreamCore:: + connectCallback(StreamBusInterface::IoStatus status) + { + switch (status) + { + case StreamBusInterface::ioSuccess: + evalCommand(); + return; + default: + error("%s: Connect failed\n", + name()); + finishProtocol(Fault); + return; + } + } + + bool StreamCore::evalDisconnect() + { + if (!busDisconnect()) + { + error("%s: Cannot disconnect from this bus\n", + name()); + finishProtocol(Fault); + return false; + } + evalCommand(); + return true; + } diff -rc ../StreamDevice-2-1/src/StreamCore.h ./src/StreamCore.h *** ../StreamDevice-2-1/src/StreamCore.h Tue May 30 16:40:24 2006 --- ./src/StreamCore.h Wed Jun 14 15:52:37 2006 *************** *** 178,183 **** --- 178,185 ---- bool evalEvent(); bool evalWait(); bool evalExec(); + bool evalConnect(); + bool evalDisconnect(); bool formatOutput(); bool matchInput(); bool matchSeparator(); *************** *** 196,201 **** --- 198,204 ---- const void* input, long size); void eventCallback(StreamBusInterface::IoStatus status); void execCallback(StreamBusInterface::IoStatus status); + void connectCallback(StreamBusInterface::IoStatus status); // virtual methods virtual void protocolStartHook() {} diff -rc ../StreamDevice-2-1/src/StreamProtocol.cc ./src/StreamProtocol.cc *** ../StreamDevice-2-1/src/StreamProtocol.cc Wed Jun 14 16:30:00 2006 --- ./src/StreamProtocol.cc Wed Jun 14 13:15:45 2006 *************** *** 356,369 **** return false; } } ! // append new protocol to parser ! *ppP = new Protocol(protocol, token, startline); ! if (!parseProtocol(**ppP, (*ppP)->commands)) { line = startline; errorMsg("in protocol '%s'\n", token()); return false; } continue; } // Must be a command or a protocol reference. --- 356,371 ---- return false; } } ! Protocol* pP = new Protocol(protocol, token, startline); ! if (!parseProtocol(*pP, pP->commands)) { line = startline; errorMsg("in protocol '%s'\n", token()); + delete pP; return false; } + // append new protocol to parser + *ppP = pP; continue; } // Must be a command or a protocol reference. diff -rc ../StreamDevice-2-1/doc/protocol.html ./doc/protocol.html *** ../StreamDevice-2-1/doc/protocol.html Wed Jun 14 16:58:45 2006 --- ./doc/protocol.html Wed Jun 14 17:04:24 2006 *************** *** 125,133 ****

3. Commands

! Five different commands can be used in a protocol: out, in, wait, event, ! and exec. Most protocols will consist only of a single out command to write some value, or an out command followed by an in command to --- 125,133 ----

3. Commands

! Seven different commands can be used in a protocol: out, in, wait, event, ! exec, disconnect, and connect. Most protocols will consist only of a single out command to write some value, or an out command followed by an in command to *************** *** 182,189 **** This is probably not supported by all busses. Any in or out command will automatically reconnect. ! Only records which are ! processed "I/O Intr" will not cause a reconnect.

connect milliseconds;
--- 182,189 ---- This is probably not supported by all busses. Any in or out command will automatically reconnect. ! Only records reading in ! "I/O Intr" mode will not cause a reconnect.
connect milliseconds;