From 2dd46cc48d5068f06fd4021f8471712ec1627313 Mon Sep 17 00:00:00 2001 From: smathis Date: Wed, 27 Nov 2024 15:36:51 +0100 Subject: [PATCH] Improved the error message when the error is printed. --- src/pmacv3Axis.cpp | 8 +--- src/pmacv3Controller.cpp | 89 +++++++++++++++++++++++++++------------- src/pmacv3Controller.h | 23 +++++++++++ 3 files changed, 86 insertions(+), 34 deletions(-) diff --git a/src/pmacv3Axis.cpp b/src/pmacv3Axis.cpp index 5f7fbd2..06aa0af 100644 --- a/src/pmacv3Axis.cpp +++ b/src/pmacv3Axis.cpp @@ -864,12 +864,8 @@ asynStatus pmacv3Axis::readEncoderType() { int reponse_length = strlen(response); if (reponse_length < 3) { - asynPrint( - pC_->pasynUserSelf, ASYN_TRACE_ERROR, - "%s => line %d:\nUnexpected reponse '%s' from axis %d on " - "controller %s while reading the encoder type. Aborting....\n", - __PRETTY_FUNCTION__, __LINE__, response, axisNo_, pC_->portName); - return asynError; + return pC_->errMsgCouldNotParseResponse(command, response, axisNo_, + __PRETTY_FUNCTION__, __LINE__); } // We are only interested in the last two digits and the last value in diff --git a/src/pmacv3Controller.cpp b/src/pmacv3Controller.cpp index 98c590e..d9c2e88 100644 --- a/src/pmacv3Controller.cpp +++ b/src/pmacv3Controller.cpp @@ -3,6 +3,7 @@ #include "asynMotorController.h" #include "asynOctetSyncIO.h" #include "pmacv3Axis.h" +#include #include #include #include @@ -11,6 +12,21 @@ #include #include +/** + * @brief Copy src into dst and replace all carriage returns with spaces + * + * @param dst Buffer for the modified string + * @param src Original string + */ +void adjustResponseForPrint(char *dst, const char *src) { + strcpy(dst, src); + for (size_t i = 0; i < strlen(dst); i++) { + if (dst[i] == '\r') { + dst[i] = '_'; + } + } +} + /** * @brief Construct a new pmacv3Controller::pmacv3Controller object * @@ -192,8 +208,9 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command, // Definition of local variables. asynStatus status = asynSuccess; asynStatus pl_status = asynSuccess; - char full_command[MAXBUF_] = {0}; - char user_message[MAXBUF_] = {0}; + char fullCommand[MAXBUF_] = {0}; + char drvMessageText[MAXBUF_] = {0}; + char modResponse[MAXBUF_] = {0}; int motorStatusProblem = 0; int numReceivedResponses = 0; @@ -232,7 +249,7 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command, this protocol encodes the message length at the beginning. See Turbo PMAC User Manual, page 418 in VR_PMAC_GETRESPONSE - The message has to be build manually into the buffer full_command, since it + The message has to be build manually into the buffer fullCommand, since it contains NULL terminators in its middle, therefore the string manipulation methods of C don't work. */ @@ -242,20 +259,20 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command, strlen(command) + 1; // +1 because of the appended /r const int offset = 8; - // Positions 2 to 6 must have the value 0. Since full_command is initialized + // Positions 2 to 6 must have the value 0. Since fullCommand is initialized // as an array of zeros, we don't need to set these bits manually. - full_command[0] = '\x40'; - full_command[1] = '\xBF'; - full_command[7] = commandLength; + fullCommand[0] = '\x40'; + fullCommand[1] = '\xBF'; + fullCommand[7] = commandLength; - snprintf((char *)full_command + offset, MAXBUF_ - offset, "%s\r", command); + snprintf((char *)fullCommand + offset, MAXBUF_ - offset, "%s\r", command); asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s => line %d:\nSending command %s", __PRETTY_FUNCTION__, - __LINE__, full_command); + __LINE__, fullCommand); // Perform the actual writeRead status = pasynOctetSyncIO->writeRead( - lowLevelPortUser_, full_command, commandLength + offset, response, + lowLevelPortUser_, fullCommand, commandLength + offset, response, MAXBUF_, comTimeout_, &nbytesOut, &nbytesIn, &eomReason); /* @@ -291,7 +308,7 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command, if (status == asynSuccess) { // If flushing the MCU succeded, try to send the command again status = pasynOctetSyncIO->writeRead( - lowLevelPortUser_, full_command, commandLength + offset, + lowLevelPortUser_, fullCommand, commandLength + offset, response, MAXBUF_, comTimeout_, &nbytesOut, &nbytesIn, &eomReason); @@ -306,15 +323,19 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command, // Second check: If this fails, give up and propagate the error. if (numExpectedResponses != numReceivedResponses) { - asynPrint( - this->pasynUserSelf, ASYN_TRACE_ERROR, - "%s => line %d:\nUnexpected response %s for command %s\n", - __PRETTY_FUNCTION__, __LINE__, response, command); - snprintf(user_message, sizeof(user_message), - "Received unexpected response %s for command %s. " + + adjustResponseForPrint(modResponse, response); + + asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, + "%s => line %d:\nUnexpected response %s (_ are " + "carriage returns) for command %s\n", + __PRETTY_FUNCTION__, __LINE__, modResponse, command); + snprintf(drvMessageText, sizeof(drvMessageText), + "Received unexpected response %s (_ are " + "carriage returns) for command %s. " "Please call the support", - response, command); - pl_status = setStringParam(motorMessageText_, user_message); + modResponse, command); + pl_status = setStringParam(motorMessageText_, drvMessageText); if (pl_status != asynSuccess) { return paramLibAccessFailed(pl_status, "motorMessageText_", __PRETTY_FUNCTION__, __LINE__); @@ -330,23 +351,24 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command, } // Create custom error messages for different failure modes - if (strlen(user_message) == 0) { + if (strlen(drvMessageText) == 0) { switch (status) { case asynSuccess: break; // Communicate nothing case asynTimeout: - snprintf(user_message, sizeof(user_message), + snprintf(drvMessageText, sizeof(drvMessageText), "connection timeout for axis %d", axisNo); break; case asynDisconnected: - snprintf(user_message, sizeof(user_message), + snprintf(drvMessageText, sizeof(drvMessageText), "axis is not connected"); break; case asynDisabled: - snprintf(user_message, sizeof(user_message), "axis is disabled"); + snprintf(drvMessageText, sizeof(drvMessageText), + "axis is disabled"); break; default: - snprintf(user_message, sizeof(user_message), + snprintf(drvMessageText, sizeof(drvMessageText), "Communication failed (%s)", stringifyAsynStatus(status)); break; } @@ -367,7 +389,7 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command, if (motorStatusProblem == 0) { pl_status = - axis->setStringParam(this->motorMessageText_, user_message); + axis->setStringParam(this->motorMessageText_, drvMessageText); if (pl_status != asynSuccess) { return paramLibAccessFailed(pl_status, "motorMessageText_", __PRETTY_FUNCTION__, __LINE__); @@ -377,16 +399,18 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command, // Log the overall status (communication successfull or not) if (status == asynSuccess) { + asynPrint(lowLevelPortUser_, ASYN_TRACEIO_DRIVER, - "%s => line %d:\nDevice response: %s\n", __PRETTY_FUNCTION__, - __LINE__, response); + "%s => line %d:\nDevice response: %s (_ are " + "carriage returns)\n", + __PRETTY_FUNCTION__, __LINE__, modResponse); pl_status = axis->setIntegerParam(this->motorStatusCommsError_, 0); } else { if (status == asynSuccess) { asynPrint( lowLevelPortUser_, ASYN_TRACE_ERROR, "%s => line %d:\nCommunication failed for command %s (%s)\n", - __PRETTY_FUNCTION__, __LINE__, full_command, + __PRETTY_FUNCTION__, __LINE__, fullCommand, stringifyAsynStatus(status)); pl_status = axis->setIntegerParam(this->motorStatusCommsError_, 1); } @@ -420,6 +444,15 @@ asynStatus pmacv3Controller::writeInt32(asynUser *pasynUser, epicsInt32 value) { } } +asynStatus pmacv3Controller::errMsgCouldNotParseResponse( + const char *command, const char *response, int axisNo, + const char *functionName, int lineNumber) { + char modifiedResponse[MAXBUF_] = {0}; + adjustResponseForPrint(modifiedResponse, response); + return sinqController::errMsgCouldNotParseResponse( + command, modifiedResponse, axisNo, functionName, lineNumber); +} + /*************************************************************************************/ /** The following functions are C-wrappers, and can be called directly from * iocsh */ diff --git a/src/pmacv3Controller.h b/src/pmacv3Controller.h index 08aa8ce..4c769c7 100644 --- a/src/pmacv3Controller.h +++ b/src/pmacv3Controller.h @@ -93,6 +93,29 @@ class pmacv3Controller : public sinqController { */ pmacv3Axis *castToAxis(asynMotorAxis *asynAxis); + /** + * @brief Specialized version of sinqController::errMsgCouldNotParseResponse + * for pmacv3 + * + * This is an overloaded version of + * sinqController::errMsgCouldNotParseResponse which calls + * adjustResponseForLogging on response before handing it over to + * sinqController::errMsgCouldNotParseResponse. + * + * @param command Command which led to the unparseable message + * @param response Response which wasn't parseable + * @param axisNo_ Axis where the problem occurred + * @param functionName Name of the caller function. It is recommended + to use a macro, e.g. __func__ or __PRETTY_FUNCTION__. + * @param lineNumber Source code line where this function is + called. It is recommended to use a macro, e.g. __LINE__. + * @return asynStatus Returns asynError. + */ + asynStatus errMsgCouldNotParseResponse(const char *command, + const char *response, int axisNo_, + const char *functionName, + int lineNumber); + private: // Set the maximum buffer size. This is an empirical value which must be // large enough to avoid overflows for all commands to the device /