diff --git a/src/masterMacsController.cpp b/src/masterMacsController.cpp index b0af070..02b3fd1 100644 --- a/src/masterMacsController.cpp +++ b/src/masterMacsController.cpp @@ -12,6 +12,18 @@ #include #include +/* +These two constants store the major and the minor firmware version this driver +needs. The following constraints need to be fulfilled: +Actual major version == FIRMWARE_MAJOR_VERSION +Actual minor version >= FIRMWARE_MINOR_VERSION +If one of these constraints is not fulfilled, the driver will shut down the IOC. +If the firmware version cannot be read (e.g. because the variable used to do so +does not exist yet), the conditions outlined above are seen as fulfilled. + */ +const int FIRMWARE_MAJOR_VERSION = 2; +const int FIRMWARE_MINOR_VERSION = 2; + struct masterMacsControllerImpl { double comTimeout; @@ -65,6 +77,7 @@ masterMacsController::masterMacsController(const char *portName, // Initialization of local variables asynStatus status = asynSuccess; + char response[MAXBUF_] = {0}; pMasterMacsC_ = std::make_unique((masterMacsControllerImpl){ @@ -116,6 +129,55 @@ masterMacsController::masterMacsController(const char *portName, pasynOctetSyncIO->disconnect(pasynOctetSyncIOipPort()); exit(-1); } + + // ========================================================================= + + // Check the firmware version according to the conditions outlined in the + // comment for FIRMWARE_MAJOR_VERSION and FIRMWARE_MINOR_VERSION + status = read(0, 99, response); + + if (status == asynSuccess) { + + // Just interpret the version if the variable already exists + double versionRaw = 0.0; + int nvals = sscanf(response, "%lf", &versionRaw); + if (nvals == 1 && versionRaw != 0.0) { + // Discard decimal part + long long versionInt = (long long)versionRaw; + + // Extract bugfix (last 3 digits) + // Currently not used, just here for completions sake + // int bugfix = versionInt % 1000; + versionInt /= 1000; + + // Extract minor (next 3 digits) + int minor = versionInt % 1000; + versionInt /= 1000; + + // Remaining is major + int major = (int)versionInt; + + // Compare to target values + if (FIRMWARE_MAJOR_VERSION != major || + FIRMWARE_MINOR_VERSION > minor) { + asynPrint( + this->pasynUser(), ASYN_TRACE_ERROR, + "Controller \"%s\" => %s, line %d\nFATAL ERROR (Incorrect " + "version number of firmware: Expected major version equal " + "to %d, got %d. Expected minor version equal to or larger " + "than %d, got %d).\nTerminating IOC", + portName, __PRETTY_FUNCTION__, __LINE__, + FIRMWARE_MAJOR_VERSION, major, FIRMWARE_MINOR_VERSION, + minor); + exit(-1); + } + } + } else { + asynPrint(this->pasynUser(), ASYN_TRACE_ERROR, + "Controller \"%s\" => %s, line %d\nCould not read firmware " + "version\n", + portName, __PRETTY_FUNCTION__, __LINE__); + } } /* @@ -199,12 +261,6 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd, comTimeout = pMasterMacsC_->comTimeout; } - masterMacsAxis *axis = getMasterMacsAxis(axisNo); - if (axis == nullptr) { - // We already did the error logging directly in getAxis - return asynError; - } - // Build the full command depending on the inputs to this function if (isRead) { snprintf(fullCommand, MAXBUF_ - 1, "%dR%02d\x0D", axisNo, tcpCmd); @@ -286,32 +342,39 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd, } // Log the overall status (communication successfull or not) - if (status == asynSuccess) { - setAxisParamChecked(axis, motorStatusCommsError, false); - } else { + if (axisNo != 0) { + masterMacsAxis *axis = getMasterMacsAxis(axisNo); + if (axis == nullptr) { + // We already did the error logging directly in getAxis + return asynError; + } - /* - Since the communication failed, there is the possibility that the - controller is not connected at all to the network. In that case, we - cannot be sure that the information read out in the init method of the - axis is still up-to-date the next time we get a connection. Therefore, - an info flag is set which the axis object can use at the start of its - poll method to try to initialize itself. - */ - axis->setNeedInit(true); - - /* - Check if the axis already is in an error communication mode. If - it is not, upstream the error. This is done to avoid "flooding" - the user with different error messages if more than one error - ocurred before an error-free communication - */ - getAxisParamChecked(axis, motorStatusProblem, &motorStatusProblem); - - if (motorStatusProblem == 0) { - setAxisParamChecked(axis, motorMessageText, drvMessageText); - setAxisParamChecked(axis, motorStatusProblem, true); + if (status == asynSuccess) { setAxisParamChecked(axis, motorStatusCommsError, false); + } else { + /* + Since the communication failed, there is the possibility that the + controller is not connected at all to the network. In that case, we + cannot be sure that the information read out in the init method of + the axis is still up-to-date the next time we get a connection. + Therefore, an info flag is set which the axis object can use at the + start of its poll method to try to initialize itself. + */ + axis->setNeedInit(true); + + /* + Check if the axis already is in an error communication mode. If + it is not, upstream the error. This is done to avoid "flooding" + the user with different error messages if more than one error + ocurred before an error-free communication + */ + getAxisParamChecked(axis, motorStatusProblem, &motorStatusProblem); + + if (motorStatusProblem == 0) { + setAxisParamChecked(axis, motorMessageText, drvMessageText); + setAxisParamChecked(axis, motorStatusProblem, true); + setAxisParamChecked(axis, motorStatusCommsError, false); + } } } @@ -334,7 +397,7 @@ asynStatus masterMacsController::parseResponse( bool responseValid = false; int responseStart = 0; asynStatus status = asynSuccess; - int prevConnected = 0; + int prevConnected = 1; char printableCommand[MAXBUF_] = {0}; char printableResponse[MAXBUF_] = {0}; @@ -342,12 +405,14 @@ asynStatus masterMacsController::parseResponse( msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__); masterMacsAxis *axis = getMasterMacsAxis(axisNo); - if (axis == nullptr) { + if (axisNo != 0 && axis == nullptr) { return asynError; } // Was the motor previously connected? - getAxisParamChecked(axis, motorConnected, &prevConnected); + if (axis != nullptr) { + getAxisParamChecked(axis, motorConnected, &prevConnected); + } // We don't use strlen here since the C string terminator 0x00 // occurs in the middle of the char array. @@ -371,14 +436,17 @@ asynStatus masterMacsController::parseResponse( "connected.\n", portName, axisNo, __PRETTY_FUNCTION__, __LINE__); - setAxisParamChecked(axis, motorConnected, true); - status = callParamCallbacks(); - if (status != asynSuccess) { - asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, - "Controller \"%s\", axis %d => %s, line " - "%d:\nCould not update parameter library\n", - portName, axisNo, __PRETTY_FUNCTION__, __LINE__); - return status; + if (axis != nullptr) { + setAxisParamChecked(axis, motorConnected, true); + status = callParamCallbacks(); + if (status != asynSuccess) { + asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, + "Controller \"%s\", axis %d => %s, line " + "%d:\nCould not update parameter library\n", + portName, axisNo, __PRETTY_FUNCTION__, + __LINE__); + return status; + } } } @@ -399,14 +467,17 @@ asynStatus masterMacsController::parseResponse( "disconnected.\n", portName, axisNo, __PRETTY_FUNCTION__, __LINE__); - setAxisParamChecked(axis, motorConnected, false); - status = callParamCallbacks(); - if (status != asynSuccess) { - asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, - "Controller \"%s\", axis %d => %s, line " - "%d:\nCould not update parameter library\n", - portName, axisNo, __PRETTY_FUNCTION__, __LINE__); - return status; + if (axis != nullptr) { + setAxisParamChecked(axis, motorConnected, false); + status = callParamCallbacks(); + if (status != asynSuccess) { + asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, + "Controller \"%s\", axis %d => %s, line " + "%d:\nCould not update parameter library\n", + portName, axisNo, __PRETTY_FUNCTION__, + __LINE__); + return status; + } } } break;