/* * GluexXPSGroup.cpp * * Created on: Jun 13, 2016 * Author: Hovanes Egiyan */ #include "GluexXPSGroup.hh" static const char *driverName = "GluexXPSGroup"; #define MAX_MESSAGE_LEN 1024 #define MAX_GROUPNAME_LEN 128 #define MAX_GROUP_AXIS 8 using namespace std; std::string GluexXPSGroup::gxgInitializeString = "GROUP_INITIALIZE"; std::string GluexXPSGroup::gxgInitializeStatusString = "GROUP_INITIALIZE_STATUS"; std::string GluexXPSGroup::gxgKillString = "GROUP_KILL"; std::string GluexXPSGroup::gxgKillStatusString = "GROUP_KILL_STATUS"; std::string GluexXPSGroup::gxgHomeSearchString = "GROUP_HOME_SEARCH"; std::string GluexXPSGroup::gxgHomeSearchStatusString = "GROUP_HOME_SEARCH_STATUS"; std::string GluexXPSGroup::gxgMotionEnableString = "GROUP_MOTION_ENABLE"; std::string GluexXPSGroup::gxgMotionEnableStatusString = "GROUP_MOTION_ENABLE_STATUS"; std::string GluexXPSGroup::gxgMotionDisableString = "GROUP_MOTION_DISABLE"; std::string GluexXPSGroup::gxgMotionDisableStatusString = "GROUP_MOTION_DISABLE_STATUS"; std::string GluexXPSGroup::gxgReferencingStartString = "GROUP_REFERENCING_START"; std::string GluexXPSGroup::gxgReferencingStartStatusString = "GROUP_REFERENCING_START_STATUS"; std::string GluexXPSGroup::gxgReferencingStopString = "GROUP_REFERENCING_STOP"; std::string GluexXPSGroup::gxgReferencingStopStatusString = "GROUP_REFERENCING_STOP_STATUS"; std::string GluexXPSGroup::gxgStatusStringString = "GROUP_STATUS_STRING"; std::string GluexXPSGroup::gxgStatusString = "GROUP_STATUS"; std::string GluexXPSGroup::gxgMessageString = "GROUP_MESSAGE"; std::string GluexXPSGroup::gxgReferencingMessageString = "GROUP_REFERENCING_MESSAGE"; // Main constructor of this asynPortDriver GluexXPSGroup::GluexXPSGroup( const string pName, const std::string groupName, GluexXPSController* pC ) : asynPortDriver( pName.c_str(), MAX_GROUP_AXIS, // NUM_GLUEX_XPS_GROUP_PARAMS, asynOctetMask | asynInt32Mask | asynFloat64Mask | asynFloat64ArrayMask | asynGenericPointerMask | asynDrvUserMask, asynOctetMask | asynInt32Mask | asynFloat64Mask | asynFloat64ArrayMask | asynGenericPointerMask, ASYN_CANBLOCK | ASYN_MULTIDEVICE, 1, 0, 0 ), gxgController( pC ), gxgName( groupName ) { static const char *functionName = "GluexXPSGroup"; this->gxgEventID = epicsEventCreate(epicsEventEmpty); // Open communication socket for moving this group char* ipAddress = const_cast( gxgController->getIPAddress().c_str() ); gxgMoveSocket = TCP_ConnectToServer( ipAddress, gxgController->getIPPort(), XPS_POLL_TIMEOUT ); if ( gxgMoveSocket < 0 ) { printf( "%s:%s: error calling TCP_ConnectToServer for move socket\n", driverName, functionName ); } /* Set the poll rate on the moveSocket to a negative number, which means that SendAndReceive should do only a write, no read */ TCP_SetTimeout( gxgMoveSocket, -0.1 ); // Use the controllers poll socket as its own polling socket gxgPollSocket = gxgController->getPollSocket(); /* Set an EPICS exit handler that will shut down polling before asyn kills the IP sockets */ epicsAtExit( GluexXPSGroup::shutdownCallback, gxgController ); this->createParameters(); this->assignAxes(); cout << "Launching thread" << endl; int status = 0; /* Create the thread that reads the group parameters from the controller in the background */ status = (asynStatus)( epicsThreadCreate(portName, epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), (EPICSTHREADFUNC) GluexXPSGroup::pollingThreadFunction, this) == NULL); if ( status ) { printf( "%s: epicsThreadCreate failure\n", functionName ); stringstream ssMessage; ssMessage << "Could not start thread from " << driverName << " for asyn port " << portName ; throw ssMessage.str(); } /* Wake up the poller task which will make it do a poll, * updating values for this axis to use the new resolution (stepSize_) */ gxgController->wakeupPoller(); return; } GluexXPSGroup::~GluexXPSGroup() { // TODO Auto-generated destructor stub } void GluexXPSGroup::createParameters() { createParam( gxgInitializeString.c_str(), asynParamInt32, &gxgInitialize_); createParam( gxgInitializeStatusString.c_str(), asynParamInt32, &gxgInitializeStatus_); createParam( gxgKillString.c_str(), asynParamInt32, &gxgKill_); createParam( gxgKillStatusString.c_str(), asynParamInt32, &gxgKillStatus_); createParam( gxgHomeSearchString.c_str(), asynParamInt32, &gxgHomeSearch_); createParam( gxgHomeSearchStatusString.c_str(), asynParamInt32, &gxgHomeSearchStatus_); createParam( gxgMotionEnableString.c_str(), asynParamInt32, &gxgMotionEnable_); createParam( gxgMotionEnableStatusString.c_str(), asynParamInt32, &gxgMotionEnableStatus_); createParam( gxgMotionDisableString.c_str(), asynParamInt32, &gxgMotionDisable_); createParam( gxgMotionDisableStatusString.c_str(), asynParamInt32, &gxgMotionDisableStatus_); createParam( gxgReferencingStartString.c_str(), asynParamInt32, &gxgReferencingStart_); createParam( gxgReferencingStartStatusString.c_str(), asynParamInt32, &gxgReferencingStartStatus_); createParam( gxgReferencingStopString.c_str(), asynParamInt32, &gxgReferencingStop_); createParam( gxgReferencingStopStatusString.c_str(), asynParamInt32, &gxgReferencingStopStatus_); createParam( gxgStatusStringString.c_str(), asynParamOctet, &gxgStatusString_); createParam( gxgStatusString.c_str(), asynParamInt32, &gxgStatus_); createParam( gxgMessageString.c_str(), asynParamOctet, &gxgMessage_); createParam( gxgReferencingMessageString.c_str(), asynParamOctet, &gxgReferencingMessage_); return; } // Check if the group should contain an axis with given positionerName if it was declared. bool GluexXPSGroup::shouldContain( const std::string positionerName ) { string groupName = GluexXPSAxis::getGroupName( positionerName ); if( groupName == gxgName ) { return true; } else { return false; } } // Check if this group contains positioner named positionerName inline bool GluexXPSGroup::contains( const std::string positionerName ) { if( gxgAxisMap.count( positionerName ) > 0 ) { return true ; } return false; } // Add axis to the map of axis inline void GluexXPSGroup::addAxis( const std::string positionerName, GluexXPSAxis* axisPtr ) { gxgAxisMap[positionerName] = axisPtr; return; } // Loop over all axes in the controller and check if they should belong to // this group and add them to the map of axes. inline void GluexXPSGroup::assignAxes() { GluexXPSAxis** axisArray = reinterpret_cast( this->getController()->getAxisPointers() ); int numberOfAxes = getController()->getNumberOfAxes(); // Loop over all axis in the controller and check if they are in the map of axis // for this group. for ( int iAxis=1; iAxis < numberOfAxes; iAxis++ ) { GluexXPSAxis* axisPtr = axisArray[iAxis]; // Check if it was actually declared and built if( axisPtr != 0 && this->shouldContain( axisPtr->getPositionerName() ) ) { string positionerName = axisPtr->getPositionerName(); // If the axis is not in the map and the positioner name of the axis // matches put the axis into the map if( gxgAxisMap.count(positionerName) == 0 ) { gxgAxisMap[positionerName] = axisPtr; } } } } // Find the axes that belong to this group in the controller, and also remove // the "wrong" axes from this grou (that for some reason ended in this group). void GluexXPSGroup::refreshAxisMap() { // Assign the arrays that need to belong to this group based on their positioner name // to this group. this->assignAxes(); // Now do the opposite, loop over all axis in the map of the group and // check if they are all initialized. If they are not initialized or they // do not belong to this group beased on their name or their controller name is // not the same as the controller name for this group or the slot number in // the axis does not match the slot number in the controller, remove the axis // from the map of axes of this group. for( map::iterator itAxis = gxgAxisMap.begin(); itAxis != gxgAxisMap.end(); itAxis++ ) { string positionerName = itAxis->first; GluexXPSAxis* axisPtr = itAxis->second; if( axisPtr == 0 || ! this->shouldContain( axisPtr->getPositionerName() ) || axisPtr->getController() != this->getController() || this->getController()->getAxisPointers()[axisPtr->getAxisNumber()] != axisPtr ) { gxgAxisMap.erase( positionerName ); } } return; } void GluexXPSGroup::pollingLoop() { this->poll(); // Set updating time to value in seconds double updateTime = 1.0; while( 1 ) { epicsEventId& eventID = this->gxgEventID; epicsEventWaitWithTimeout( eventID, updateTime ); getController()->lock(); this->poll(); getController()->unlock(); } } // This function simply calls the member function of the driver whose pointer // is passed as the argument. This function is to be called from a separate // thread and is specified in the argument when launching that thread. void GluexXPSGroup::pollingThreadFunction( void *drvPvt ) { GluexXPSGroup* pPvt = static_cast( drvPvt ); pPvt->pollingLoop(); return; } void GluexXPSGroup::shutdownCallback( void *pPvt ) { GluexXPSController *pC = static_cast( pPvt ); pC->lock(); pC->shuttingDown_ = 1; pC->unlock(); return; } // Method that polls the controller to find the status of this group asynStatus GluexXPSGroup::poll() { int groupStatus; int status = GroupStatusGet( gxgPollSocket, const_cast( gxgName.c_str() ), &groupStatus ); if ( status != 0 ) { asynPrint( this->pasynUserSelf, ASYN_TRACE_ERROR, " Error performing GroupStatusGet, status=%d\n", status ); return asynError; } // cout << "In GluexXPSGroup::poll" << endl; status = setIntegerParam( gxgStatus_, groupStatus ); char groupStatusString[MAX_MESSAGE_LEN]; status = GroupStatusStringGet( gxgPollSocket, groupStatus, groupStatusString ); if ( status != 0 ) { asynPrint( this->pasynUserSelf, ASYN_TRACE_ERROR, " Error performing GroupStatusGet, status=%d\n", status ); return asynError; } // printf("*********GluexXPSGroup::poll groupName= %s groupStatus= %i groupStatusString= %s\n", const_cast( gxgName.c_str()),groupStatus,groupStatusString); status = setStringParam( gxgStatusString_, groupStatusString ); callParamCallbacks(); return asynSuccess; } void GluexXPSGroup::report( FILE *fp, int details ) { fprintf( fp, " name = %s\n poll socket = %d, moveSocket = %d\n", gxgName.c_str(), gxgPollSocket, gxgMoveSocket ); for( map::iterator itAxis = gxgAxisMap.begin(); itAxis != gxgAxisMap.end(); itAxis++ ) { GluexXPSAxis* axisPtr = itAxis->second; axisPtr->report( fp, details ); } return; } // Overwrite writeInt32 for the asynPortDriver asynStatus GluexXPSGroup::writeInt32( asynUser *pasynUser, epicsInt32 value ) { int function = pasynUser->reason; int status = asynSuccess; /* Set the parameter and readback in the parameter library. This may be overwritten when we read back the * status at the end, but that's OK */ status = this->setIntegerParam( function, value ); // printf( "********* Referencing groupName= %s \n", gxgName.c_str() ); if ( function == gxgInitialize_ ) { status = initialize(); } else if ( function == gxgKill_ ) { status = kill(); } else if (function == gxgHomeSearch_) { status = homeSearch(); } else if (function == gxgMotionEnable_) { status = motionEnable(); } else if (function == gxgMotionDisable_) { status = motionDisable(); } else if (function == gxgReferencingStart_) { status = referencingStart(); } else if (function == gxgReferencingStop_) { status = referencingStop(); } else { /* Call base class method */ status = asynPortDriver::writeInt32( pasynUser, value ); } return (asynStatus) status; } // Initialize this group asynStatus GluexXPSGroup::initialize() { bool initializeOK = true; static const char *functionName = "initialize"; int status = 0; char message[MAX_MESSAGE_LEN]; int initStatus; asynPrint( this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: entry\n", driverName, functionName ); status = GroupInitialize( gxgPollSocket, const_cast( gxgName.c_str() ) ); if ( status ) initializeOK = false; switch ( -status ) { case 0: strcpy( message, " " ); break; case 7: strcpy( message, "GroupInitialize: Valid command format: ERR_WRONG_FORMAT(-7)" ); break; case 8: strcpy( message, "GroupInitialize: Actor must be a group: ERR_WRONG_OBJECT_TYPE(-8)" ); break; case 19: strcpy( message, "GroupInitialize: Valid Group name: ERR_GROUP_NAME(-19)" ); break; case 20: strcpy( message, "GroupInitialize: Configuration files reading: ERR_FATAL_INIT(-20)" ); break; case 21: strcpy( message, "GroupInitialize: XPS initialization in progress: ERR_IN_INITIALIZATION(-21)" ); break; case 22: strcpy( message, "GroupInitialize: Group state must be 'Not Initialized': ERR_NOT_ALLOWED_ACTION(-22)" ); break; case 50: strcpy( message, "GroupInitialize: ERR_MOTOR_INITIALIZATION_ERROR(-50)" ); break; default: sprintf( message, "GroupInitialize: Unknown error=%d", status ); break; } setStringParam( gxgReferencingMessage_, message ); setStringParam( gxgMessage_, message ); initStatus = (initializeOK) ? GROUP_REFERENCING_STATUS_SUCCESS : GROUP_REFERENCING_STATUS_FAILURE; setIntegerParam( gxgInitializeStatus_, initStatus ); setIntegerParam( gxgInitialize_, 0 ); callParamCallbacks(); return status ? asynError : asynSuccess; } // Kill this group asynStatus GluexXPSGroup::kill() { bool groupKillOK = true; static const char *functionName = "kill"; int status = 0; char message[MAX_MESSAGE_LEN]; int killStatus; asynPrint( this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: entry\n", driverName, functionName ); // printf( " %s groupName= %s \n", functionName, gxgName.c_str() ); status = GroupKill( gxgPollSocket, const_cast( gxgName.c_str() ) ); if ( status ) groupKillOK = false; switch ( -status ) { case 0: strcpy( message, " " ); break; case 7: strcpy( message, "GroupKill: Valid command format: ERR_WRONG_FORMAT(-7)" ); break; case 8: strcpy( message, "GroupKill: ERR_WRONG_OBJECT_TYPE(-8)" ); break; case 19: strcpy( message, "GroupKill: Valid Group name: ERR_GROUP_NAME(-19)" ); break; case 20: strcpy( message, "GroupKill: Configuration files reading: ERR_FATAL_INIT(-20)" ); break; case 21: strcpy( message, "GroupKill: XPS initialization in progress: ERR_IN_INITIALIZATION(-21)" ); break; default: sprintf( message, "GroupKill: Unknown error=%d", status ); break; } setStringParam( gxgReferencingMessage_, message ); setStringParam( gxgMessage_, message ); killStatus = (groupKillOK) ? GROUP_REFERENCING_STATUS_SUCCESS : GROUP_REFERENCING_STATUS_FAILURE; setIntegerParam( gxgKillStatus_, killStatus ); setIntegerParam( gxgKill_, 0 ); callParamCallbacks(); return status ? asynError : asynSuccess; } asynStatus GluexXPSGroup::referencingStart() { bool groupReferencingStartOK = true; static const char *functionName = "referencingStart"; int status = 0; int startStatus; char message[MAX_MESSAGE_LEN]; asynPrint( this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: entry\n", driverName, functionName ); status = GroupReferencingStart( gxgPollSocket, const_cast(gxgName.c_str()) ); if ( status ) groupReferencingStartOK = false; // printf("---groupReferencingStart status %s \n",groupReferencingStartOK); switch ( -status ) { case 0: strcpy( message, " " ); break; case 7: strcpy( message, "GroupReferencingStart: Valid command format: ERR_WRONG_FORMAT(-7)" ); break; case 19: strcpy( message, "GroupReferencingStart: Valid Group name: ERR_GROUP_NAME(-19)" ); break; case 20: strcpy( message, "GroupReferencingStart: Configuration files reading: ERR_FATAL_INIT(-20)" ); break; case 21: strcpy( message, "GroupReferencingStart: XPS initialization in progress: ERR_IN_INITIALIZATION(-21)" ); break; case 22: strcpy( message, "GroupReferencingStart: Group state must be 'NOT REFERENCED': ERR_NOT_ALLOWED_ACTION(-22)" ); break; default: sprintf( message, "GroupReferencingStart: Unknown error=%d", status ); break; } setStringParam( gxgReferencingMessage_, message ); setStringParam( gxgMessage_, message ); startStatus = (groupReferencingStartOK) ? GROUP_REFERENCING_STATUS_SUCCESS : GROUP_REFERENCING_STATUS_FAILURE; setIntegerParam( gxgReferencingStartStatus_, startStatus ); setIntegerParam( gxgReferencingStart_, 0 ); callParamCallbacks(); return status ? asynError : asynSuccess; } asynStatus GluexXPSGroup::referencingStop() { bool groupReferencingStopOK=true; static const char *functionName = "referencingStop"; int status = 0; char message[MAX_MESSAGE_LEN]; int stopStatus; asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: entry\n", driverName, functionName); status = GroupReferencingStop(gxgPollSocket, const_cast( gxgName.c_str() ) ); if (status) groupReferencingStopOK = false; switch (-status) { case 0: strcpy(message, " "); break; case 7: strcpy( message, "GroupReferencingStop: Valid command format: ERR_WRONG_FORMAT(-7)" ); break; case 19: strcpy(message, "GroupReferencingStop: Valid Group name: ERR_GROUP_NAME(-19)"); break; case 20: strcpy(message, "GroupReferencingStop: Configuration files reading: ERR_FATAL_INIT(-20)"); break; case 21: strcpy(message, "GroupReferencingStop: XPS initialization in progress: ERR_IN_INITIALIZATION(-21)"); break; case 22: strcpy(message, "GroupReferencingStop: Group state must be 'REFERENCING': ERR_NOT_ALLOWED_ACTION(-22)"); break; case 35: strcpy(message, "GroupReferencingStop: ERR_TRAVEL_LIMITS(-35)"); break; default: sprintf(message, "GroupReferencingStop: Unknown error=%d", status); break; } setStringParam(gxgReferencingMessage_, message); setStringParam( gxgMessage_, message ); stopStatus = (groupReferencingStopOK) ? GROUP_REFERENCING_STATUS_SUCCESS : GROUP_REFERENCING_STATUS_FAILURE; setIntegerParam(gxgReferencingStopStatus_, stopStatus); setIntegerParam(gxgReferencingStop_, 0 ); callParamCallbacks(); return status ? asynError : asynSuccess; } asynStatus GluexXPSGroup::homeSearch() { int status = 0; char message[MAX_MESSAGE_LEN]; int homeStatus; bool groupHomeSearchOK=true; static const char *functionName = "homeSearch"; asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: entry\n", driverName, functionName); status = GroupHomeSearch(gxgPollSocket, const_cast( gxgName.c_str() ) ); /* printf("*****HomeSearch: Status= %d \n", status); */ if (status) groupHomeSearchOK = false; switch (-status) { case 0: strcpy(message, " "); break; case 7: strcpy( message, "GroupHomeSearch: Valid command format: ERR_WRONG_FORMAT(-7)" ); break; case 19: strcpy(message, "GroupHomeSearch: Valid Group name: ERR_GROUP_NAME(-19)"); break; case 20: strcpy(message, "GroupHomeSearch: Configuration files reading: ERR_FATAL_INIT(-20)"); break; case 21: strcpy(message, "GroupHomeSearch: XPS initialization in progress: ERR_IN_INITIALIZATION(-21)"); break; case 22: strcpy(message, "GroupHomeSearch: Group state must be 'Initialized': ERR_NOT_ALLOWED_ACTION(-22)"); break; case 25: strcpy(message, "GroupHomeSearch: ERR_FOLLOWING_ERROR(-25)"); break; case 28: strcpy(message, "GroupHomeSearch: ERR_GROUP_HOME_SEARCH_TIMEOUT(-28)"); break; case 33: strcpy(message, "GroupHomeSearch: ERR_GROUP_MOTION_DONE_TIMEOUT(-33)"); break; case 35: strcpy(message, "GroupHomeSearch: ERR_TRAVEL_LIMITS(-35)"); break; case 49: strcpy(message, "GroupHomeSearch: ERR_GROUP_HOME_SEARCH_ZM_ERROR(-49)"); break; default: sprintf(message, "GroupHomeSearch: Unknown error=%d", status); break; } setStringParam(gxgMessage_, message); homeStatus = (groupHomeSearchOK) ? GROUP_REFERENCING_STATUS_SUCCESS : GROUP_REFERENCING_STATUS_FAILURE; setIntegerParam(gxgHomeSearchStatus_, homeStatus); setIntegerParam( gxgHomeSearch_, 0 ); callParamCallbacks(); return status ? asynError : asynSuccess; } asynStatus GluexXPSGroup::motionEnable() { int status = 0; char message[MAX_MESSAGE_LEN]; int enableStatus; bool groupMotionEnableOK=true; static const char *functionName = "motionEnable"; asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: entry\n", driverName, functionName); status = GroupMotionEnable(gxgPollSocket, const_cast( gxgName.c_str() ) ); if (status) groupMotionEnableOK = false; switch (-status) { case 0: strcpy(message, " "); break; case 7: strcpy( message, "GroupMotionEnable: Valid command format: ERR_WRONG_FORMAT(-7)" ); break; case 8: strcpy( message, "GroupMotionEnable: ERR_WRONG_OBJECT_TYPE(-8)" ); break; case 18: strcpy(message, "GroupMotionEnable: ERR_POSITIONER_NAME(-18)"); break; case 19: strcpy(message, "GroupMotionEnable: Valid Group name: ERR_GROUP_NAME(-19)"); break; case 20: strcpy(message, "GroupMotionEnable: Configuration files reading: ERR_FATAL_INIT(-20)"); break; case 21: strcpy(message, "GroupMotionEnable: XPS initialization in progress: ERR_IN_INITIALIZATION(-21)"); break; case 22: strcpy(message, "GroupMotionEnable: Not 'Homed' or Motion state must be 'Disable': ERR_NOT_ALLOWED_ACTION(-22)"); break; default: sprintf(message, "GroupMotionEnable: Unknown error=%d", status); break; } setStringParam(gxgMessage_, message); enableStatus = (groupMotionEnableOK) ? GROUP_REFERENCING_STATUS_SUCCESS : GROUP_REFERENCING_STATUS_FAILURE; setIntegerParam(gxgMotionEnableStatus_, enableStatus); setIntegerParam( gxgMotionEnable_, 0 ); callParamCallbacks(); return status ? asynError : asynSuccess; } asynStatus GluexXPSGroup::motionDisable() { int status = 0; char message[MAX_MESSAGE_LEN]; int disableStatus; bool groupMotionDisableOK=true; static const char *functionName = "motionDisable"; asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: entry\n", driverName, functionName); status = GroupMotionDisable(gxgPollSocket, const_cast( gxgName.c_str() )); if (status) groupMotionDisableOK = false; switch (-status) { case 0: strcpy(message, " "); break; case 7: strcpy( message, "GroupMotionDisable: Valid command format: ERR_WRONG_FORMAT(-7)" ); break; case 8: strcpy( message, "GroupMotionDisable: ERR_WRONG_OBJECT_TYPE(-8)" ); break; case 18: strcpy(message, "GroupMotionDisable: ERR_POSITIONER_NAME(-18)"); break; case 19: strcpy(message, "GroupMotionDisable: Valid Group name: ERR_GROUP_NAME(-19)"); break; case 20: strcpy(message, "GroupMotionDisable: Configuration files reading: ERR_FATAL_INIT(-20)"); break; case 21: strcpy(message, "GroupMotionDisable: XPS initialization in progress: ERR_IN_INITIALIZATION(-21)"); break; case 22: strcpy(message, "GroupMotionDisable: Not 'Homed' or Motion state must be 'Enable': ERR_NOT_ALLOWED_ACTION(-22)"); break; default: sprintf(message, "GroupMotionDisable: Unknown error=%d", status); break; } setStringParam(gxgMessage_, message); disableStatus = (groupMotionDisableOK) ? PCO_STATUS_SUCCESS : PCO_STATUS_FAILURE; setIntegerParam(gxgMotionDisableStatus_, disableStatus); setIntegerParam( gxgMotionDisable_, 0 ); callParamCallbacks(); return status ? asynError : asynSuccess; } /** The following functions have C linkage, and can be called directly or from iocsh */ extern "C" { // Function that creates a asynPortDriver with portName for group called groupName that belongs to // controller asynPortDriver called cPortName. asynStatus GluexXPSCreateGroup( const char *portName, const char* groupName, const char *cPortNAme ) { GluexXPSController* controllerDiver = GluexXPSController::getDriver( cPortNAme ); if ( controllerDiver != 0 ) { new GluexXPSGroup( portName, groupName, controllerDiver ); return asynSuccess; } else { return asynError; } } static const iocshArg GluexXPSCreateGroupArg0 = { "Group port name", iocshArgString }; static const iocshArg GluexXPSCreateGroupArg1 = { "Group name", iocshArgString }; static const iocshArg GluexXPSCreateGroupArg2 = { "Controller port name", iocshArgString }; static const iocshArg * const GluexXPSCreateGroupArgs[] = { &GluexXPSCreateGroupArg0, &GluexXPSCreateGroupArg1, &GluexXPSCreateGroupArg2 }; static const iocshFuncDef configGluexXPSGroup = { "GluexXPSCreateGroup", 3, GluexXPSCreateGroupArgs }; static void configGluexXPSGroupCallFunc( const iocshArgBuf *args ) { GluexXPSCreateGroup( args[0].sval, args[1].sval, args[2].sval ); } static void GluexXPSGroupRegister( void ) { iocshRegister( &configGluexXPSGroup, configGluexXPSGroupCallFunc ); } epicsExportRegistrar(GluexXPSGroupRegister); } // extern "C"