Compare commits

...

2 Commits
0.2.0 ... 0.2.1

Author SHA1 Message Date
3b648c4f7b Improved the error message when the MCU response is printed and the IOC
shell constructor documentation.
2024-11-27 15:57:00 +01:00
2dd46cc48d Improved the error message when the error is printed. 2024-11-27 15:36:51 +01:00
3 changed files with 93 additions and 37 deletions

View File

@ -864,12 +864,8 @@ asynStatus pmacv3Axis::readEncoderType() {
int reponse_length = strlen(response); int reponse_length = strlen(response);
if (reponse_length < 3) { if (reponse_length < 3) {
asynPrint( return pC_->errMsgCouldNotParseResponse(command, response, axisNo_,
pC_->pasynUserSelf, ASYN_TRACE_ERROR, __PRETTY_FUNCTION__, __LINE__);
"%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;
} }
// We are only interested in the last two digits and the last value in // We are only interested in the last two digits and the last value in

View File

@ -1,3 +1,5 @@
// Needed to use strcpy_s from string.h
#define __STDC_WANT_LIB_EXT1__ 1
#include "pmacv3Controller.h" #include "pmacv3Controller.h"
#include "asynMotorController.h" #include "asynMotorController.h"
@ -11,6 +13,24 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
/**
* @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) {
// Needed to use strcpy_s from string.h
#ifdef __STDC_LIB_EXT1__
strcpy_s(dst, src);
for (size_t i = 0; i < strlen(dst); i++) {
if (dst[i] == '\r') {
dst[i] = '_';
}
}
#endif
}
/** /**
* @brief Construct a new pmacv3Controller::pmacv3Controller object * @brief Construct a new pmacv3Controller::pmacv3Controller object
* *
@ -192,8 +212,9 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command,
// Definition of local variables. // Definition of local variables.
asynStatus status = asynSuccess; asynStatus status = asynSuccess;
asynStatus pl_status = asynSuccess; asynStatus pl_status = asynSuccess;
char full_command[MAXBUF_] = {0}; char fullCommand[MAXBUF_] = {0};
char user_message[MAXBUF_] = {0}; char drvMessageText[MAXBUF_] = {0};
char modResponse[MAXBUF_] = {0};
int motorStatusProblem = 0; int motorStatusProblem = 0;
int numReceivedResponses = 0; int numReceivedResponses = 0;
@ -232,7 +253,7 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command,
this protocol encodes the message length at the beginning. See Turbo PMAC this protocol encodes the message length at the beginning. See Turbo PMAC
User Manual, page 418 in VR_PMAC_GETRESPONSE 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 contains NULL terminators in its middle, therefore the string manipulation
methods of C don't work. methods of C don't work.
*/ */
@ -242,20 +263,20 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command,
strlen(command) + 1; // +1 because of the appended /r strlen(command) + 1; // +1 because of the appended /r
const int offset = 8; 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. // as an array of zeros, we don't need to set these bits manually.
full_command[0] = '\x40'; fullCommand[0] = '\x40';
full_command[1] = '\xBF'; fullCommand[1] = '\xBF';
full_command[7] = commandLength; 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, asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
"%s => line %d:\nSending command %s", __PRETTY_FUNCTION__, "%s => line %d:\nSending command %s", __PRETTY_FUNCTION__,
__LINE__, full_command); __LINE__, fullCommand);
// Perform the actual writeRead // Perform the actual writeRead
status = pasynOctetSyncIO->writeRead( status = pasynOctetSyncIO->writeRead(
lowLevelPortUser_, full_command, commandLength + offset, response, lowLevelPortUser_, fullCommand, commandLength + offset, response,
MAXBUF_, comTimeout_, &nbytesOut, &nbytesIn, &eomReason); MAXBUF_, comTimeout_, &nbytesOut, &nbytesIn, &eomReason);
/* /*
@ -291,7 +312,7 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command,
if (status == asynSuccess) { if (status == asynSuccess) {
// If flushing the MCU succeded, try to send the command again // If flushing the MCU succeded, try to send the command again
status = pasynOctetSyncIO->writeRead( status = pasynOctetSyncIO->writeRead(
lowLevelPortUser_, full_command, commandLength + offset, lowLevelPortUser_, fullCommand, commandLength + offset,
response, MAXBUF_, comTimeout_, &nbytesOut, &nbytesIn, response, MAXBUF_, comTimeout_, &nbytesOut, &nbytesIn,
&eomReason); &eomReason);
@ -306,15 +327,18 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command,
// Second check: If this fails, give up and propagate the error. // Second check: If this fails, give up and propagate the error.
if (numExpectedResponses != numReceivedResponses) { if (numExpectedResponses != numReceivedResponses) {
asynPrint(
this->pasynUserSelf, ASYN_TRACE_ERROR, adjustResponseForPrint(modResponse, response);
"%s => line %d:\nUnexpected response %s for command %s\n", asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
__PRETTY_FUNCTION__, __LINE__, response, command); "%s => line %d:\nUnexpected response %s (_ are "
snprintf(user_message, sizeof(user_message), "carriage returns) for command %s\n",
"Received unexpected response %s for command %s. " __PRETTY_FUNCTION__, __LINE__, modResponse, command);
snprintf(drvMessageText, sizeof(drvMessageText),
"Received unexpected response %s (_ are "
"carriage returns) for command %s. "
"Please call the support", "Please call the support",
response, command); modResponse, command);
pl_status = setStringParam(motorMessageText_, user_message); pl_status = setStringParam(motorMessageText_, drvMessageText);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return paramLibAccessFailed(pl_status, "motorMessageText_", return paramLibAccessFailed(pl_status, "motorMessageText_",
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
@ -330,23 +354,24 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command,
} }
// Create custom error messages for different failure modes // Create custom error messages for different failure modes
if (strlen(user_message) == 0) { if (strlen(drvMessageText) == 0) {
switch (status) { switch (status) {
case asynSuccess: case asynSuccess:
break; // Communicate nothing break; // Communicate nothing
case asynTimeout: case asynTimeout:
snprintf(user_message, sizeof(user_message), snprintf(drvMessageText, sizeof(drvMessageText),
"connection timeout for axis %d", axisNo); "connection timeout for axis %d", axisNo);
break; break;
case asynDisconnected: case asynDisconnected:
snprintf(user_message, sizeof(user_message), snprintf(drvMessageText, sizeof(drvMessageText),
"axis is not connected"); "axis is not connected");
break; break;
case asynDisabled: case asynDisabled:
snprintf(user_message, sizeof(user_message), "axis is disabled"); snprintf(drvMessageText, sizeof(drvMessageText),
"axis is disabled");
break; break;
default: default:
snprintf(user_message, sizeof(user_message), snprintf(drvMessageText, sizeof(drvMessageText),
"Communication failed (%s)", stringifyAsynStatus(status)); "Communication failed (%s)", stringifyAsynStatus(status));
break; break;
} }
@ -367,7 +392,7 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command,
if (motorStatusProblem == 0) { if (motorStatusProblem == 0) {
pl_status = pl_status =
axis->setStringParam(this->motorMessageText_, user_message); axis->setStringParam(this->motorMessageText_, drvMessageText);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return paramLibAccessFailed(pl_status, "motorMessageText_", return paramLibAccessFailed(pl_status, "motorMessageText_",
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
@ -377,16 +402,18 @@ asynStatus pmacv3Controller::writeRead(int axisNo, const char *command,
// Log the overall status (communication successfull or not) // Log the overall status (communication successfull or not)
if (status == asynSuccess) { if (status == asynSuccess) {
asynPrint(lowLevelPortUser_, ASYN_TRACEIO_DRIVER, asynPrint(lowLevelPortUser_, ASYN_TRACEIO_DRIVER,
"%s => line %d:\nDevice response: %s\n", __PRETTY_FUNCTION__, "%s => line %d:\nDevice response: %s (_ are "
__LINE__, response); "carriage returns)\n",
__PRETTY_FUNCTION__, __LINE__, modResponse);
pl_status = axis->setIntegerParam(this->motorStatusCommsError_, 0); pl_status = axis->setIntegerParam(this->motorStatusCommsError_, 0);
} else { } else {
if (status == asynSuccess) { if (status == asynSuccess) {
asynPrint( asynPrint(
lowLevelPortUser_, ASYN_TRACE_ERROR, lowLevelPortUser_, ASYN_TRACE_ERROR,
"%s => line %d:\nCommunication failed for command %s (%s)\n", "%s => line %d:\nCommunication failed for command %s (%s)\n",
__PRETTY_FUNCTION__, __LINE__, full_command, __PRETTY_FUNCTION__, __LINE__, fullCommand,
stringifyAsynStatus(status)); stringifyAsynStatus(status));
pl_status = axis->setIntegerParam(this->motorStatusCommsError_, 1); pl_status = axis->setIntegerParam(this->motorStatusCommsError_, 1);
} }
@ -420,6 +447,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 /** The following functions are C-wrappers, and can be called directly from
* iocsh */ * iocsh */
@ -533,9 +569,9 @@ types and then providing "factory" functions
(configCreateControllerCallFunc). These factory functions are used to (configCreateControllerCallFunc). These factory functions are used to
register the constructors during compilation. register the constructors during compilation.
*/ */
static const iocshArg CreateControllerArg0 = {"Controller port name", static const iocshArg CreateControllerArg0 = {"Controller name (e.g. mcu1)",
iocshArgString}; iocshArgString};
static const iocshArg CreateControllerArg1 = {"Low level port name", static const iocshArg CreateControllerArg1 = {"Asyn IP port name (e.g. pmcu1)",
iocshArgString}; iocshArgString};
static const iocshArg CreateControllerArg2 = {"Number of axes", iocshArgInt}; static const iocshArg CreateControllerArg2 = {"Number of axes", iocshArgInt};
static const iocshArg CreateControllerArg3 = {"Moving poll rate (s)", static const iocshArg CreateControllerArg3 = {"Moving poll rate (s)",
@ -558,7 +594,8 @@ static void configPmacV3CreateControllerCallFunc(const iocshArgBuf *args) {
Same procedure as for the CreateController function, but for the axis Same procedure as for the CreateController function, but for the axis
itself. itself.
*/ */
static const iocshArg CreateAxisArg0 = {"Controller port name", iocshArgString}; static const iocshArg CreateAxisArg0 = {"Controller name (e.g. mcu1)",
iocshArgString};
static const iocshArg CreateAxisArg1 = {"Axis number", iocshArgInt}; static const iocshArg CreateAxisArg1 = {"Axis number", iocshArgInt};
static const iocshArg *const CreateAxisArgs[] = {&CreateAxisArg0, static const iocshArg *const CreateAxisArgs[] = {&CreateAxisArg0,
&CreateAxisArg1}; &CreateAxisArg1};

View File

@ -93,6 +93,29 @@ class pmacv3Controller : public sinqController {
*/ */
pmacv3Axis *castToAxis(asynMotorAxis *asynAxis); 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: private:
// Set the maximum buffer size. This is an empirical value which must be // Set the maximum buffer size. This is an empirical value which must be
// large enough to avoid overflows for all commands to the device / // large enough to avoid overflows for all commands to the device /