Removed FaulhaberSrc; Added motorFaulhaber submodule

This commit is contained in:
kpetersn
2019-04-04 16:13:52 -05:00
parent cc0bfbfd46
commit 2b77267562
13 changed files with 5 additions and 1224 deletions
+3
View File
@@ -13,3 +13,6 @@
[submodule "modules/motorDeltaTau"]
path = modules/motorDeltaTau
url = https://github.com/epics-motor/motorDeltaTau.git
[submodule "modules/motorFaulhaber"]
path = modules/motorFaulhaber
url = https://github.com/epics-motor/motorFaulhaber.git
-16
View File
@@ -173,22 +173,6 @@ dbLoadRecords("$(MOTOR)/db/motorUtil.db", "P=IOC:")
#!SC800Config(0, "L0", 0)
#!drvSC800debug=4
# Faulhaber MCDC2805 driver setup parameters:
# (1)Max. controller count
# (2)Polling rate
#!MCDC2805Setup(1, 10)
# Faulhaber MCDC2805 driver configuration parameters:
# (1)Card being configured
# (2)# modules on this serial port
# (3)asyn port name
#!MCDC2805Config(0, 1, "L0")
#!drvMCDC2805debug=4
# The MCDC2805 driver does not set end of string (EOS).
#!asynOctetSetInputEos("L0",0,"\r")
#!asynOctetSetOutputEos("L0",0,"\r")
# Aerotech Ensemble digital servo controller Setup
# (1) maximum number of controllers in system
-16
View File
@@ -129,22 +129,6 @@ asynSetOption("L0", -1, "crtscts", "N")
#!SC800Config(0, "L0", 0)
#!var drvSC800debug 4
# Faulhaber MCDC2805 driver setup parameters:
# (1)Max. controller count
# (2)Polling rate
#!MCDC2805Setup(1, 10)
# Faulhaber MCDC2805 driver configuration parameters:
# (1)Card being configured
# (2)# modules on this serial port
# (3)asyn port name
#!MCDC2805Config(0, 1, "L0")
#!var drvMCDC2805debug 4
# The MCDC2805 driver does not set end of string (EOS).
#!asynOctetSetInputEos("L0",0,"\r")
#!asynOctetSetOutputEos("L0",0,"\r")
# Aerotech Ensemble digital servo controller Setup
# (1) maximum number of controllers in system
-17
View File
@@ -95,23 +95,6 @@ dbLoadRecords("$(MOTOR)/db/motorUtil.db", "P=IOC:")
#!MDriveConfig(0, "L0")
#!var drvMDrivedebug 4
# Faulhaber MCDC2805 driver setup parameters:
# (1)Max. controller count
# (2)Polling rate
#!MCDC2805Setup(1, 10)
# Faulhaber MCDC2805 driver configuration parameters:
# (1)Card being configured
# (2)# modules on this serial port
# (3)asyn port name
#!MCDC2805Config(0, 1, "L0")
#!var drvMCDC2805debug 4
# The MCDC2805 driver does not set end of string (EOS).
#!asynOctetSetInputEos("L0",0,"\r")
#!asynOctetSetOutputEos("L0",0,"\r")
# Aerotech Ensemble digital servo controller Setup
# (1) maximum number of controllers in system
# (2) motor task polling rate (min=1Hz,max=60Hz)
+1
View File
@@ -8,6 +8,7 @@ SUBMODULES += motorNewport
SUBMODULES += motorAcsTech80
SUBMODULES += motorAttocube
SUBMODULES += motorDeltaTau
SUBMODULES += motorFaulhaber
# Allow sites to add extra submodules
-include Makefile.local
-19
View File
@@ -1,19 +0,0 @@
# Makefile
TOP = ../..
include $(TOP)/configure/CONFIG
# The following are used for debugging messages.
#USR_CXXFLAGS += -DDEBUG
DBD += devFaulhaberMotor.dbd
LIBRARY_IOC = Faulhaber
# Intelligent Motion Systems driver support.
SRCS += devMCDC2805.cc drvMCDC2805.cc
Faulhaber_LIBS += motor asyn
Faulhaber_LIBS += $(EPICS_BASE_IOC_LIBS)
include $(TOP)/configure/RULES
-52
View File
@@ -1,52 +0,0 @@
Faulhaber MCDC2805 driver
Mark Rivers
Nov. 4, 2005
This driver supports the Faulhaber MCDC2805 servo controller.
It assumes the following wiring:
Analog input = Input 1 = Home input
Fault pin = Input 2 = CW limit
Input 3 Input 3 = CCW limit
There is a currently a problem with the Home input, and its status cannot be read. The reason for this
is being investigated, but until it is resolved the home functions in the motor record do not work.
The following commands are send to the MCDC2805 when the EPICS software initializes:
/* Set the velocity control to be RS-232 */
SOR 0
/* Program fault pin as limit switch input */
REFIN
/* Program limit polarity for rising edge and high level */
HP7
/* Program the motor to hard block on the the limit switch inputs */
HB6
/* Program the limit switch directions to block
* + direction on input 2, - direction on input 3 */
HD2
/* Program homing sequence on input 1*/
HL1
HA1
CAHOSEQ
It is a good idea to set the power-up behavior of the device to be "disabled" by sending the following
commands once:
DI
EEPSAV
It is also necessary to change the address of the board from the default address of 0 if daisy chaining
multiple modules. To change to address 1, send the following commands once:
NODEADR 1
EEPSAV
@@ -1,5 +0,0 @@
# Intelligent Motion Systems driver support.
device(motor,VME_IO,devMCDC2805, "MCDC2805")
driver(drvMCDC2805)
registrar(MCDC2805Register)
variable(drvMCDC2805debug)
-346
View File
@@ -1,346 +0,0 @@
/*
FILENAME... devMCDC2805.cc
USAGE... Motor record device level support for Intelligent Motion
Systems, Inc. MCDC2805 series of controllers.
*/
/*
* Original Author: Mark Rivers
* Date: 10/20/05
*
* 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 10/20/05 mlr Initialize from ImsSrc/devMDrive.cc
*/
#include <string.h>
#include <errlog.h>
#include "motorRecord.h"
#include "motor.h"
#include "motordevCom.h"
#include "drvMCDC2805.h"
#include "epicsExport.h"
#define STATIC static
extern struct driver_table MCDC2805_access;
/* ----------------Create the dsets for devMCDC2805----------------- */
STATIC struct driver_table *drvtabptr;
STATIC long MCDC2805_init(int);
STATIC long MCDC2805_init_record(void *);
STATIC long MCDC2805_start_trans(struct motorRecord *);
STATIC RTN_STATUS MCDC2805_build_trans(motor_cmnd, double *, struct motorRecord *);
STATIC RTN_STATUS MCDC2805_end_trans(struct motorRecord *);
struct motor_dset devMCDC2805 =
{
{8, NULL, (DEVSUPFUN) MCDC2805_init, (DEVSUPFUN) MCDC2805_init_record, NULL},
motor_update_values,
MCDC2805_start_trans,
MCDC2805_build_trans,
MCDC2805_end_trans
};
extern "C" {epicsExportAddress(dset,devMCDC2805);}
/* --------------------------- program data --------------------- */
/* This table is used to define the command types */
/* WARNING! this must match "motor_cmnd" in motor.h */
static msg_types MCDC2805_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 **MCDC2805_cards;
/* --------------------------- program data --------------------- */
/* initialize device support for MCDC2805 stepper motor */
STATIC long MCDC2805_init(int after)
{
long rtnval;
if (!after)
{
drvtabptr = &MCDC2805_access;
(drvtabptr->init)();
}
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &MCDC2805_cards);
return(rtnval);
}
/* initialize a record instance */
STATIC long MCDC2805_init_record(void *arg)
{
struct motorRecord *mr = (struct motorRecord *) arg;
return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, MCDC2805_cards));
}
/* start building a transaction */
STATIC long MCDC2805_start_trans(struct motorRecord *mr)
{
return(OK);
}
/* end building a transaction */
STATIC RTN_STATUS MCDC2805_end_trans(struct motorRecord *mr)
{
return(OK);
}
/* add a part to the transaction */
STATIC RTN_STATUS MCDC2805_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 MCDC2805controller *cntrl;
char buff[110];
int axis, card, intval;
int rpm;
unsigned int size;
RTN_STATUS rtnval;
bool send;
msta_field msta;
send = true; /* Default to send motor command. */
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]);
msta.All = mr->msta;
motor_start_trans_com(mr, MCDC2805_cards);
motor_call = &(trans->motor_call);
card = motor_call->card;
axis = motor_call->signal + 1;
brdptr = (*trans->tabptr->card_array)[card];
if (brdptr == NULL)
return(rtnval = ERROR);
cntrl = (struct MCDC2805controller *) brdptr->DevicePrivate;
if (MCDC2805_table[command] > motor_call->type)
motor_call->type = MCDC2805_table[command];
if (trans->state != BUILD_STATE)
return(rtnval = ERROR);
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
{
strcat(motor_call->message, " ");
strcat(motor_call->message, mr->init);
}
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, "LA %d", intval);
break;
case MOVE_REL:
sprintf(buff, "LR %d", intval);
break;
case HOME_FOR:
case HOME_REV:
rpm = NINT(mr->velo / mr->srev * 60.);
if (command == HOME_REV) rpm = -rpm;
/* Need to send multiple messages */
sprintf(buff, "ENCRES%d", mr->srev);
strcpy(motor_call->message, buff);
rtnval = motor_end_trans_com(mr, drvtabptr);
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MCDC2805_cards);
sprintf(buff, "HOSP%d", rpm);
strcpy(motor_call->message, buff);
rtnval = motor_end_trans_com(mr, drvtabptr);
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MCDC2805_cards);
sprintf(buff, "GOHOSEQ");
motor_call->type = MCDC2805_table[command];
break;
case LOAD_POS:
sprintf(buff, "HO %d", intval);
break;
case SET_VEL_BASE:
/* Not supported */
send = false;
break;
case SET_VELOCITY:
/* The input speed is in steps/second. The controller wants RPM */
rpm = NINT(parms[0] / mr->srev * 60.);
/* Need to send multiple messages */
sprintf(buff, "ENCRES%d", mr->srev);
strcpy(motor_call->message, buff);
rtnval = motor_end_trans_com(mr, drvtabptr);
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MCDC2805_cards);
sprintf(buff, "SP %d", rpm);
motor_call->type = MCDC2805_table[command];
break;
case SET_ACCEL:
/* The input speed is in steps/s/s. The controller wants Revs/s/s */
rpm = NINT(parms[0] / mr->srev);
/* Need to send multiple messages */
sprintf(buff, "ENCRES%d", mr->srev);
strcpy(motor_call->message, buff);
rtnval = motor_end_trans_com(mr, drvtabptr);
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MCDC2805_cards);
sprintf(buff, "AC %d", rpm);
motor_call->type = MCDC2805_table[command];
break;
case GO:
sprintf(buff, "M");
break;
case PRIMITIVE:
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, "V 0");
break;
case JOG_VELOCITY:
case JOG:
rpm = NINT(parms[0] / mr->srev * 60.);
/* Need to send multiple messages */
sprintf(buff, "ENCRES%d", mr->srev);
strcpy(motor_call->message, buff);
rtnval = motor_end_trans_com(mr, drvtabptr);
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MCDC2805_cards);
sprintf(buff, "SP %d", rpm);
strcpy(motor_call->message, buff);
rtnval = motor_end_trans_com(mr, drvtabptr);
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MCDC2805_cards);
sprintf(buff, "V %d", rpm);
motor_call->type = MCDC2805_table[command];
break;
case SET_PGAIN:
sprintf(buff, "POR %ld", NINT(parms[0]*255.));
break;
case SET_IGAIN:
sprintf(buff, "I %ld", NINT(parms[0]*255.));
break;
case SET_DGAIN:
send = false;
break;
case ENABLE_TORQUE:
sprintf(buff, "EN");
break;
case DISABL_TORQUE:
sprintf(buff, "DI");
break;
case SET_HIGH_LIMIT:
case SET_LOW_LIMIT:
case SET_ENC_RATIO:
trans->state = IDLE_STATE; /* No command sent to the controller. */
send = false;
break;
default:
send = false;
rtnval = ERROR;
}
size = strlen(buff);
if (send == false)
return(rtnval);
else if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE)
errlogMessage("MCDC2805_build_trans(): buffer overflow.\n");
else
{
strcat(motor_call->message, buff);
motor_end_trans_com(mr, drvtabptr);
}
return(rtnval);
}
-688
View File
@@ -1,688 +0,0 @@
/*
FILENAME... drvMCDC2805.cc
USAGE... Motor record driver level support for Faulhaber MCDC2805
*/
/*
* Original Author: Mark Rivers
* Date: 10/20/2005
*
* 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 10/20/05 mlr Initialize from ImsDrc/MDrive.cc
*/
/*
DESIGN LIMITATIONS...
1 - Like all controllers, the MCDC2805 must be powered-on when EPICS is first
booted up.
*/
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <iocsh.h>
#include <string.h>
#include <epicsThread.h>
#include <drvSup.h>
#include <errlog.h>
#include "motor.h"
#include "drvMCDC2805.h"
#include "asynOctetSyncIO.h"
#include "epicsExport.h"
#define MCDC2805_NUM_CARDS 8
#define BUFF_SIZE 100 /* Maximum length of string to/from MCDC2805 */
/*----------------debugging-----------------*/
volatile int drvMCDC2805debug = 0;
extern "C" {epicsExportAddress(int, drvMCDC2805debug);}
static inline void Debug(int level, const char *format, ...) {
#ifdef DEBUG
if (level < drvMCDC2805debug) {
va_list pVar;
va_start(pVar, format);
vprintf(format, pVar);
va_end(pVar);
}
#endif
}
/* --- Local data. --- */
int MCDC2805_num_cards = 0;
static char *MCDC2805_axis[] = {"0", "1", "2", "3", "4", "5", "6", "7"};
/* Local data required for every driver; see "motordrvComCode.h" */
#include "motordrvComCode.h"
/*----------------functions-----------------*/
static int recv_mess(int, char *, int);
static RTN_STATUS send_mess(int, char const *, char *);
static int set_status(int, int);
static long report(int);
static long init();
static int motor_init();
static void query_done(int, int, struct mess_node *);
/*----------------functions-----------------*/
struct driver_table MCDC2805_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,
MCDC2805_axis
};
struct drvMCDC2805_drvet
{
long number;
long (*report) (int);
long (*init) (void);
} drvMCDC2805 = {2, report, init};
extern "C" {epicsExportAddress(drvet, drvMCDC2805);}
static struct thread_args targs = {SCAN_RATE, &MCDC2805_access, 0.0};
/*********************************************************
* Print out driver status report
*********************************************************/
static long report(int level)
{
int card;
if (MCDC2805_num_cards <=0)
printf(" No MCDC2805 controllers configured.\n");
else
{
for (card = 0; card < MCDC2805_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
if (brdptr == NULL)
printf(" MCDC2805 controller %d connection failed.\n", card);
else
{
struct MCDC2805controller *cntrl;
cntrl = (struct MCDC2805controller *) brdptr->DevicePrivate;
printf(" MCDC2805SM controller #%d, port=%s, id: %s \n", card,
cntrl->asyn_port, brdptr->ident);
}
}
}
return(OK);
}
static long init()
{
/*
* We cannot call motor_init() here, because that function can do serial I/O,
* and hence requires that the serial port have already been initialized.
* That cannot be guaranteed, so we need to call motor_init from device
* support
*/
/* Check for setup */
if (MCDC2805_num_cards <= 0)
{
Debug(1, "init(): MCDC2805 driver disabled. MCDC2805Setup() missing from startup script.\n");
}
return((long) 0);
}
static void query_done(int card, int axis, struct mess_node *nodeptr)
{
}
/********************************************************************************
* *
* FUNCTION NAME: set_status *
* *
* LOGIC: *
* Initialize. *
* Send "Moving Status" query. *
* Read response. *
* IF normal response to query. *
* Set communication status to NORMAL. *
* ELSE *
* IF communication status is NORMAL. *
* Set communication status to RETRY. *
* NORMAL EXIT. *
* ELSE *
* Set communication status error. *
* ERROR EXIT. *
* ENDIF *
* ENDIF *
* *
* IF "Moving Status" indicates any motion (i.e. status != 0). *
* Clear "Done Moving" status bit. *
* ELSE *
* Set "Done Moving" status bit. *
* ENDIF *
* *
* *
********************************************************************************/
static int set_status(int card, int signal)
{
struct MCDC2805controller *cntrl;
struct mess_node *nodeptr;
register struct mess_info *motor_info;
/* Message parsing variables */
char buff[BUFF_SIZE];
char status_buff[BUFF_SIZE];
int rtnval, rtn_state;
double motorData;
epicsUInt8 Lswitch;
bool plusdir, ls_active = false;
msta_field status;
cntrl = (struct MCDC2805controller *) motor_state[card]->DevicePrivate;
motor_info = &(motor_state[card]->motor_info[signal]);
nodeptr = motor_info->motor_motion;
status.All = motor_info->status.All;
send_mess(card, "GST", MCDC2805_axis[signal]);
rtn_state = recv_mess(card, status_buff, 1);
if (rtn_state > 0)
{
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 0;
}
else
{
if (cntrl->status == NORMAL)
{
cntrl->status = RETRY;
rtn_state = OK;
goto exit;
}
else
{
cntrl->status = COMM_ERR;
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
}
rtnval = status_buff[4] == '1';
/* We can't use this logic for done, because it won't work in jog mode or when
* a move is stopped by setting velocity=0. */
/* status.Bits.RA_DONE = (rtnval == 0) ? 0 : 1; */
/*
* Parse motor position
* Position string format: 1TP5.012,2TP1.123,3TP-100.567,...
* Skip to substring for this motor, convert to double
*/
send_mess(card, "POS", MCDC2805_axis[signal]);
recv_mess(card, buff, 1);
motorData = atof(buff);
if (motorData == motor_info->position)
{
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
}
else
{
epicsInt32 newposition;
newposition = NINT(motorData);
status.Bits.RA_DIRECTION = (newposition >= motor_info->position) ? 1 : 0;
motor_info->position = newposition;
motor_info->no_motion_count = 0;
}
plusdir = (status.Bits.RA_DIRECTION) ? true : false;
send_mess(card, "GAST", MCDC2805_axis[signal]);
recv_mess(card, buff, 1);
Lswitch = buff[0] == '1';
/* Set limit Lswitch error indicators. */
if (Lswitch != 0)
{
status.Bits.RA_PLUS_LS = 1;
if (plusdir == true)
ls_active = true;
}
else
status.Bits.RA_PLUS_LS = 0;
Lswitch = buff[1] == '1';
if (Lswitch != 0)
{
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
}
else
status.Bits.RA_MINUS_LS = 0;
/* If there is an active limit switch (i.e. one that stopped motion) then
* we need to do an absolute move to the current position.
* If this is not done then as soon as the limit switch is released the motor will
* start moving, which is not good.
*/
if (ls_active) {
sprintf(buff, "LA %ld", NINT(motorData));
send_mess(card, buff, MCDC2805_axis[signal]);
send_mess(card, "M", MCDC2805_axis[signal]);
}
Lswitch = status_buff[6] == '1';
status.Bits.RA_HOME = (Lswitch) ? 1 : 0;
/* !!! Assume no closed-looped control!!!*/
status.Bits.EA_POSITION = 0;
/* encoder status */
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP_STALL = 0;
status.Bits.EA_HOME = 0;
if (motor_state[card]->motor_info[signal].encoder_present == NO)
motor_info->encoder_position = 0;
else
{
motor_info->encoder_position = (int) motorData;
}
status.Bits.RA_PROBLEM = 0;
/* Read the actual velocity. Use this to set the DONE bit.
* This is needed because the "reached command position bit in GST does
* not work for jog commands or when move is stopped by setting velocity=0 */
send_mess(card, "GV", MCDC2805_axis[signal]);
recv_mess(card, buff, 1);
motor_info->velocity = NINT(atof(buff));
status.Bits.RA_DONE = (motor_info->velocity == 0) ? 1 : 0;
if (!status.Bits.RA_DIRECTION)
motor_info->velocity *= -1;
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)
{
strcpy(buff, nodeptr->postmsgptr);
send_mess(card, buff, MCDC2805_axis[signal]);
nodeptr->postmsgptr = NULL;
}
exit:
motor_info->status.All = status.All;
return(rtn_state);
}
/*****************************************************/
/* send a message to the MCDC2805 board */
/* send_mess() */
/*****************************************************/
static RTN_STATUS send_mess(int card, char const *com, char *name)
{
char local_buff[MAX_MSG_SIZE];
struct MCDC2805controller *cntrl;
int comsize, namesize;
size_t nwrite;
comsize = (com == NULL) ? 0 : strlen(com);
namesize = (name == NULL) ? 0 : strlen(name);
if ((comsize + namesize) > MAX_MSG_SIZE)
{
errlogMessage("drvMCDC2805.c:send_mess(); message size violation.\n");
return(ERROR);
}
else if (comsize == 0) /* Normal exit on empty input message. */
return(OK);
if (!motor_state[card])
{
errlogPrintf("drvMCDC2805.c:send_mess() - invalid card #%d\n", card);
return(ERROR);
}
/* Make a local copy of the string and add the command line terminator. */
if (namesize != 0)
{
strcpy(local_buff, name); /* put in axis */
strcat(local_buff, com);
}
else
strcpy(local_buff, com);
Debug(2, "send_mess(): message = %s\n", local_buff);
cntrl = (struct MCDC2805controller *) motor_state[card]->DevicePrivate;
pasynOctetSyncIO->write(cntrl->pasynUser, local_buff, strlen(local_buff),
COMM_TIMEOUT, &nwrite);
return(OK);
}
/*****************************************************/
/* receive a message from the MCDC2805 board */
/* recv_mess() */
/*****************************************************/
static int recv_mess(int card, char *com, int flag)
{
struct MCDC2805controller *cntrl;
const double timeout = 1.0;
size_t nread = 0;
asynStatus status = asynError;
int eomReason;
/* Check that card exists */
if (!motor_state[card])
return(ERROR);
cntrl = (struct MCDC2805controller *) motor_state[card]->DevicePrivate;
if (flag == FLUSH)
pasynOctetSyncIO->flush(cntrl->pasynUser);
else
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 */
/* MCDC2805Setup() */
/*****************************************************/
RTN_STATUS
MCDC2805Setup(int num_cards, /* maximum number of chains in system. */
int scan_rate) /* polling rate - 1/60 sec units. */
{
int itera;
if (num_cards < 1 || num_cards > MCDC2805_NUM_CARDS)
MCDC2805_num_cards = MCDC2805_NUM_CARDS;
else
MCDC2805_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 MCDC2805Config 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(MCDC2805_num_cards *
sizeof(struct controller *));
for (itera = 0; itera < MCDC2805_num_cards; itera++)
motor_state[itera] = (struct controller *) NULL;
return(OK);
}
/*****************************************************/
/* Configure a controller */
/* MCDC2805Config() */
/*****************************************************/
RTN_STATUS
MCDC2805Config(int card, /* chain being configured */
int num_motors, /* Number of MCDC-2805 units on this serial port */
const char *name) /* ASYN port name */
{
struct MCDC2805controller *cntrl;
if (card < 0 || card >= MCDC2805_num_cards)
return(ERROR);
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
motor_state[card]->DevicePrivate = malloc(sizeof(struct MCDC2805controller));
cntrl = (struct MCDC2805controller *) motor_state[card]->DevicePrivate;
cntrl->num_motors = num_motors;
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 MCDC2805controller *cntrl;
int card_index, motor_index;
char buff[BUFF_SIZE];
int total_axis = 0;
int status;
asynStatus success_rtn;
initialized = true; /* Indicate that driver is initialized. */
/* Check for setup */
if (MCDC2805_num_cards <= 0)
return(ERROR);
for (card_index = 0; card_index < MCDC2805_num_cards; card_index++)
{
if (!motor_state[card_index])
continue;
brdptr = motor_state[card_index];
brdptr->ident[0] = (char) NULL; /* No controller identification message. */
brdptr->cmnd_response = false;
total_cards = card_index + 1;
cntrl = (struct MCDC2805controller *) brdptr->DevicePrivate;
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port, 0,
&cntrl->pasynUser, NULL);
if (success_rtn == asynSuccess)
{
/* Send a message to the board, see if it exists */
/* flush any junk at input port - should not be any data available */
pasynOctetSyncIO->flush(cntrl->pasynUser);
for (total_axis = 0; total_axis < cntrl->num_motors; total_axis++)
{
int retry = 0;
/* Try 3 times to connect to controller. */
do
{
send_mess(card_index, "VER", MCDC2805_axis[total_axis]);
status = recv_mess(card_index, buff, 1);
retry++;
} while (status == 0 && retry < 3);
if (status <= 0)
break;
else if (total_axis == 0)
strcpy(brdptr->ident, buff);
}
brdptr->total_axis = total_axis;
}
if (success_rtn == asynSuccess && total_axis > 0)
{
brdptr->localaddr = (char *) NULL;
brdptr->motor_in_motion = 0;
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;
brdptr->motor_info[motor_index].motor_motion = NULL;
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
motor_info->encoder_present = YES;
motor_info->status.Bits.EA_PRESENT = 1;
/* Set the velocity control to be RS-232 */
send_mess(card_index, "SOR 0", MCDC2805_axis[motor_index]);
/* Set the limit switch configuration. */
/* We assume the following:
* Analog input = Input 1 = Home input = 1 bit
* Fault pin = Input 2 = CW limit = 2 bit
* Input 3 Input 3 = CCW limit = 4 bit
*/
/* Program fault pin as limit switch input */
send_mess(card_index, "REFIN", MCDC2805_axis[motor_index]);
/* Program limit polarity for rising edge and high level */
send_mess(card_index, "HP7", MCDC2805_axis[motor_index]);
/* Program the motor to hard block on the the limit switch inputs */
send_mess(card_index, "HB6", MCDC2805_axis[motor_index]);
/* Program the limit switch directions to block
* + direction on input 2, - direction on input 3 */
send_mess(card_index, "HD2", MCDC2805_axis[motor_index]);
/* Program homing sequence on input 1*/
send_mess(card_index, "HL1", MCDC2805_axis[motor_index]);
send_mess(card_index, "HA1", MCDC2805_axis[motor_index]);
send_mess(card_index, "CAHOSEQ", MCDC2805_axis[motor_index]);
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 *) "MCDC2805_motor", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
return(OK);
}
extern "C"
{
// Faulhaber Setup arguments
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
static const iocshArg setupArg1 = {"Polling rate", iocshArgInt};
// Faulhaber Config arguments
static const iocshArg configArg0 = {"Card being configured", iocshArgInt};
static const iocshArg configArg1 = {"# modules on this serial port", iocshArgInt};
static const iocshArg configArg2 = {"asyn port name", iocshArgString};
static const iocshArg * const setupArgs[2] = {&setupArg0,
&setupArg1};
static const iocshArg * const configArgs[3] = {&configArg0,
&configArg1,
&configArg2};
static const iocshFuncDef setupMCDC2805 = {"MCDC2805Setup", 2, setupArgs};
static const iocshFuncDef configMCDC2805 = {"MCDC2805Config", 3, configArgs};
static void setupMCDC2805CallFunc(const iocshArgBuf *args)
{
MCDC2805Setup(args[0].ival, args[1].ival);
}
static void configMCDC2805CallFunc(const iocshArgBuf *args)
{
MCDC2805Config(args[0].ival, args[1].ival, args[2].sval);
}
static void MCDC2805Register(void)
{
iocshRegister(&setupMCDC2805, setupMCDC2805CallFunc);
iocshRegister(&configMCDC2805, configMCDC2805CallFunc);
}
epicsExportRegistrar(MCDC2805Register);
} // extern "C"
-62
View File
@@ -1,62 +0,0 @@
/*
FILENAME... drvMCDC2805.h
USAGE... This file contains driver "include" information for the Faulhaber MCDC 2805 controller.
*/
/*
* Original Author: Mark Rivers
* Date: 10/20/2005
*
* 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 10/20/2005 mlr Converted from MDrive.h
*/
#ifndef INCdrvMCDC2805h
#define INCdrvMCDC2805h 1
#include "motordrvCom.h"
#include "asynDriver.h"
#include "asynOctetSyncIO.h"
#define COMM_TIMEOUT 2 /* Timeout in seconds */
/* MCDC-2805 specific data is stored in this structure. */
struct MCDC2805controller
{
asynUser *pasynUser; /* For RS-232 */
char asyn_port[80]; /* asyn port name */
int num_motors; /* Number of MCDC-2805 modules on this serial port */
CommStatus status; /* Controller communication status. */
};
/* Function prototypes. */
extern RTN_STATUS MCDC2805Config(int, const char *);
extern RTN_STATUS MCDC2805Config(int, const char *);
#endif /* INCdrvMCDC2805h */
-3
View File
@@ -42,9 +42,6 @@ MicroMoSrc_DEPEND_DIRS = MotorSrc
DIRS += MicosSrc
MicosSrc_DEPEND_DIRS = MotorSrc
DIRS += FaulhaberSrc
FaulhaberSrc_DEPEND_DIRS = MotorSrc
DIRS += PC6KSrc
PC6KSrc_DEPEND_DIRS = MotorSrc