Initial version of ACS Tech80 motor controller

Tested on Nanomotion (picomotor) motor stage
This commit is contained in:
jsullivan-anl
2006-05-19 16:39:46 +00:00
parent d9115f871f
commit 430c140b12
9 changed files with 1684 additions and 0 deletions
@@ -0,0 +1,66 @@
/*
FILENAME... ACSTech80Register.cc
USAGE... Register ACS Tech80 motor device driver shell commands.
Version: $Revision: 1.1 $
Modified By: $Author: sullivan $
Last Modified: $Date: 2006-05-19 16:39:44 $
*/
/*****************************************************************
COPYRIGHT NOTIFICATION
*****************************************************************
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
This software was developed under a United States Government license
described on the COPYRIGHT_UniversityOfChicago file included as part
of this distribution.
**********************************************************************/
#include <iocsh.h>
#include "ACSTech80Register.h"
#include "epicsExport.h"
extern "C"
{
// ACSTech80 Setup arguments
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
static const iocshArg setupArg1 = {"Polling rate", iocshArgInt};
// ACSTech80 Config arguments
static const iocshArg configArg0 = {"Card being configured", iocshArgInt};
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
static const iocshArg * const ACSTech80SetupArgs[2] = {&setupArg0, &setupArg1};
static const iocshArg * const ACSTech80ConfigArgs[2] = {&configArg0, &configArg1};
static const iocshFuncDef setupSPiiPlus = {"SPiiPlusSetup",2, ACSTech80SetupArgs};
static const iocshFuncDef configSPiiPlus = {"SPiiPlusConfig", 2, ACSTech80ConfigArgs};
static void setupSPiiPlusCallFunc(const iocshArgBuf *args)
{
SPiiPlusSetup(args[0].ival, args[1].ival);
}
static void configSPiiPlusCallFunc(const iocshArgBuf *args)
{
SPiiPlusConfig(args[0].ival, args[1].sval);
}
static void ACSTech80Register(void)
{
iocshRegister(&setupSPiiPlus, setupSPiiPlusCallFunc);
iocshRegister(&configSPiiPlus, configSPiiPlusCallFunc);
}
epicsExportRegistrar(ACSTech80Register);
} // extern "C"
+46
View File
@@ -0,0 +1,46 @@
/*
FILENAME... NewportRegister.h
USAGE... This file contains function prototypes for Newport IOC shell commands.
Version: 1.4
Modified By: rivers
Last Modified: 2004/07/28 18:45:16
*/
/*
* Original Author: Ron Sluiter
* Date: 05/19/03
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
*/
#include "motor.h"
#include "motordrvCom.h"
/* Function prototypes. */
extern RTN_STATUS SPiiPlusSetup(int, int);
extern RTN_STATUS SPiiPlusConfig(int, const char *);
+22
View File
@@ -0,0 +1,22 @@
# Makefile
TOP = ../..
include $(TOP)/configure/CONFIG
# The following are used for debugging messages.
#USR_CXXFLAGS += -DDEBUG
OPT_CXXFLAGS =
DBD += devSPiiPlus.dbd
LIBRARY_IOC = acsTech80
# Intelligent Motion Systems driver support.
SRCS += ACSTech80Register.cc
SRCS += devSPiiPlus.cc drvSPiiPlus.cc
acsTech80_LIBS += motor asyn
acsTech80_LIBS += $(EPICS_BASE_IOC_LIBS)
include $(TOP)/configure/RULES
+58
View File
@@ -0,0 +1,58 @@
ACSTech80 SPiiPlus Motor Controller
===================================
**** EXAMPLE CONFIGURATION FOR VXWORKS TARGETS ****
xxxApp/src/Makefile
-------------------
xxx_vxWorks_LIBS += acsTech80
xxxApp/src/xxxCommonInclude.dbd
--------------------------------
include "devSPiiPlus.dbd"
iocBoot/iocxxx/serial.cmd
---------------------------
# serial 61 is connected to the SPiiPlus Motor Controller
#drvAsynIPPortConfigure("portName","hostInfo",priority,noAutoConnect,
# noProcessEos)
drvAsynIPPortConfigure("serial61", "164.54.116.61:701", 0, 0, 0)
asynOctetSetInputEos("serial61",0,"\r")
asynOctetSetOutputEos("serial61",0,"\r")
.
.
.
# ACS Tech80 - SPiiPlus driver setup parameters:
# (1) maximum number of controllers in system
# (2) motor task polling rate (min=1Hz, max=60Hz)
SPiiPlusSetup(1, 60)
# ACS Tech80 - SPiiPlus driver configuration parameters:
# (1) controller being configured
# (2) asyn port name (string)
SPiiPlusConfig(0, "serial61")
iocBoot/iocxxx/motor.substitutions
----------------------------------
{xxx:, 1, m$(N), "SPiiPlus", 0, 0, "motor $(N)", degrees, Pos, 10, 0., 1., 0, 1, .2, 1e-3, 3, 100, -100, ""}
{xxx:, 2 m$(N), "SPiiPlus", 0, 1, "motor $(N)", degrees, Pos, 60, 0., 1.5, 0, 1, .2, 1e-3, 3, 100, -100, ""}
****************** SPiiPlus Setup *******************************
Install the "SPiiPlus_EPICS.prg" file in the SPiiPlus motor controller
using the ACSTech80 WINDOWS software.
This file contains the EPICS interface programs need by the
motorRecord driver to control one SPiiPlus motors (AXIS 0). For
each motor used, copy the contents of Buffer #0 it's corresponding
buffer. (Motor 1 - buffer #0, Motor 2 - buffer #1, ... etc()
Each motor is assigned a SPiiPlus buffer with a copy of all the programs
that are currently in buffer #0.
+274
View File
@@ -0,0 +1,274 @@
#/ Controller version = 4.50
#/ Date = 04/26/2006 16:41
#/ User remarks = hello
#0
!Note: Each motor needs all the programs in BUFFER 0 copied into its corresponding buffer.
!Note: ie: motor 1 - buffer #0 , motor 2 - buffer #1 ..... etc.
!Note: VEL and ACC are commented out for the AC mode as they are set from EPICS MEDM screens.
!Note: VEL and ACC are DEFINED for the DC mode as they are not defined from EPICS MEDM screens
!ACC is defined in the homing routines as they are defined from EPICS during Homing but VEL is defined.
GLOBAL acpar(4)
GLOBAL dcpar(4)
GLOBAL INT home_F(4)
GLOBAL INT home_R(4)
GLOBAL target_pos(4)
GLOBAL jog_vel(4)
GLOBAL Done(4)
GLOBAL opReq(4)
! Each AXIS has a copy of these functions in a corresponding buffer
LOCAL Axis
Axis = 0
IF opReq(Axis) = 1
call ABS_MOVE
ELSEIF opReq(Axis) = 2
call REL_MOVE
ELSEIF opReq(Axis) = 3
call JOG_MOVE
ELSEIF opReq(Axis) = 4
call HOME_F
ELSEIF opReq(Axis) = 5
call HOME_R
END
opReq(Axis) = 0; Done(Axis) = 1
STOP
!THESE PROGRAMS ARE SMALL ROUTINES THAT ARE REQUIRED FOR CO-ORDINATING MOVEMENT WITH EPICS. THIS IS ESPECIALLY NEEDED
!BECAUSE OF THE AC AND DC MODE SWITCHING NEEDED for AB2 amplifier BEFORE AND AFTER EVERY MOVE.
!Written by Joe Sullivan (BCDA) and Suresh (8-ID) (March 2006)
ABS_MOVE:
! Switch to AC(Servo) Mode
acpar(Axis)=1; TILL acpar(Axis)=0
PTP(Axis),target_pos(Axis)
TILL ^MST(Axis).#MOVE
! Switch to DC(Position) Mode
dcpar(Axis)=1; TILL dcpar(Axis)=0
RET
REL_MOVE:
acpar(Axis)=1; TILL acpar(Axis)=0
PTP/r(Axis),target_pos(Axis)
TILL ^MST(Axis).#MOVE
dcpar(Axis)=1; TILL dcpar(Axis)=0
RET
JOG_MOVE:
acpar(Axis)=1; TILL acpar(Axis)=0
JOG/v(Axis),jog_vel(Axis)
TILL ^MST(Axis).#MOVE
dcpar(Axis)=1; TILL dcpar(Axis)=0
RET
!These program are for homing X and was written by Aaron Dietrich, ACS-Tech80 and modified by Suresh, 8-ID (March 2006)
!EPICS calls these routines when you Home from the MEDM screen.
!HOME_R homes in the -ve direction and HOME_F homes in the +ve direction
!If you desire to home in the same direction due to constraints, change the last 2 lines
!in this program accordingly.
!Note: this program is written for AB2 amplifier. If using with AB5, comment out acpar and dcpar lines
!and rest should be fine.
HOME_R:
! Load tuned parameters for AC mode for AB2 Amplifier
!disable this when using AB5 amplifier
acpar(Axis)=1; TILL acpar(Axis)=0
!VEL(Axis) = 102400*2 !2 mm/sec !defined from EPICS
ACC(Axis) = VEL(Axis)*10
DEC(Axis) = ACC(Axis)
KDEC(Axis) = DEC(Axis)*2
JERK(Axis) = ACC(Axis)*20
DISP "Homing in negative direction is in PROGRESS ......"
ENABLE (Axis)
FDEF(Axis).#CL = 0 !disable default response of Current Limit fault
FDEF(Axis).#CPE = 0 !disable default response of Critical Postion Error fault
FDEF(Axis).#SRL = 0 !disable default response of Software Right Limit fault
FDEF(Axis).#SLL = 0 !disable default response of Software Left Limit fault
JOG (Axis), -
TILL (ABS(PE(Axis))>10000)
JOG (Axis), +
IST(Axis).#IND = 0 !enables the index capture
TILL IST(Axis).#IND = 1 !wait till index capture happens
KILL (Axis)
SET FPOS(Axis)=FPOS(Axis)-IND(Axis) !this sets index position as 0 reference point
PTP (Axis), 0
TILL ^MST(Axis).#MOVE
FDEF(Axis).#CL = 1 !re-enable default response of Current Limit fault
FDEF(Axis).#CPE = 1 !re-enable default response of Critical Postion Error fault
FDEF(Axis).#SRL = 1 !re-enable default response of Software Right Limit fault
FDEF(Axis).#SLL = 1 !re-enable default response of Software Left Limit fault
!Put the stage in DC Mode
dcpar(Axis)=1; TILL dcpar(Axis)=0
!DISABLE (Axis)
DISP "Homing is DONE ......"
home_R(Axis) = 0;
RET
HOME_F:
! Load tuned parameters for AC mode for AB2 Amplifier
!disable this when using AB5 amplifier
acpar(Axis)=1; TILL acpar(Axis)=0
!VEL(Axis) = 102400*2 !2 mm/sec !defined from EPICS
ACC(Axis) = VEL(Axis)*10
DEC(Axis) = ACC(Axis)*0.5
KDEC(Axis) = DEC(Axis)
JERK(Axis) = ACC(Axis)*10
DISP "Homing in positive direction is in PROGRESS ......"
ENABLE (Axis)
FDEF(Axis).#CL = 0 !disable default response of Current Limit fault
FDEF(Axis).#CPE = 0 !disable default response of Critical Postion Error fault
FDEF(Axis).#SRL = 0 !disable default response of Software Right Limit fault
FDEF(Axis).#SLL = 0 !disable default response of Software Left Limit fault
JOG (Axis), +
TILL (ABS(PE(Axis))>10000)
JOG (Axis), -
IST(Axis).#IND = 0 !enables the index capture
TILL IST(Axis).#IND = 1 !wait till index capture happens
KILL (Axis)
SET FPOS(Axis)=FPOS(Axis)-IND(Axis) !this sets index position as 0 reference point
PTP (Axis), 0
TILL ^MST(Axis).#MOVE
FDEF(Axis).#CL = 1 !re-enable default response of Current Limit fault
FDEF(Axis).#CPE = 1 !re-enable default response of Critical Postion Error fault
FDEF(Axis).#SRL = 1 !re-enable default response of Software Right Limit fault
FDEF(Axis).#SLL = 1 !re-enable default response of Software Left Limit fault
!Put the stage in DC Mode
dcpar(Axis)=1; TILL dcpar(Axis)=0
!DISABLE (Axis)
DISP "Homing is DONE ......"
home_F(Axis) = 0;
RET
!THESE PROGRAMS TUNE PARAMETERS SAVED FOR AB2 and AB5 AND THE GOOD
!STAGE TO BE USED IN THE MONO IN 8-ID
!MOSTLY WE WILL NEVER USE AB5 AMPLIFIER AS THE MOTOR IS ALWAYS SERVOING IN THIS MODE
!AND IS NOT GOOD FOR VACUUM USE AS THE MOTOR GETS HOT AND CANNOT BE ENABLED FOR MORE THAN
!10 MINUTES OR SO. IN AB2, DEADBAND IS ACTIVE AND SO THE MOTOR IS BASICALLY DISABLED
!ONCE THE STAGE IS WITHIN THE DEADBAND MAX WHICH IS LIKE 10 COUNTS IN THE CURRENT TUNING
!CONFIGURATION AND IS ABOUT 100 nm.
!In the DC mode, the motor can be kept enabled forever in vacuum and holds position to within 1 count
!which is currently 10 nm.
!Written by Suresh (8-ID) (March 2006)
!Note: VEL and ACC are commented out for the AC mode as they are set from EPICS MEDM screens.
!Note: VEL and ACC are DEFINED for the DC mode as they are not defined from EPICS MEDM screens
!To switch from DC to AC you must disable the motor
AC_TUNED_PAR: ! FOR LONG MOVE
!!!! BLOCK !All commands between BLOCK and END will be executed in one controller cycle (1 msec)
DISABLE(Axis);
SLCPRD(Axis)=1E9; !Set this parameter for Nanomotion with High res. on sin/cos encoder to over come a bug in ACS related to Commutating motors
!VEL(Axis)= 102400 * 1.0; !defined from EPICS
!ACC(Axis)=VEL(Axis)*10; !defined from EPICS
!SET DC_MODE to 0 and SET Nanomotion bit to 1 resp.
MFLAGS(Axis).30 = 0;
MFLAGS(Axis).7 = 1;
XVEL(Axis)=2.048E7;
SLPKP(Axis)=300;
SLVKP(Axis)=20;
SLVKI(Axis)= 1600;
SLFRC(Axis)=17;
SLDZMIN(Axis)=2;
SLDZMAX(Axis)=10;
TARGRAD(Axis) = SLDZMAX(Axis);
SETTLE(Axis) = 10;
DEC(Axis)=ACC(Axis)*0.5;
KDEC(Axis)=DEC(Axis);
JERK(Axis)=ACC(Axis)*10;
!!!! END !All commands between BLOCK and END will be executed in one controller cycle (1 msec)
ENABLE(Axis);
acpar(Axis)=0;
RET
DC_TUNED_PAR:
!SET DC_MODE to 1 and SET Nanomotion bit to 0 resp.
!!!! BLOCK !All commands between BLOCK and END will be executed in one controller cycle (1 msec)
VEL(Axis)=15;
ACC(Axis)=VEL(Axis)*10;
MFLAGS(Axis).30 = 1;
MFLAGS(Axis).7 =0;
XVEL(Axis)=2.048E7;
SLPKP(Axis)=2500;
SLVKP(Axis)=20;
SLVKI(Axis)= 9000;
SLFRC(Axis)=0;
SETTLE(Axis) = 10;
DEC(Axis)=ACC(Axis);
KDEC(Axis)=DEC(Axis);
JERK(Axis)=ACC(Axis)*10;
!SLDZMIN(Axis)=2;SLDZMAX(Axis)=10;TARGRAD(Axis) = SLDZMAX(Axis);
!!!! END !All commands between BLOCK and END will be executed in one controller cycle (1 msec)
dcpar(Axis)=0;
RET
ON home_R(0)=1; Axis = 0; CALL HOME_R; RET
ON home_F(0)=1; Axis = 0; CALL HOME_F; RET
ON acpar(0)=1;Axis=0;CALL AC_TUNED_PAR; RET
ON dcpar(0)=1;Axis=0;CALL DC_TUNED_PAR; RET
#4
!THIS BUFFER STOPS MOTION PROGRAMS ON A PER AXIS BASES AND RETURNS TO DC MODE
!Done(Axis) Flag is used by EPICS to check when op operation is complete
!Written by Joe Sullivan (BCDA) and Suresh (8-ID) (March 2006)
GLOBAL stop_all(4)
GLOBAL Done(4)
GLOBAL acpar(4)
GLOBAL dcpar(4)
LOCAL INT Axis
STOP
STOP_MOVE:
! Stop corresponding buffer
stop Axis
! Halt motor motion and wait until done
HALT(Axis)
TILL ^MST(Axis).#MOVE
!Test that buffer and autoroutine are stopped (with timeout)
TILL ^PST(Axis).#RUN & ^PST(Axis).#AUTO,500
!clear the AC and DC Flags to make sure they are cleared
acpar(0)=0;dcpar(0)=0;
! Switch to DC Mode
dcpar(Axis)=1; TILL dcpar(Axis)=0
! Clear flags
stop_all(Axis) = 0; Done(Axis) = 1;
RET
ON stop_all(0)=1; Axis=0;CALL STOP_MOVE; RET
+336
View File
@@ -0,0 +1,336 @@
/*
FILENAME... devSPiiPlus.cc
USAGE... Motor record device level support for ACS Tech80 SPiiPlus
Version: $Revision: 1.1 $
Modified By: $Author: sullivan $
Last Modified: $Date: 2006-05-19 16:39:45 $
*/
/*
* Original Author: Mark Rivers
* Date: 10/20/97
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
* .01 04-07-05 jps initialized from devMM4000.cc
*/
#include <string.h>
#include <math.h>
#include "motorRecord.h"
#include "motor.h"
#include "motordevCom.h"
#include "drvSPiiPlus.h"
#include "epicsExport.h"
#define STATIC static
extern struct driver_table SPiiPlus_access;
/* ----------------Create the dsets for devSPiiPlus----------------- */
STATIC struct driver_table *drvtabptr;
STATIC long SPiiPlus_init(void *);
STATIC long SPiiPlus_init_record(void *);
STATIC long SPiiPlus_start_trans(struct motorRecord *);
STATIC RTN_STATUS SPiiPlus_build_trans(motor_cmnd, double *, struct motorRecord *);
STATIC RTN_STATUS SPiiPlus_end_trans(struct motorRecord *);
struct motor_dset devSPiiPlus =
{
{8, NULL, (DEVSUPFUN) SPiiPlus_init, (DEVSUPFUN) SPiiPlus_init_record, NULL},
motor_update_values,
SPiiPlus_start_trans,
SPiiPlus_build_trans,
SPiiPlus_end_trans
};
extern "C" {epicsExportAddress(dset,devSPiiPlus);}
/* --------------------------- program data --------------------- */
/* This table is used to define the command types */
/* WARNING! this must match "motor_cmnd" in motor.h */
static msg_types SPiiPlus_table[] = {
MOTION, /* MOVE_ABS */
MOTION, /* MOVE_REL */
MOTION, /* HOME_FOR */
MOTION, /* HOME_REV */
IMMEDIATE, /* LOAD_POS */
IMMEDIATE, /* SET_VEL_BASE */
IMMEDIATE, /* SET_VELOCITY */
IMMEDIATE, /* SET_ACCEL */
IMMEDIATE, /* GO */
IMMEDIATE, /* SET_ENC_RATIO */
INFO, /* GET_INFO */
MOVE_TERM, /* STOP_AXIS */
VELOCITY, /* JOG */
IMMEDIATE, /* SET_PGAIN */
IMMEDIATE, /* SET_IGAIN */
IMMEDIATE, /* SET_DGAIN */
IMMEDIATE, /* ENABLE_TORQUE */
IMMEDIATE, /* DISABL_TORQUE */
IMMEDIATE, /* PRIMITIVE */
IMMEDIATE, /* SET_HIGH_LIMIT */
IMMEDIATE, /* SET_LOW_LIMIT */
VELOCITY /* JOG_VELOCITY */
};
static struct board_stat **SPiiPlus_cards;
/* --------------------------- program data --------------------- */
/* initialize device support for SPiiPlus stepper motor */
STATIC long SPiiPlus_init(void *arg)
{
long rtnval;
int after = (int) arg;
if (after == 0)
{
drvtabptr = &SPiiPlus_access;
(drvtabptr->init)();
}
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &SPiiPlus_cards);
return(rtnval);
}
/* initialize a record instance */
STATIC long SPiiPlus_init_record(void *arg)
{
struct motorRecord *mr = (struct motorRecord *) arg;
return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, SPiiPlus_cards));
}
/* start building a transaction */
STATIC long SPiiPlus_start_trans(struct motorRecord *mr)
{
return(motor_start_trans_com(mr, SPiiPlus_cards));
}
/* end building a transaction */
STATIC RTN_STATUS SPiiPlus_end_trans(struct motorRecord *mr)
{
return(motor_end_trans_com(mr, drvtabptr));
}
/* add a part to the transaction */
STATIC RTN_STATUS SPiiPlus_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
{
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
struct mess_node *motor_call;
struct controller *brdptr;
struct mess_info *motor_info;
struct SPiiPlusController *cntrl;
char buff[110];
int axis, card;
int intval;
double dval;
unsigned int size;
RTN_STATUS rtnval;
rtnval = OK;
buff[0] = '\0';
/* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */
intval = (parms == NULL) ? 0 : NINT(parms[0]);
dval = (parms == NULL) ? 0 : *parms;
motor_call = &(trans->motor_call);
card = motor_call->card;
axis = motor_call->signal;
brdptr = (*trans->tabptr->card_array)[card];
if (brdptr == NULL)
return(rtnval = ERROR);
cntrl = (struct SPiiPlusController *) brdptr->DevicePrivate;
if (SPiiPlus_table[command] > motor_call->type)
motor_call->type = SPiiPlus_table[command];
if (trans->state != BUILD_STATE)
return(rtnval = ERROR);
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
{
strcat(motor_call->message, mr->init);
strcat(motor_call->message, "\r");
}
switch (command)
{
case MOVE_ABS:
case MOVE_REL:
case HOME_FOR:
case HOME_REV:
case JOG:
if (strlen(mr->prem) != 0)
{
strcat(motor_call->message, mr->prem);
strcat(motor_call->message, ";");
}
if (strlen(mr->post) != 0)
motor_call->postmsgptr = (char *) &mr->post;
break;
default:
break;
}
switch (command)
{
case MOVE_ABS:
// sprintf(buff, "ptp (%d), %d;", axis, intval);
sprintf(buff, "Done(%d)=0;target_pos(%d)=%d;opReq(%d)=%d;", axis, axis, intval, axis, OP_ABS_MOVE);
break;
case MOVE_REL:
// sprintf(buff, "ptp/r (%d), %d;", axis, intval);
sprintf(buff, "Done(%d)=0;target_pos(%d)=%d;opReq(%d)=%d;", axis, axis, intval, axis, OP_REL_MOVE);
break;
case HOME_FOR:
sprintf(buff, "Done(%d)=0;opReq(%d)=%d;", axis, axis, OP_HOME_F);
break;
case HOME_REV:
sprintf(buff, "Done(%d)=0;opReq(%d)=%d;", axis, axis, OP_HOME_R);
break;
case LOAD_POS:
/* The Feedback position follows the Reference set position */
sprintf(buff, "set RPOS(%d)=%d;", axis, intval);
break;
case SET_VEL_BASE:
break; /* SPiiPlus does not use base velocity */
case SET_VELOCITY:
sprintf(buff, "VEL%d=%d;", axis, intval);
break;
case SET_ACCEL:
sprintf(buff, "ACC%d=%d;", axis, intval);
break;
case GO:
// Execute the ACS program buffer that corresponds to the axis
// ACS Buffer Execution command must be alone
rtnval = motor_end_trans_com(mr, drvtabptr);
rtnval = (RTN_STATUS) motor_start_trans_com(mr, SPiiPlus_cards);
motor_call->type = SPiiPlus_table[command];
sprintf(buff, "start %d, 1", axis);
break;
case SET_ENC_RATIO:
sprintf(buff, "EFAC%d=%f;", axis, dval);
break;
case GET_INFO:
/* These commands are not actually done by sending a message, but
rather they will indirectly cause the driver to read the status
of all motors */
break;
case STOP_AXIS:
// sprintf(buff, "halt (%d);", axis);
sprintf(buff, "Done(%d)=0;stop_all(%d)=1;", axis, axis);
break;
case JOG:
// sprintf(buff, "jog/v (%d), %d;", axis, intval);
sprintf(buff, "Done(%d)=0;jog_vel(%d)=%d; opReq(%d)=%d;", axis, axis, intval, axis, OP_JOG_MOVE);
strcat(motor_call->message, buff);
// ACS Buffer Execution command must be alone
rtnval = motor_end_trans_com(mr, drvtabptr);
rtnval = (RTN_STATUS) motor_start_trans_com(mr, SPiiPlus_cards);
motor_call->type = SPiiPlus_table[command];
sprintf(buff, "start %d,1", axis);
break;
case SET_PGAIN:
break;
case SET_IGAIN:
break;
case SET_DGAIN:
break;
case ENABLE_TORQUE:
sprintf(buff, "enable(%d);", axis);
break;
case DISABL_TORQUE:
sprintf(buff, "disable(%d);", axis);
break;
case SET_HIGH_LIMIT:
motor_info = &(*trans->tabptr->card_array)[card]->motor_info[axis];
trans->state = IDLE_STATE; /* No command sent to the controller. */
// if (intval > motor_info->high_limit)
// {
// mr->dhlm = motor_info->high_limit * mr->mres;
// rtnval = ERROR;
// }
break;
case SET_LOW_LIMIT:
motor_info = &(*trans->tabptr->card_array)[card]->motor_info[axis];
trans->state = IDLE_STATE; /* No command sent to the controller. */
// if (intval < motor_info->low_limit)
// {
// mr->dllm = motor_info->low_limit * mr->mres;
// rtnval = ERROR;
// }
break;
default:
rtnval = ERROR;
}
size = strlen(buff);
if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE)
errlogMessage("SPiiPlus_build_trans(): buffer overflow.\n");
else
strcat(motor_call->message, buff);
return(rtnval);
}
+5
View File
@@ -0,0 +1,5 @@
# ACS Tech 80 Device Driver support.
device(motor,VME_IO,devSPiiPlus,"SPiiPlus")
driver(drvSPiiPlus)
registrar(ACSTech80Register)
#variable(drvSPiiPlusdebug)
+725
View File
@@ -0,0 +1,725 @@
/*
FILENAME... drvSPiiPlus.cc
USAGE... Motor record driver level support for ACS Tech80
SPiiPlus
Version: $Revision: 1.1 $
Modified By: $Author: sullivan $
Last Modified: $Date: 2006-05-19 16:39:45 $
*/
/*
* Original Author: Mark Rivers
* Date: 10/20/97
* Current Author: J. Sullivan
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
* .01 04-08-05 jps initialized from drvSPiiPlus.cc
*/
#include <string.h>
#include <math.h>
#include <epicsThread.h>
#include <drvSup.h>
#include "motor.h"
#include "ACSTech80Register.h"
#include "drvSPiiPlus.h"
#include "asynOctetSyncIO.h"
#include "epicsExport.h"
#define READ_RESOLUTION "TU;"
#define READ_FAULT "?D/FAULT(%d)"
#define READ_STATUS "?D/MST(%d)"
#define READ_POSITION "?RPOS(%d)"
#define READ_EA_POSITION "?FPOS(%d)"
#define READ_VELOCITY "?FVEL(%d)"
#define READ_ALL_POSITION "?FPOS"
#define READ_HOME "?opReq(%d)"
#define READ_DONE "?Done(%d)"
#define STOP_ALL "halt all"
#define MOTOR_ON "enable(%d)"
#define GET_IDENT "?VR"
#define ACS_EOS "\r" /* End-of-string */
#define SPiiPlus_NUM_CARDS 8
#define BUFF_SIZE 120 /* Maximum length of string to/from SPiiPlus */
#define TIMEOUT 2.0 /* Command timeout in sec. */
/*----------------debugging-----------------*/
#ifdef __GNUG__
#ifdef DEBUG
#define Debug(l, f, args...) { if(l<=drvSPiiPlusdebug) printf(f,## args); }
#else
#define Debug(l, f, args...)
#endif
#else
#define Debug()
#endif
volatile int drvSPiiPlusdebug = 0;
extern "C" {epicsExportAddress(int, drvSPiiPlusdebug);}
/* --- Local data. --- */
int SPiiPlus_num_cards = 0;
/* Local data required for every driver; see "motordrvComCode.h" */
#include "motordrvComCode.h"
/* This is a temporary fix to introduce a delayed reading of the motor
* position after a move completes
*/
volatile double drvSPiiPlusReadbackDelay = 0.;
/*----------------functions-----------------*/
static int recv_mess(int card, char *com, int flag);
static RTN_STATUS send_mess(int card, char const *, char *name);
static int send_recv_mess(int card, char const *send_com, char *recv_com);
static int set_status(int card, int signal);
static long report(int level);
static long init();
static int motor_init();
static void query_done(int, int, struct mess_node *);
/*----------------functions-----------------*/
struct driver_table SPiiPlus_access =
{
motor_init,
motor_send,
motor_free,
motor_card_info,
motor_axis_info,
&mess_queue,
&queue_lock,
&free_list,
&freelist_lock,
&motor_sem,
&motor_state,
&total_cards,
&any_motor_in_motion,
send_mess,
recv_mess,
set_status,
query_done,
NULL,
&initialized,
NULL
};
struct
{
long number;
#ifdef __cplusplus
long (*report) (int);
long (*init) (void);
#else
DRVSUPFUN report;
DRVSUPFUN init;
#endif
} drvSPiiPlus = {2, report, init};
extern "C" {epicsExportAddress(drvet, drvSPiiPlus);}
static struct thread_args targs = {SCAN_RATE, &SPiiPlus_access, 0.010};
/*********************************************************
* Print out driver status report
*********************************************************/
static long report(int level)
{
int card;
if (SPiiPlus_num_cards <=0)
printf(" No SPiiPlus controllers configured.\n");
else
{
for (card = 0; card < SPiiPlus_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
if (brdptr == NULL)
printf(" SPiiPlus controller %d connection failed.\n", card);
else
{
struct SPiiPlusController *cntrl;
cntrl = (struct SPiiPlusController *) brdptr->DevicePrivate;
printf(" SPiiPlus controller %d, port=%s, address=%d, id: %s \n",
card, cntrl->asyn_port, cntrl->asyn_address,
brdptr->ident);
}
}
}
return(OK);
}
static long init()
{
/*
* We cannot call motor_init() here, because that function can do GPIB I/O,
* and hence requires that the drvGPIB have already been initialized.
* That cannot be guaranteed, so we need to call motor_init from device
* support
*/
/* Check for setup */
if (SPiiPlus_num_cards <= 0)
{
Debug(1, "init(): SPiiPlus driver disabled. SPiiPlusSetup() missing from startup script.\n");
}
return((long) 0);
}
static void query_done(int card, int axis, struct mess_node *nodeptr)
{
}
/*********************************************************
* Read the status and position of all motors on a card
* start_status(int card)
* if card == -1 then start all cards
*********************************************************/
// static void start_status(int card)
//{
//}
/**************************************************************
* Parse status and position strings for a card and signal
* set_status()
************************************************************/
static int set_status(int card, int signal)
{
struct SPiiPlusController *cntrl;
struct mess_node *nodeptr;
register struct mess_info *motor_info;
char send_buff[80];
int flags;
double vel;
MOTOR_STATUS mstat;
MOTOR_FAULTS mfault;
int rtn_state;
int recvCnt;
int opReq;
long motorData;
bool homing;
bool plusdir, ls_active = false;
msta_field status;
cntrl = (struct SPiiPlusController *) motor_state[card]->DevicePrivate;
motor_info = &(motor_state[card]->motor_info[signal]);
status.All = motor_info->status.All;
sprintf(send_buff, READ_STATUS, signal);
recvCnt = send_recv_mess(card, send_buff, cntrl->recv_string[QSTATUS]);
if (recvCnt > 0)
{
cntrl->status = NORMAL;
sprintf(send_buff, READ_DONE, signal);
recvCnt = send_recv_mess(card, send_buff, cntrl->recv_string[QDONE]);
sprintf(send_buff, READ_FAULT, signal);
recvCnt = send_recv_mess(card, send_buff, cntrl->recv_string[QFAULT]);
sprintf(send_buff, READ_POSITION, signal);
recvCnt = send_recv_mess(card, send_buff, cntrl->recv_string[QPOS]);
sprintf(send_buff, READ_EA_POSITION, signal);
recvCnt = send_recv_mess(card, send_buff, cntrl->recv_string[QEA_POS]);
sprintf(send_buff, READ_VELOCITY, signal);
recvCnt = send_recv_mess(card, send_buff, cntrl->recv_string[QVEL]);
sprintf(send_buff, READ_HOME, signal);
recvCnt = send_recv_mess(card, send_buff, cntrl->recv_string[QHOME]);
}
else
{
if (cntrl->status == NORMAL)
cntrl->status = RETRY;
else
cntrl->status = COMM_ERR;
}
if (cntrl->status != NORMAL)
{
if (cntrl->status == COMM_ERR)
{
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
else
{
rtn_state = 0;
goto exit;
}
}
else
status.Bits.CNTRL_COMM_ERR = 0;
nodeptr = motor_info->motor_motion;
/*
* Parse the status/fault strings
*/
flags = atoi(cntrl->recv_string[QSTATUS]);
mstat.All = flags;
mfault.All = atoi(cntrl->recv_string[QFAULT]);
Debug(5, "set_status(): status byte = %x, fault int = %x\n", mstat.All, mfault.All);
vel = atof(cntrl->recv_string[QVEL]);
status.Bits.RA_DIRECTION = (vel >= 0) ? 1 : 0;
plusdir = (status.Bits.RA_DIRECTION) ? true : false;
status.Bits.RA_DONE = (atoi(cntrl->recv_string[QDONE])) ? 1 : 0;
// if (mstat.Bits.inmotion == false && mstat.Bits.inposition == true)
// {
// status.Bits.RA_DONE = 1;
// }
// else
// status.Bits.RA_DONE = 0;
opReq = atoi(cntrl->recv_string[QHOME]);
homing = (opReq == OP_HOME_F || opReq == OP_HOME_R) ? true : false;
status.Bits.RA_HOME = status.Bits.RA_DONE;
/* Set Travel limit switch status bits. */
if ((mfault.Bits.rl == false && mfault.Bits.srl == false) || homing)
status.Bits.RA_PLUS_LS = 0;
else
{
status.Bits.RA_PLUS_LS = 1;
if (plusdir == true)
ls_active = true;
}
if ((mfault.Bits.ll == false && mfault.Bits.sll == false) || homing)
status.Bits.RA_MINUS_LS = 0;
else
{
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
}
/* Position maintence enabled */
status.Bits.EA_POSITION = (mstat.Bits.enabled) ? 1: 0;
/* encoder status */
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP_STALL = 0;
status.Bits.EA_HOME = 0;
/*
* Parse motor position
*/
motorData = (long)atof(cntrl->recv_string[QPOS]);
// printf("motorData=%ld, last_position=%ld, count=%d\n",motorData, motor_info->position, motor_info->no_motion_count);
if (motorData == motor_info->position)
{
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
}
else
{
motor_info->position = motorData;
motor_info->no_motion_count = 0;
}
// Always update encoder position - for non-motion monitoring
if (motor_state[card]->motor_info[signal].encoder_present == YES)
motor_info->encoder_position = (long)(atof(cntrl->recv_string[QEA_POS]));
else
motor_info->encoder_position = 0;
status.Bits.RA_PROBLEM = 0;
/* Parse motor velocity? */
/* NEEDS WORK */
motor_info->velocity = (int)vel;
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
/* Test for post-move string. */
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 &&
nodeptr->postmsgptr != 0)
{
strncpy(send_buff, nodeptr->postmsgptr, 80);
send_mess(card, send_buff, (char) NULL);
nodeptr->postmsgptr = NULL;
}
exit:
motor_info->status.All = status.All;
return(rtn_state);
}
/*****************************************************/
/* send_receive a message to the SPiiPlus board */
/* send_recv_mess() */
/*****************************************************/
static int send_recv_mess(int card, char const *send_com, char *recv_com)
{
struct SPiiPlusController *cntrl;
int size;
size_t nwrite;
size_t nread = 0;
double timeout = 0.;
asynStatus status;
int eomReason;
size = strlen(send_com);
recv_com[0] = '\0';
if (size > MAX_MSG_SIZE)
{
errlogMessage("drvSPiiPlus.c:send_recv_mess(); message size violation.\n");
return(ERROR);
}
else if (size == 0) /* Normal exit on empty input message. */
return(OK);
if (!motor_state[card])
{
errlogPrintf("drvSPiiPlus.c:send_recv_mess() - invalid card #%d\n", card);
return(ERROR);
}
Debug(2, "send_recv_mess(): message = %s\n", send_com);
cntrl = (struct SPiiPlusController *) motor_state[card]->DevicePrivate;
timeout = TIMEOUT;
/* flush any junk at input port - should not be any data available */
pasynOctetSyncIO->flush(cntrl->pasynUser);
/* Perform atomic write/read operation */
status = pasynOctetSyncIO->writeRead(cntrl->pasynUser, send_com, strlen(send_com),
recv_com, ACS_MSG_SIZE,
TIMEOUT, &nwrite, &nread, &eomReason);
if ((status != asynSuccess) || (nread <= 0))
{
recv_com[0] = '\0';
nread = 0;
}
Debug(2, "send_recv_mess(): recv message = \"%s\"\n", recv_com);
return(nread);
}
/*****************************************************/
/* send a message to the SPiiPlus board */
/* send_mess() */
/*****************************************************/
static RTN_STATUS send_mess(int card, char const *com, char *name)
{
struct SPiiPlusController *cntrl;
int size;
size_t nwrite;
size = strlen(com);
if (size > MAX_MSG_SIZE)
{
errlogMessage("drvSPiiPlus.c:send_mess(); message size violation.\n");
return(ERROR);
}
else if (size == 0) /* Normal exit on empty input message. */
return(OK);
if (!motor_state[card])
{
errlogPrintf("drvSPiiPlus.c:send_mess() - invalid card #%d\n", card);
return(ERROR);
}
if (name != NULL)
{
errlogPrintf("drvSPiiPlus.c:send_mess() - invalid argument = %s\n", name);
return(ERROR);
}
Debug(2, "send_mess(): message = %s\n", com);
cntrl = (struct SPiiPlusController *) motor_state[card]->DevicePrivate;
/* flush any junk at input port - should not be any data available */
pasynOctetSyncIO->flush(cntrl->pasynUser);
pasynOctetSyncIO->write(cntrl->pasynUser, com, strlen(com),
TIMEOUT, &nwrite);
return(OK);
}
/*
* FUNCTION... recv_mess(int card, char *com, int flag)
*
* INPUT ARGUMENTS...
* card - controller card # (0,1,...).
* *com - caller's response buffer.
* flag | FLUSH = this flag is ignored - the receive buffer is flushed
* on every write (see write_mess())
* LOGIC...
* IF controller card does not exist.
* ERROR RETURN.
* ENDIF
* NORMAL RETURN.
*/
static int recv_mess(int card, char *com, int flag)
{
struct SPiiPlusController *cntrl;
double timeout = 0.;
size_t nread = 0;
asynStatus status;
int eomReason;
/* Check that card exists */
if (!motor_state[card])
return(ERROR);
cntrl = (struct SPiiPlusController *) motor_state[card]->DevicePrivate;
timeout = TIMEOUT;
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
timeout, &nread, &eomReason);
if ((status != asynSuccess) || (nread <= 0))
{
com[0] = '\0';
nread = 0;
}
Debug(2, "recv_mess(): message = \"%s\"\n", com);
return(nread);
}
/*****************************************************/
/* Setup system configuration */
/* SPiiPlusSetup() */
/*****************************************************/
RTN_STATUS
SPiiPlusSetup(int num_cards, /* maximum number of controllers in system. */
int scan_rate) /* polling rate - 1/60 sec units. */
{
int itera;
if (num_cards < 1 || num_cards > SPiiPlus_NUM_CARDS)
SPiiPlus_num_cards = SPiiPlus_NUM_CARDS;
else
SPiiPlus_num_cards = num_cards;
/* Set motor polling task rate */
if (scan_rate >= 1 && scan_rate <= 60)
targs.motor_scan_rate = scan_rate;
else
targs.motor_scan_rate = SCAN_RATE;
/*
* Allocate space for motor_state structures. Note this must be done
* before SPiiPlusConfig is called, so it cannot be done in motor_init()
* This means that we must allocate space for a card without knowing
* if it really exists, which is not a serious problem
*/
motor_state = (struct controller **) malloc(SPiiPlus_num_cards *
sizeof(struct controller *));
for (itera = 0; itera < SPiiPlus_num_cards; itera++)
motor_state[itera] = (struct controller *) NULL;
return(OK);
}
/*****************************************************/
/* Configure a controller */
/* SPiiPlusConfig() */
/*****************************************************/
RTN_STATUS
SPiiPlusConfig(int card, /* card being configured */
const char *name) /* asyn port name */
{
struct SPiiPlusController *cntrl;
if (card < 0 || card >= SPiiPlus_num_cards)
return(ERROR);
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
motor_state[card]->DevicePrivate = malloc(sizeof(struct SPiiPlusController));
cntrl = (struct SPiiPlusController *) motor_state[card]->DevicePrivate;
strcpy(cntrl->asyn_port, name);
return(OK);
}
/*****************************************************/
/* initialize all software and hardware */
/* This is called from the initialization routine in */
/* device support. */
/* motor_init() */
/*****************************************************/
static int motor_init()
{
struct controller *brdptr;
struct SPiiPlusController *cntrl;
int card_index, motor_index;
char axis_pos[BUFF_SIZE];
char buff[BUFF_SIZE];
char write_buff[30];
char *tok_save, *pos_ptr;
int total_axis = 0;
int status;
asynStatus success_rtn;
initialized = true; /* Indicate that driver is initialized. */
/* Check for setup */
if (SPiiPlus_num_cards <= 0)
return(ERROR);
for (card_index = 0; card_index < SPiiPlus_num_cards; card_index++)
{
if (!motor_state[card_index])
continue;
brdptr = motor_state[card_index];
brdptr->cmnd_response = true;
total_cards = card_index + 1;
cntrl = (struct SPiiPlusController *) brdptr->DevicePrivate;
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port,
cntrl->asyn_address, &cntrl->pasynUser, NULL);
if (success_rtn == asynSuccess)
{
int retry = 0;
/* Set command End-of-string */
pasynOctetSyncIO->setInputEos(cntrl->pasynUser,ACS_EOS,strlen(ACS_EOS));
pasynOctetSyncIO->setOutputEos(cntrl->pasynUser,ACS_EOS,strlen(ACS_EOS));
/* Send a message to the board, see if it exists */
do
{
status = send_recv_mess(card_index, READ_ALL_POSITION, axis_pos);
retry++;
/* Return value is length of response string */
} while(status == 0 && retry < 3);
}
if (success_rtn == asynSuccess && status > 0)
{
brdptr->localaddr = (char *) NULL;
brdptr->motor_in_motion = 0;
status = send_recv_mess(card_index, STOP_ALL, buff); /* Stop all motors */
status = send_recv_mess(card_index, GET_IDENT, buff); /* Read controller ID string */
strcpy(brdptr->ident, buff); /* Save Version */
/* The return string will tell us how many axes this controller has */
for (total_axis = 0, tok_save = NULL, pos_ptr = strtok_r(axis_pos, " ", &tok_save);
pos_ptr != 0; pos_ptr = strtok_r(NULL, " ", &tok_save), total_axis++)
brdptr->motor_info[total_axis].motor_motion = NULL;
brdptr->total_axis = total_axis;
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
motor_info->status.All = 0;
motor_info->no_motion_count = 0;
motor_info->encoder_position = 0;
motor_info->position = 0;
/* Encoder Enable */
motor_info->encoder_present = YES;
motor_info->status.Bits.EA_PRESENT = 1;
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
/* Determine low limit */
sprintf(write_buff, "?SLLIMIT(%d)", motor_index);
status = send_recv_mess(card_index, write_buff, buff);
// motor_info->low_limit = atof(buff);
/* Determine high limit */
sprintf(write_buff, "?SRLIMIT(%d)", motor_index);
status = send_recv_mess(card_index, write_buff, buff);
// motor_info->high_limit = atof(buff);
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
}
any_motor_in_motion = 0;
mess_queue.head = (struct mess_node *) NULL;
mess_queue.tail = (struct mess_node *) NULL;
free_list.head = (struct mess_node *) NULL;
free_list.tail = (struct mess_node *) NULL;
// epicsThreadCreate((char *) "SPiiPlus_motor", 64, 5000, (EPICSTHREADFUNC) motor_task, (void *) &targs);
epicsThreadCreate((char *) "SPiiPlus_motor",
epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
return(OK);
}
+152
View File
@@ -0,0 +1,152 @@
/*
FILENAME... drvSPiiPlus.h
USAGE... This file contains ACS Tech80 driver "include"
information that is specific to the SPiiPlus serial controller
Version: $Revision: 1.1 $
Modified By: $Author: sullivan $
Last Modified: $Date: 2006-05-19 16:39:46 $
*/
/*
* Original Author: Mark Rivers
* Current Author: J. Sullivan
* Date: 10/16/97
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
* .01 04-07-05 jps initialized from drvMM4000.cc
*/
#ifndef INCdrvSPiiPlush
#define INCdrvSPiiPlush 1
#include "motor.h"
#include "motordrvCom.h"
#include "asynDriver.h"
#include "asynOctetSyncIO.h"
#define ACS_MSG_SIZE 120
// ACS Motion Commands -
// These definitions must match the native ACS programming
#define OP_ABS_MOVE 1
#define OP_REL_MOVE 2
#define OP_JOG_MOVE 3
#define OP_HOME_F 4
#define OP_HOME_R 5
#define QUERY_CNT 7
enum query_types {QSTATUS, QFAULT, QPOS, QEA_POS, QVEL, QHOME, QDONE};
/* Motion Master specific data is stored in this structure. */
struct SPiiPlusController
{
asynUser *pasynUser; /* For RS-232 */
int asyn_address; /* Use for GPIB or other address with asyn */
char asyn_port[80]; /* asyn port name */
char recv_string[QUERY_CNT][ACS_MSG_SIZE]; /* Query result strings */
double home_preset[MAX_AXIS]; /* Controller's home preset position (XF command). */
CommStatus status; /* Controller communication status. */
};
/* Motor status response for SPiiPlus . */
typedef union
{
epicsUInt8 All;
struct
{
#ifdef MSB_First
bool bit7 :1; /* Bit #7 N/A. */
bool inaccel :1; /* Motor is accelerating */
bool inmotion :1; /* Motor in-motion */
bool inposition :1; /* Motor in position */
bool bit3 :1; /* Bit #3 N/A */
bool bit2 :1; /* Bit #2 N/A */
bool openloop :1; /* Motor in open-loop (torque control) mode */
bool enabled :1; /* Motor Enabled */
#else
bool enabled :1; /* Motor Enabled */
bool openloop :1; /* Motor in open-loop (torque control) mode */
bool bit2 :1; /* Bit #2 N/A */
bool bit3 :1; /* Bit #3 N/A */
bool inposition :1; /* Motor in position */
bool inmotion :1; /* Motor in-motion */
bool inaccel :1; /* Motor is accelerating */
bool bit7 :1; /* Bit #7 N/A. */
#endif
} Bits;
} MOTOR_STATUS;
/*
* Motor fault flags for SPiiPlus
* (See page 8-4 in SPiiPlus ACSPL Programmers Guide)
*/
typedef union
{
epicsUInt32 All;
struct
{
#ifdef MSB_First
bool bit31 :1; /* Bit #31 N/A */
bool misc_faults :6; /* Misc. Faults */
bool bits21_24 :4; /* Bits #21 - #24 N/A */
bool hssinc :1; /* HSSI Not Connected */
bool bits19 :1; /* Bits #9 N/A */
bool bits18 :1; /* Bits #18 N/A */
bool sp :1; /* Servo Processor Alarm */
bool limit_error :3; /* Limit Error (Vel, Accel, Current) */
bool pos_error :2; /* Position Error */
bool enc_error :5; /* Encoder or Drive error */
bool sll :1; /* Software Left Limit */
bool srl :1; /* Software Right Limit */
bool bits2_4 :3; /* Bits #2 - #4 N/A */
bool rl :1; /* Left Limit */
bool ll :1; /* Right Limit */
#else
bool ll :1; /* Right Limit */
bool rl :1; /* Left Limit */
bool bits2_4 :3; /* Bits #2 - #4 N/A */
bool srl :1; /* Software Right Limit */
bool sll :1; /* Software Left Limit */
bool enc_error :5; /* Encoder or Drive error */
bool pos_error :2; /* Position Error */
bool limit_error :3; /* Limit Error (Vel, Accel, Current) */
bool sp :1; /* Servo Processor Alarm */
bool bits18 :1; /* Bits #18 N/A */
bool bits19 :1; /* Bits #9 N/A */
bool hssinc :1; /* HSSI Not Connected */
bool bits21_24 :4; /* Bits #21 - #24 N/A */
bool misc_faults :6; /* Misc. Faults */
bool bit31 :1; /* Bit #31 N/A */
#endif
} Bits;
} MOTOR_FAULTS;
#endif /* INCdrvSPiiPlush */