Avoid repeated messages for errors from asyn layer

This is done by remembering the last asynStatus in the AsynDriverInterface
object. In certain selected places, namely when pasynManager->queueRequest
or pasynCommon->connect is called, we report an error only if the new status
differs from the last one. This gives us just one message when the failure
occurs (or when the operation is tried for the first time) and another
message when the status returns back to asynSuccess.

Note this is currently limited to AsynDriverInterface. If a device is online
but responds in unexpected ways (including not at all) StreamDevice will
still report errors repeatedly whenever records are processed. Fixing this
is very well possible but beyond the scope of this patch.
This commit is contained in:
Benjamin Franksen
2017-11-27 19:01:11 +01:00
parent f2ceb71c2b
commit ca01ba7c35

View File

@ -171,6 +171,7 @@ class AsynDriverInterface : StreamBusInterface
epicsTimerQueueActive* timerQueue; epicsTimerQueueActive* timerQueue;
epicsTimer* timer; epicsTimer* timer;
#endif #endif
asynStatus previousAsynStatus;
AsynDriverInterface(Client* client); AsynDriverInterface(Client* client);
~AsynDriverInterface(); ~AsynDriverInterface();
@ -229,6 +230,7 @@ class AsynDriverInterface : StreamBusInterface
timer->cancel(); timer->cancel();
#endif #endif
} }
void reportAsynStatus(asynStatus status, const char *name);
// asynUser callback functions // asynUser callback functions
friend void handleRequest(asynUser*); friend void handleRequest(asynUser*);
@ -262,6 +264,7 @@ AsynDriverInterface(Client* client) : StreamBusInterface(client)
eventMask = 0; eventMask = 0;
receivedEvent = 0; receivedEvent = 0;
peeksize = 1; peeksize = 1;
previousAsynStatus = asynSuccess;
debug ("AsynDriverInterface(%s) createAsynUser\n", client->name()); debug ("AsynDriverInterface(%s) createAsynUser\n", client->name());
pasynUser = pasynManager->createAsynUser(handleRequest, pasynUser = pasynManager->createAsynUser(handleRequest,
handleTimeout); handleTimeout);
@ -490,6 +493,19 @@ connectToBus(const char* portname, int addr)
return true; return true;
} }
void AsynDriverInterface::
reportAsynStatus(asynStatus status, const char *name)
{
if (previousAsynStatus != status) {
previousAsynStatus = status;
if (status == asynSuccess) {
error("%s %s: status returned to normal\n", clientName(), name);
} else {
error("%s %s: %s\n", clientName(), name, pasynUser->errorMessage);
}
}
}
// interface function: we want exclusive access to the device // interface function: we want exclusive access to the device
// lockTimeout_ms=0 means "block here" (used in @init) // lockTimeout_ms=0 means "block here" (used in @init)
bool AsynDriverInterface:: bool AsynDriverInterface::
@ -503,16 +519,11 @@ lockRequest(unsigned long lockTimeout_ms)
ioAction = Lock; ioAction = Lock;
status = pasynManager->queueRequest(pasynUser, status = pasynManager->queueRequest(pasynUser,
priority(), lockTimeout); priority(), lockTimeout);
if (status != asynSuccess) reportAsynStatus(status, "lockRequest: pasynManager->queueRequest");
{ return (status == asynSuccess);
error("%s lockRequest: pasynManager->queueRequest() failed: %s\n",
clientName(), pasynUser->errorMessage);
return false;
}
// continues with: // continues with:
// handleRequest() -> lockHandler() -> lockCallback() // handleRequest() -> lockHandler() -> lockCallback()
// or handleTimeout() -> lockCallback(StreamIoTimeout) // or handleTimeout() -> lockCallback(StreamIoTimeout)
return true;
} }
bool AsynDriverInterface:: bool AsynDriverInterface::
@ -562,22 +573,12 @@ connectToAsynPort()
clientName(), connected ? "already" : "not yet"); clientName(), connected ? "already" : "not yet");
if (!connected) if (!connected)
{ {
printf ("%s: AsynDriverInterface::connectToAsynPort: "
"pasynCommon->connect(%p, %p)\n",
clientName(), pvtCommon, pasynUser);
status = pasynCommon->connect(pvtCommon, pasynUser); status = pasynCommon->connect(pvtCommon, pasynUser);
printf ("%s: AsynDriverInterface::connectToAsynPort: "
"pasynCommon->connect(%p, %p) = %s\n",
clientName(), pvtCommon, pasynUser, asynStatusStr[status]);
debug("AsynDriverInterface::connectToAsynPort(%s): " debug("AsynDriverInterface::connectToAsynPort(%s): "
"status=%s\n", "status=%s\n",
clientName(), asynStatusStr[status]); clientName(), asynStatusStr[status]);
if (status != asynSuccess) reportAsynStatus(status, "connectToAsynPort: pasynCommon->connect");
{ return (status == asynSuccess);
error("%s connectToAsynPort: pasynCommon->connect() failed: %s\n",
clientName(), pasynUser->errorMessage);
return false;
}
} }
// We probably should set REN=1 prior to sending but this // We probably should set REN=1 prior to sending but this
// seems to hang up the device every other time. // seems to hang up the device every other time.
@ -644,16 +645,11 @@ writeRequest(const void* output, size_t size,
ioAction = Write; ioAction = Write;
status = pasynManager->queueRequest(pasynUser, priority(), status = pasynManager->queueRequest(pasynUser, priority(),
writeTimeout); writeTimeout);
if (status != asynSuccess) reportAsynStatus(status, "writeRequest: pasynManager->queueRequest");
{ return (status == asynSuccess);
error("%s writeRequest: pasynManager->queueRequest() failed: %s\n",
clientName(), pasynUser->errorMessage);
return false;
}
// continues with: // continues with:
// handleRequest() -> writeHandler() -> lockCallback() // handleRequest() -> writeHandler() -> lockCallback()
// or handleTimeout() -> writeCallback(StreamIoTimeout) // or handleTimeout() -> writeCallback(StreamIoTimeout)
return true;
} }
// now, we can write (called by asynManager) // now, we can write (called by asynManager)
@ -757,11 +753,9 @@ writeHandler()
{ {
status = pasynManager->queueRequest(pasynUser, status = pasynManager->queueRequest(pasynUser,
priority(), lockTimeout); priority(), lockTimeout);
reportAsynStatus(status, "writeHandler: pasynManager->queueRequest");
if (status != asynSuccess) if (status != asynSuccess)
{ {
error("%s writeHandler: "
"pasynManager->queueRequest() failed: %s\n",
clientName(), pasynUser->errorMessage);
writeCallback(StreamIoFault); writeCallback(StreamIoFault);
} }
// continues with: // continues with:
@ -841,6 +835,10 @@ readRequest(unsigned long replyTimeout_ms, unsigned long readTimeout_ms,
clientName(), priority(), queueTimeout, clientName(), priority(), queueTimeout,
asynStatusStr[status], async? "true" : "false", asynStatusStr[status], async? "true" : "false",
status!=asynSuccess ? pasynUser->errorMessage : ""); status!=asynSuccess ? pasynUser->errorMessage : "");
if (!async)
{
reportAsynStatus(status, "readRequest: pasynManager->queueRequest");
}
if (status != asynSuccess) if (status != asynSuccess)
{ {
// Not queued for some reason (e.g. disconnected / already queued) // Not queued for some reason (e.g. disconnected / already queued)
@ -850,8 +848,6 @@ readRequest(unsigned long replyTimeout_ms, unsigned long readTimeout_ms,
startTimer(replyTimeout); startTimer(replyTimeout);
return true; return true;
} }
error("%s readRequest: pasynManager->queueRequest() failed: %s\n",
clientName(), pasynUser->errorMessage);
return false; return false;
} }
// continues with: // continues with:
@ -1411,16 +1407,11 @@ connectRequest(unsigned long connecttimeout_ms)
clientName()); clientName());
status = pasynManager->queueRequest(pasynUser, status = pasynManager->queueRequest(pasynUser,
asynQueuePriorityConnect, queueTimeout); asynQueuePriorityConnect, queueTimeout);
if (status != asynSuccess) reportAsynStatus(status, "connectRequest: pasynManager->queueRequest");
{ return (status == asynSuccess);
error("%s connectRequest: pasynManager->queueRequest() failed: %s\n",
clientName(), pasynUser->errorMessage);
return false;
}
// continues with: // continues with:
// handleRequest() -> connectHandler() -> connectCallback() // handleRequest() -> connectHandler() -> connectCallback()
// or handleTimeout() -> connectCallback(StreamIoTimeout) // or handleTimeout() -> connectCallback(StreamIoTimeout)
return true;
} }
void AsynDriverInterface:: void AsynDriverInterface::
@ -1439,15 +1430,10 @@ disconnectRequest()
clientName()); clientName());
status = pasynManager->queueRequest(pasynUser, status = pasynManager->queueRequest(pasynUser,
asynQueuePriorityConnect, 0.0); asynQueuePriorityConnect, 0.0);
if (status != asynSuccess) reportAsynStatus(status, "disconnectRequest: pasynManager->queueRequest");
{ return (status == asynSuccess);
error("%s disconnectRequest: pasynManager->queueRequest() failed: %s\n",
clientName(), pasynUser->errorMessage);
return false;
}
// continues with: // continues with:
// handleRequest() -> disconnectHandler() // handleRequest() -> disconnectHandler()
return true;
} }
void AsynDriverInterface:: void AsynDriverInterface::