Corrected compiler error when passing Asyn parameter(s).

This commit is contained in:
David Kline
2005-04-14 18:52:48 +00:00
parent 94b50f4f38
commit ce49cec901
9 changed files with 2075 additions and 2095 deletions
+211 -218
View File
@@ -1,11 +1,11 @@
/*
FILENAME... drvIM483PL.cc
USAGE... Motor record driver level support for Intelligent Motion
Systems, Inc. IM483(I/IE).
FILENAME... drvIM483PL.cc
USAGE... Motor record driver level support for Intelligent Motion
Systems, Inc. IM483(I/IE).
Version: $Revision: 1.13 $
Modified By: $Author: sluiter $
Last Modified: $Date: 2005-03-30 19:01:27 $
Version: $Revision: 1.14 $
Modified By: $Author: dkline $
Last Modified: $Date: 2005-04-14 18:51:51 $
*/
/*****************************************************************
@@ -28,9 +28,9 @@ of this distribution.
* .01 07/10/00 rls copied from drvIM483SM.c
* .02 10/02/01 rls allow one retry after a communication error.
* .03 04/15/02 rls Bug fix for limit switches. Set RA_DIRECTION in
* set_status() based on (new - old) commanded position.
* Removed support for "ASCII record separator (IS2) = /x1E"
* from send_mess().
* set_status() based on (new - old) commanded position.
* Removed support for "ASCII record separator (IS2) = /x1E"
* from send_mess().
* .04 03/07/03 rls R3.14 conversion.
* .05 02/03/04 rls Eliminate erroneous "Motor motion timeout ERROR".
* .06 07/01/04 rls Converted from MPF to asyn.
@@ -38,22 +38,22 @@ of this distribution.
* - support for 32axes/controller.
* - remove '?' command line padding.
* .08 12/14/04 rls - asyn R4.0 support.
* - make debug variables always available.
* - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
* - retry on initial communication.
* - make debug variables always available.
* - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
* - retry on initial communication.
*/
/*
DESIGN LIMITATIONS...
1 - Like all controllers, the IM483 must be powered-on when EPICS is first
booted up.
booted up.
2 - The IM483 cannot be power cycled while EPICS is up and running. The
consequences are permanent communication lose with the IM483 until
EPICS is rebooted.
consequences are permanent communication lose with the IM483 until
EPICS is rebooted.
3 - Like the Newport MM3000, the IM483's position can only be set to zero.
4 - The IM483 uses an internal look-up table for acceleration/deceleration.
Translation between the IM483 and the ACCL/BACC fields is not obvious.
Translation between the IM483 and the ACCL/BACC fields is not obvious.
*/
#include <string.h>
@@ -65,22 +65,22 @@ DESIGN LIMITATIONS...
#include "epicsExport.h"
/* Read Limit Status response values. */
#define L_ALIMIT 1
#define L_BLIMIT 2
#define L_BOTH_LIMITS 3
#define L_ALIMIT 1
#define L_BLIMIT 2
#define L_BOTH_LIMITS 3
#define IM483PL_NUM_CARDS 8
#define MAX_AXES 8
#define BUFF_SIZE 50 /* Maximum length of string to/from IM483PL */
#define IM483PL_NUM_CARDS 8
#define MAX_AXES 8
#define BUFF_SIZE 50 /* Maximum length of string to/from IM483PL */
/*----------------debugging-----------------*/
#ifdef __GNUG__
#ifdef DEBUG
#define Debug(l, f, args...) {if (l <= drvIM483PLdebug) printf(f, ## args);}
#ifdef DEBUG
#define Debug(l, f, args...) {if (l <= drvIM483PLdebug) printf(f, ## args);}
#else
#define Debug(l, f, args...)
#define Debug(l, f, args...)
#endif
#else
#define Debug()
@@ -93,7 +93,7 @@ int IM483PL_num_cards = 0;
static char *IM483PL_axis[] = {"A", "B", "C", "D", "E", "F", "G", "H"};
/* Local data required for every driver; see "motordrvComCode.h" */
#include "motordrvComCode.h"
#include "motordrvComCode.h"
/*----------------functions-----------------*/
static int recv_mess(int, char *, int);
@@ -149,24 +149,24 @@ static long report(int level)
int card;
if (IM483PL_num_cards <=0)
printf(" No IM483PL controllers configured.\n");
printf(" No IM483PL controllers configured.\n");
else
{
for (card = 0; card < IM483PL_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
for (card = 0; card < IM483PL_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
if (brdptr == NULL)
printf(" IM483PL controller %d connection failed.\n", card);
else
{
struct IM483controller *cntrl;
if (brdptr == NULL)
printf(" IM483PL controller %d connection failed.\n", card);
else
{
struct IM483controller *cntrl;
cntrl = (struct IM483controller *) brdptr->DevicePrivate;
printf(" IM483PL controller #%d, port=%s, id: %s \n", card,
cntrl->asyn_port, brdptr->ident);
}
}
cntrl = (struct IM483controller *) brdptr->DevicePrivate;
printf(" IM483PL controller #%d, port=%s, id: %s \n", card,
cntrl->asyn_port, brdptr->ident);
}
}
}
return(OK);
}
@@ -174,7 +174,7 @@ static long report(int level)
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
@@ -183,7 +183,7 @@ static long init()
/* Check for setup */
if (IM483PL_num_cards <= 0)
{
Debug(1, "init(): IM483PL driver disabled. IM483PLSetup() missing from startup script.\n");
Debug(1, "init(): IM483PL driver disabled. IM483PLSetup() missing from startup script.\n");
}
return((long) 0);
}
@@ -195,32 +195,32 @@ 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 *
* *
* *
* *
* 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)
@@ -244,32 +244,32 @@ static int set_status(int card, int signal)
rtn_state = recv_mess(card, buff, 1);
if (rtn_state > 0)
{
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 0;
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 0;
}
else
{
if (cntrl->status == NORMAL)
{
cntrl->status = RETRY;
rtn_state = 0;
goto exit;
}
else
{
cntrl->status = COMM_ERR;
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
if (cntrl->status == NORMAL)
{
cntrl->status = RETRY;
rtn_state = 0;
goto exit;
}
else
{
cntrl->status = COMM_ERR;
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
}
rtnval = atoi(&buff[4]);
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
@@ -282,17 +282,17 @@ static int set_status(int card, int signal)
if (motorData == motor_info->position)
{
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
}
else
{
epicsInt32 newposition;
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;
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;
@@ -304,21 +304,21 @@ static int set_status(int card, int signal)
/* Set limit switch error indicators. */
if (rtnval & 1)
{
status.Bits.RA_PLUS_LS = 1;
if (plusdir == true)
ls_active = true;
status.Bits.RA_PLUS_LS = 1;
if (plusdir == true)
ls_active = true;
}
else
status.Bits.RA_PLUS_LS = 0;
status.Bits.RA_PLUS_LS = 0;
if (rtnval & 2)
{
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
}
else
status.Bits.RA_MINUS_LS = 0;
status.Bits.RA_MINUS_LS = 0;
send_mess(card, " ] 1", IM483PL_axis[signal]);
recv_mess(card, buff, 1);
@@ -330,21 +330,21 @@ static int set_status(int card, int signal)
status.Bits.EA_POSITION = 0;
/* encoder status */
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP_STALL = 0;
status.Bits.EA_HOME = 0;
status.Bits.EA_HOME = 0;
if (motor_state[card]->motor_info[signal].encoder_present == NO)
motor_info->encoder_position = 0;
motor_info->encoder_position = 0;
else
{
send_mess(card, " z 0", IM483PL_axis[signal]);
recv_mess(card, buff, 1);
motorData = atof(&buff[5]);
motor_info->encoder_position = (int32_t) motorData;
send_mess(card, " z 0", IM483PL_axis[signal]);
recv_mess(card, buff, 1);
motorData = atof(&buff[5]);
motor_info->encoder_position = (int32_t) motorData;
}
status.Bits.RA_PROBLEM = 0;
status.Bits.RA_PROBLEM = 0;
/* Parse motor velocity? */
/* NEEDS WORK */
@@ -352,18 +352,17 @@ static int set_status(int card, int signal)
motor_info->velocity = 0;
if (!status.Bits.RA_DIRECTION)
motor_info->velocity *= -1;
motor_info->velocity *= -1;
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
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)
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 && nodeptr->postmsgptr != 0)
{
strcpy(buff, nodeptr->postmsgptr);
send_mess(card, buff, IM483PL_axis[signal]);
nodeptr->postmsgptr = NULL;
strcpy(buff, nodeptr->postmsgptr);
send_mess(card, buff, IM483PL_axis[signal]);
nodeptr->postmsgptr = NULL;
}
exit:
@@ -373,47 +372,46 @@ exit:
/*****************************************************/
/* send a message to the IM483PL board */
/* send_mess() */
/* send a message to the IM483PL board */
/* send_mess() */
/*****************************************************/
static RTN_STATUS send_mess(int card, char const *com, char *name)
{
char local_buff[MAX_MSG_SIZE];
struct IM483controller *cntrl;
int comsize, namesize;
int nwrite;
size_t nwrite;
comsize = (com == NULL) ? 0 : strlen(com);
namesize = (name == NULL) ? 0 : strlen(name);
if ((comsize + namesize) > MAX_MSG_SIZE)
{
errlogMessage("drvIM483PL.c:send_mess(); message size violation.\n");
return(ERROR);
errlogMessage("drvIM483PL.c:send_mess(); message size violation.\n");
return(ERROR);
}
else if (comsize == 0) /* Normal exit on empty input message. */
return(OK);
else if (comsize == 0) /* Normal exit on empty input message. */
return(OK);
if (!motor_state[card])
{
errlogPrintf("drvIM483PL.c:send_mess() - invalid card #%d\n", card);
return(ERROR);
errlogPrintf("drvIM483PL.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);
strcpy(local_buff, name); /* put in axis */
strcat(local_buff, com);
}
else
strcpy(local_buff, com);
strcpy(local_buff, com);
Debug(2, "send_mess(): message = %s\n", local_buff);
cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate;
pasynOctetSyncIO->write(cntrl->pasynUser, local_buff, strlen(local_buff),
COMM_TIMEOUT, &nwrite);
pasynOctetSyncIO->write(cntrl->pasynUser, local_buff, strlen(local_buff), COMM_TIMEOUT, &nwrite);
return(OK);
}
@@ -421,31 +419,30 @@ static RTN_STATUS send_mess(int card, char const *com, char *name)
/*****************************************************/
/* receive a message from the IM483 board */
/* recv_mess() */
/* recv_mess() */
/*****************************************************/
static int recv_mess(int card, char *com, int flag)
{
struct IM483controller *cntrl;
int nread = 0;
size_t nread = 0;
asynStatus status = asynError;
int eomReason;
/* Check that card exists */
if (!motor_state[card])
return(ERROR);
return(ERROR);
cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate;
if (flag == FLUSH)
pasynOctetSyncIO->flush(cntrl->pasynUser);
pasynOctetSyncIO->flush(cntrl->pasynUser);
else
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
COMM_TIMEOUT, &nread, &eomReason);
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE, COMM_TIMEOUT, &nread, &eomReason);
if ((status != asynSuccess) || (nread <= 0))
{
com[0] = '\0';
nread = 0;
com[0] = '\0';
nread = 0;
}
Debug(2, "recv_mess(): message = \"%s\"\n", com);
@@ -458,33 +455,32 @@ static int recv_mess(int card, char *com, int flag)
/* IM483PLSetup() */
/*****************************************************/
RTN_STATUS
IM483PLSetup(int num_cards, /* maximum number of controllers in system. */
int scan_rate) /* polling rate - 1/60 sec units. */
IM483PLSetup(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 > IM483PL_NUM_CARDS)
IM483PL_num_cards = IM483PL_NUM_CARDS;
IM483PL_num_cards = IM483PL_NUM_CARDS;
else
IM483PL_num_cards = num_cards;
IM483PL_num_cards = num_cards;
/* Set motor polling task rate */
if (scan_rate >= 1 && scan_rate <= 60)
targs.motor_scan_rate = scan_rate;
targs.motor_scan_rate = scan_rate;
else
targs.motor_scan_rate = SCAN_RATE;
targs.motor_scan_rate = SCAN_RATE;
/*
/*
* Allocate space for motor_state structures. Note this must be done
* before IM483Config 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(IM483PL_num_cards *
sizeof(struct controller *));
motor_state = (struct controller **) malloc(IM483PL_num_cards * sizeof(struct controller *));
for (itera = 0; itera < IM483PL_num_cards; itera++)
motor_state[itera] = (struct controller *) NULL;
motor_state[itera] = (struct controller *) NULL;
return(OK);
}
@@ -495,8 +491,8 @@ IM483PLSetup(int num_cards, /* maximum number of controllers in system. */
/* IM483PLConfig() */
/*****************************************************/
RTN_STATUS
IM483PLConfig(int card, /* card being configured */
const char *name) /* asyn server task name */
IM483PLConfig(int card, /* card being configured */
const char *name) /* asyn server task name */
{
struct IM483controller *cntrl;
@@ -513,10 +509,10 @@ IM483PLConfig(int card, /* card being configured */
/*****************************************************/
/* initialize all software and hardware */
/* initialize all software and hardware */
/* This is called from the initialization routine in */
/* device support. */
/* motor_init() */
/* motor_init() */
/*****************************************************/
static int motor_init()
{
@@ -530,86 +526,83 @@ static int motor_init()
static const char output_terminator[] = "\n";
static const char input_terminator[] = "\n";
initialized = true; /* Indicate that driver is initialized. */
initialized = true; /* Indicate that driver is initialized. */
/* Check for setup */
if (IM483PL_num_cards <= 0)
return(ERROR);
return(ERROR);
for (card_index = 0; card_index < IM483PL_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 = true;
total_cards = card_index + 1;
cntrl = (struct IM483controller *) brdptr->DevicePrivate;
if (!motor_state[card_index])
continue;
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port, 0,
&cntrl->pasynUser, NULL);
brdptr = motor_state[card_index];
brdptr->ident[0] = (char) NULL; /* No controller identification message. */
brdptr->cmnd_response = true;
total_cards = card_index + 1;
cntrl = (struct IM483controller *) brdptr->DevicePrivate;
if (success_rtn == asynSuccess)
{
pasynOctetSyncIO->setOutputEos(cntrl->pasynUser, output_terminator,
strlen(output_terminator));
pasynOctetSyncIO->setInputEos(cntrl->pasynUser, input_terminator,
strlen(input_terminator));
/* Send a message to the board, see if it exists */
/* flush any junk at input port - should not be any data available */
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port, 0, &cntrl->pasynUser, NULL);
if (success_rtn == asynSuccess)
{
pasynOctetSyncIO->setOutputEos(cntrl->pasynUser, output_terminator, strlen(output_terminator));
pasynOctetSyncIO->setInputEos(cntrl->pasynUser, input_terminator, strlen(input_terminator));
/* 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 < MAX_AXES; total_axis++)
{
int retry = 0;
do
{
send_mess(card_index, " Z 0", IM483PL_axis[total_axis]);
status = recv_mess(card_index, buff, 1);
retry++;
} while (status <= 0 && retry < 3);
for (total_axis = 0; total_axis < MAX_AXES; total_axis++)
{
int retry = 0;
if (status <= 0)
break;
}
brdptr->total_axis = total_axis;
}
do
{
send_mess(card_index, " Z 0", IM483PL_axis[total_axis]);
status = recv_mess(card_index, buff, 1);
retry++;
} while (status <= 0 && retry < 3);
if (success_rtn == asynSuccess && total_axis > 0)
{
brdptr->localaddr = (char *) NULL;
brdptr->motor_in_motion = 0;
if (status <= 0)
break;
}
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];
int loop_state;
if (success_rtn == asynSuccess && total_axis > 0)
{
brdptr->localaddr = (char *) NULL;
brdptr->motor_in_motion = 0;
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;
/* Assume encoder support, i.e., IM483IE. */
motor_info->encoder_present = YES;
motor_info->status.Bits.EA_PRESENT = 1;
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
int loop_state;
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;
/* Assume encoder support, i.e., IM483IE. */
motor_info->encoder_present = YES;
motor_info->status.Bits.EA_PRESENT = 1;
/* Determine if encoder present based on open/closed loop mode. */
loop_state = 0;
if (loop_state != 0)
{
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
}
loop_state = 0;
if (loop_state != 0)
{
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
}
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
}
any_motor_in_motion = 0;
@@ -621,9 +614,9 @@ static int motor_init()
free_list.tail = (struct mess_node *) NULL;
epicsThreadCreate((char *) "IM483PL_motor", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
return(OK);
}
+243 -250
View File
@@ -1,13 +1,13 @@
/*
FILENAME... drvIM483SM.cc
USAGE... Motor record driver level support for Intelligent Motion
Systems, Inc. IM483(I/IE).
FILENAME... drvIM483SM.cc
USAGE... Motor record driver level support for Intelligent Motion
Systems, Inc. IM483(I/IE).
Version: $Revision: 1.14 $
Modified By: $Author: sluiter $
Last Modified: $Date: 2005-03-30 19:01:27 $
Version: $Revision: 1.15 $
Modified By: $Author: dkline $
Last Modified: $Date: 2005-04-14 18:51:52 $
*/
/*****************************************************************
COPYRIGHT NOTIFICATION
*****************************************************************
@@ -28,30 +28,30 @@ of this distribution.
* .01 02/10/00 rls copied from drvMM4000.c
* .02 10/02/01 rls allow one retry after a communication error.
* .03 04/15/02 rls Bug fix for limit switches. Set RA_DIRECTION in
* set_status() based on (new - old) commanded position.
* Removed support for "ASCII record separator (IS2) = /x1E"
* from send_mess().
* set_status() based on (new - old) commanded position.
* Removed support for "ASCII record separator (IS2) = /x1E"
* from send_mess().
* .04 03/07/03 rls R3.14 conversion.
* .05 02/03/04 rls Eliminate erroneous "Motor motion timeout ERROR".
* .06 07/01/04 rls Converted from MPF to asyn.
* .07 09/20/04 rls support for 32axes/controller.
* .08 12/14/04 rls - asyn R4.0 support.
* - make debug variables always available.
* - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
* - retry on initial communication.
* - make debug variables always available.
* - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
* - retry on initial communication.
*/
/*
DESIGN LIMITATIONS...
1 - Like all controllers, the IM483 must be powered-on when EPICS is first
booted up.
booted up.
2 - The IM483 cannot be power cycled while EPICS is up and running. The
consequences are permanent communication lose with the IM483 until
EPICS is rebooted.
consequences are permanent communication lose with the IM483 until
EPICS is rebooted.
3 - Like the Newport MM3000, the IM483's position can only be set to zero.
4 - The IM483 uses an internal look-up table for acceleration/deceleration.
Translation between the IM483 and the ACCL/BACC fields is not obvious.
Translation between the IM483 and the ACCL/BACC fields is not obvious.
*/
#include <string.h>
@@ -64,20 +64,20 @@ DESIGN LIMITATIONS...
#include "epicsExport.h"
/* Read Limit Status response values. */
#define L_ALIMIT 1
#define L_BLIMIT 2
#define L_BOTH_LIMITS 3
#define L_ALIMIT 1
#define L_BLIMIT 2
#define L_BOTH_LIMITS 3
#define IM483SM_NUM_CARDS 8
#define IM483SM_NUM_CARDS 8
#define BUFF_SIZE 50 /* Maximum length of string to/from IM483 */
/*----------------debugging-----------------*/
#ifdef __GNUG__
#ifdef DEBUG
#define Debug(l, f, args...) {if (l <= drvIM483SMdebug) printf(f, ## args);}
#ifdef DEBUG
#define Debug(l, f, args...) {if (l <= drvIM483SMdebug) printf(f, ## args);}
#else
#define Debug(l, f, args...)
#define Debug(l, f, args...)
#endif
#else
#define Debug()
@@ -89,7 +89,7 @@ extern "C" {epicsExportAddress(int, drvIM483SMdebug);}
int IM483SM_num_cards = 0;
/* Local data required for every driver; see "motordrvComCode.h" */
#include "motordrvComCode.h"
#include "motordrvComCode.h"
/*----------------functions-----------------*/
static int recv_mess(int, char *, int);
@@ -146,24 +146,24 @@ static long report(int level)
int card;
if (IM483SM_num_cards <=0)
printf(" No IM483SM controllers configured.\n");
printf(" No IM483SM controllers configured.\n");
else
{
for (card = 0; card < IM483SM_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
for (card = 0; card < IM483SM_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
if (brdptr == NULL)
printf(" IM483SM controller %d connection failed.\n", card);
else
{
struct IM483controller *cntrl;
if (brdptr == NULL)
printf(" IM483SM controller %d connection failed.\n", card);
else
{
struct IM483controller *cntrl;
cntrl = (struct IM483controller *) brdptr->DevicePrivate;
printf(" IM483SM controller #%d, port=%s, id: %s \n", card,
cntrl->asyn_port, brdptr->ident);
}
}
cntrl = (struct IM483controller *) brdptr->DevicePrivate;
printf(" IM483SM controller #%d, port=%s, id: %s \n", card,
cntrl->asyn_port, brdptr->ident);
}
}
}
return(OK);
}
@@ -171,7 +171,7 @@ static long report(int level)
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
@@ -180,7 +180,7 @@ static long init()
/* Check for setup */
if (IM483SM_num_cards <= 0)
{
Debug(1, "init(): IM483SM driver disabled. IM483SMSetup() missing from startup script.\n");
Debug(1, "init(): IM483SM driver disabled. IM483SMSetup() missing from startup script.\n");
}
return((long) 0);
}
@@ -192,32 +192,32 @@ 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 *
* *
* *
* *
* 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)
@@ -241,32 +241,32 @@ static int set_status(int card, int signal)
rtn_state = recv_mess(card, buff, 1);
if (rtn_state > 0)
{
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 0;
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 0;
}
else
{
if (cntrl->status == NORMAL)
{
cntrl->status = RETRY;
rtn_state = 0;
goto exit;
}
else
{
cntrl->status = COMM_ERR;
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
if (cntrl->status == NORMAL)
{
cntrl->status = RETRY;
rtn_state = 0;
goto exit;
}
else
{
cntrl->status = COMM_ERR;
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
}
rtnval = atoi(&buff[4]);
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
@@ -279,17 +279,17 @@ static int set_status(int card, int signal)
if (motorData == motor_info->position)
{
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
}
else
{
epicsInt32 newposition;
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;
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;
@@ -301,21 +301,21 @@ static int set_status(int card, int signal)
/* Set limit switch error indicators. */
if (rtnval & 1)
{
status.Bits.RA_PLUS_LS = 1;
if (plusdir == true)
ls_active = true;
status.Bits.RA_PLUS_LS = 1;
if (plusdir == true)
ls_active = true;
}
else
status.Bits.RA_PLUS_LS = 0;
status.Bits.RA_PLUS_LS = 0;
if (rtnval & 2)
{
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
}
else
status.Bits.RA_MINUS_LS = 0;
status.Bits.RA_MINUS_LS = 0;
send_mess(card, "] 1", (char) NULL);
recv_mess(card, buff, 1);
@@ -327,21 +327,21 @@ static int set_status(int card, int signal)
status.Bits.EA_POSITION = 0;
/* encoder status */
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP_STALL = 0;
status.Bits.EA_HOME = 0;
status.Bits.EA_HOME = 0;
if (motor_state[card]->motor_info[signal].encoder_present == NO)
motor_info->encoder_position = 0;
motor_info->encoder_position = 0;
else
{
send_mess(card, "z 0", (char) NULL);
recv_mess(card, buff, 1);
motorData = atof(&buff[5]);
motor_info->encoder_position = (int32_t) motorData;
send_mess(card, "z 0", (char) NULL);
recv_mess(card, buff, 1);
motorData = atof(&buff[5]);
motor_info->encoder_position = (int32_t) motorData;
}
status.Bits.RA_PROBLEM = 0;
status.Bits.RA_PROBLEM = 0;
/* Parse motor velocity? */
/* NEEDS WORK */
@@ -349,18 +349,17 @@ static int set_status(int card, int signal)
motor_info->velocity = 0;
if (!status.Bits.RA_DIRECTION)
motor_info->velocity *= -1;
motor_info->velocity *= -1;
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
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)
nodeptr->postmsgptr != 0)
{
strcpy(buff, nodeptr->postmsgptr);
send_mess(card, buff, (char) NULL);
nodeptr->postmsgptr = NULL;
strcpy(buff, nodeptr->postmsgptr);
send_mess(card, buff, (char) NULL);
nodeptr->postmsgptr = NULL;
}
exit:
@@ -370,42 +369,41 @@ exit:
/*****************************************************/
/* send a message to the IM483SM board */
/* send_mess() */
/* send a message to the IM483SM board */
/* send_mess() */
/*****************************************************/
static RTN_STATUS send_mess(int card, char const *com, char *name)
{
struct IM483controller *cntrl;
int size;
int nwrite;
size_t nwrite;
size = strlen(com);
if (size > MAX_MSG_SIZE)
{
errlogMessage("drvIM483SM.c:send_mess(); message size violation.\n");
return(ERROR);
errlogMessage("drvIM483SM.c:send_mess(); message size violation.\n");
return(ERROR);
}
else if (size == 0) /* Normal exit on empty input message. */
return(OK);
else if (size == 0) /* Normal exit on empty input message. */
return(OK);
if (!motor_state[card])
{
errlogPrintf("drvIM483SM.c:send_mess() - invalid card #%d\n", card);
return(ERROR);
errlogPrintf("drvIM483SM.c:send_mess() - invalid card #%d\n", card);
return(ERROR);
}
if (name != NULL)
{
errlogPrintf("drvIM483SM.c:send_mess() - invalid argument = %s\n", name);
return(ERROR);
errlogPrintf("drvIM483SM.c:send_mess() - invalid argument = %s\n", name);
return(ERROR);
}
Debug(2, "send_mess(): message = %s\n", com);
cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate;
pasynOctetSyncIO->write(cntrl->pasynUser, com, size, COMM_TIMEOUT,
&nwrite);
pasynOctetSyncIO->write(cntrl->pasynUser, com, size, COMM_TIMEOUT, &nwrite);
return(OK);
}
@@ -413,31 +411,30 @@ static RTN_STATUS send_mess(int card, char const *com, char *name)
/*****************************************************/
/* receive a message from the IM483 board */
/* recv_mess() */
/* recv_mess() */
/*****************************************************/
static int recv_mess(int card, char *com, int flag)
{
struct IM483controller *cntrl;
int nread = 0;
size_t nread = 0;
asynStatus status = asynError;
int eomReason;
/* Check that card exists */
if (!motor_state[card])
return(ERROR);
return(ERROR);
cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate;
if (flag == FLUSH)
pasynOctetSyncIO->flush(cntrl->pasynUser);
pasynOctetSyncIO->flush(cntrl->pasynUser);
else
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
COMM_TIMEOUT, &nread, &eomReason);
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE, COMM_TIMEOUT, &nread, &eomReason);
if ((status != asynSuccess) || (nread <= 0))
{
com[0] = '\0';
nread = 0;
com[0] = '\0';
nread = 0;
}
Debug(2, "recv_mess(): message = \"%s\"\n", com);
@@ -450,33 +447,32 @@ static int recv_mess(int card, char *com, int flag)
/* IM483SMSetup() */
/*****************************************************/
RTN_STATUS
IM483SMSetup(int num_cards, /* maximum number of controllers in system. */
int scan_rate) /* polling rate - 1/60 sec units. */
IM483SMSetup(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 > IM483SM_NUM_CARDS)
IM483SM_num_cards = IM483SM_NUM_CARDS;
IM483SM_num_cards = IM483SM_NUM_CARDS;
else
IM483SM_num_cards = num_cards;
IM483SM_num_cards = num_cards;
/* Set motor polling task rate */
if (scan_rate >= 1 && scan_rate <= 60)
targs.motor_scan_rate = scan_rate;
targs.motor_scan_rate = scan_rate;
else
targs.motor_scan_rate = SCAN_RATE;
targs.motor_scan_rate = SCAN_RATE;
/*
/*
* Allocate space for motor_state structures. Note this must be done
* before IM483SMConfig 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(IM483SM_num_cards *
sizeof(struct controller *));
motor_state = (struct controller **) malloc(IM483SM_num_cards * sizeof(struct controller *));
for (itera = 0; itera < IM483SM_num_cards; itera++)
motor_state[itera] = (struct controller *) NULL;
motor_state[itera] = (struct controller *) NULL;
return(OK);
}
@@ -487,7 +483,7 @@ IM483SMSetup(int num_cards, /* maximum number of controllers in system. */
/* IM483SMConfig() */
/*****************************************************/
RTN_STATUS
IM483SMConfig(int card, /* card being configured */
IM483SMConfig(int card, /* card being configured */
const char *name) /* asyn server task name */
{
struct IM483controller *cntrl;
@@ -505,10 +501,10 @@ IM483SMConfig(int card, /* card being configured */
/*****************************************************/
/* initialize all software and hardware */
/* initialize all software and hardware */
/* This is called from the initialization routine in */
/* device support. */
/* motor_init() */
/* motor_init() */
/*****************************************************/
static int motor_init()
{
@@ -522,125 +518,122 @@ static int motor_init()
static const char output_terminator[] = "\r";
static const char input_terminator[] = "\r\n";
initialized = true; /* Indicate that driver is initialized. */
initialized = true; /* Indicate that driver is initialized. */
/* Check for setup */
if (IM483SM_num_cards <= 0)
return(ERROR);
return(ERROR);
for (card_index = 0; card_index < IM483SM_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 IM483controller *) brdptr->DevicePrivate;
if (!motor_state[card_index])
continue;
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port, 0,
&cntrl->pasynUser, NULL);
brdptr = motor_state[card_index];
brdptr->cmnd_response = true;
total_cards = card_index + 1;
cntrl = (struct IM483controller *) brdptr->DevicePrivate;
if (success_rtn == asynSuccess)
{
int itera, retry = 0;
char *src, *dest;
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port, 0, &cntrl->pasynUser, NULL);
pasynOctetSyncIO->setOutputEos(cntrl->pasynUser, output_terminator,
strlen(output_terminator));
pasynOctetSyncIO->setInputEos(cntrl->pasynUser, input_terminator,
strlen(input_terminator));
do
{
/* 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);
if (success_rtn == asynSuccess)
{
int itera, retry = 0;
char *src, *dest;
send_mess(card_index, "\003", (char) NULL); /* Reset device. */
epicsThreadSleep(1.0);
send_mess(card_index, " ", (char) NULL);
pasynOctetSyncIO->setOutputEos(cntrl->pasynUser, output_terminator, strlen(output_terminator));
pasynOctetSyncIO->setInputEos(cntrl->pasynUser, input_terminator, strlen(input_terminator));
do
{
/* 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);
/* Save controller identification message. */
src = buff;
dest = brdptr->ident;
*src = (char) NULL;
send_mess(card_index, "\003", (char) NULL); /* Reset device. */
epicsThreadSleep(1.0);
send_mess(card_index, " ", (char) NULL);
for (itera = 0; itera < 50; itera++)
{
if (*src == (char) NULL)
{
status = recv_mess(card_index, buff, 1);
if (status <= 0)
{
if (itera != 0)
{
*dest = (char) NULL;
status = 1;
}
break;
}
src = buff;
while (isspace(*src++));
--src;
if (itera != 0)
{
*dest++ = ' ';
itera++;
}
}
else if (isspace(*src))
{
while (isspace(*src++));
src -= 2;
}
else if (strncmp(src, "AD", 2) == 0)
{
strcpy(dest, "AMS");
src += 22;
dest += 3;
itera += 3;
}
*dest++ = *src++;
}
retry++;
/* Return value is length of response string */
} while (status == 0 && retry < 3);
}
/* Save controller identification message. */
src = buff;
dest = brdptr->ident;
*src = (char) NULL;
if (success_rtn == asynSuccess && status > 0)
{
brdptr->localaddr = (char *) NULL;
brdptr->motor_in_motion = 0;
for (itera = 0; itera < 50; itera++)
{
if (*src == (char) NULL)
{
status = recv_mess(card_index, buff, 1);
if (status <= 0)
{
if (itera != 0)
{
*dest = (char) NULL;
status = 1;
}
break;
}
src = buff;
while (isspace(*src++));
--src;
if (itera != 0)
{
*dest++ = ' ';
itera++;
}
}
else if (isspace(*src))
{
while (isspace(*src++));
src -= 2;
}
else if (strncmp(src, "AD", 2) == 0)
{
strcpy(dest, "AMS");
src += 22;
dest += 3;
itera += 3;
}
*dest++ = *src++;
}
retry++;
/* Return value is length of response string */
} while (status == 0 && retry < 3);
}
brdptr->total_axis = total_axis = 1;
if (success_rtn == asynSuccess && status > 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];
int loop_state;
brdptr->total_axis = total_axis = 1;
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;
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
int loop_state;
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;
/* Determine if encoder present based on open/closed loop mode. */
loop_state = 0;
if (loop_state != 0)
{
loop_state = 0;
if (loop_state != 0)
{
motor_info->encoder_present = YES;
motor_info->status.Bits.EA_PRESENT = 1;
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
}
motor_info->status.Bits.EA_PRESENT = 1;
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
}
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
}
any_motor_in_motion = 0;
@@ -652,8 +645,8 @@ static int motor_init()
free_list.tail = (struct mess_node *) NULL;
epicsThreadCreate((char *) "IM483SM_motor", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
return(OK);
}
+275 -275
View File
@@ -1,11 +1,11 @@
/*
FILENAME... drvMDrive.cc
USAGE... Motor record driver level support for Intelligent Motion
Systems, Inc. MDrive series; M17, M23, M34.
FILENAME... drvMDrive.cc
USAGE... Motor record driver level support for Intelligent Motion
Systems, Inc. MDrive series; M17, M23, M34.
Version: $Revision: 1.16 $
Modified By: $Author: sluiter $
Last Modified: $Date: 2005-03-30 19:01:26 $
Version: $Revision: 1.17 $
Modified By: $Author: dkline $
Last Modified: $Date: 2005-04-14 18:51:52 $
*/
/*
@@ -22,16 +22,16 @@ Last Modified: $Date: 2005-03-30 19:01:26 $
* 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
* 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
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
@@ -44,20 +44,20 @@ Last Modified: $Date: 2005-03-30 19:01:26 $
* .05 09/20/04 rls - support for 32axes/controller.
* - remove '?' command string padding.
* .06 12/16/04 rls - asyn R4.0 support.
* - make debug variables always available.
* - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
* - make debug variables always available.
* - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
* .07 03/18/05 rls - Flexible MDrive I/O configuration.
* - Change Echo mode to 2; eliminate eat_garbage().
* - Change Echo mode to 2; eliminate eat_garbage().
*/
/*
DESIGN LIMITATIONS...
1 - Like all controllers, the MDrive must be powered-on when EPICS is first
booted up.
booted up.
2 - The MDrive cannot be power cycled while EPICS is up and running. The
consequences are permanent communication lose with the MDrive until
EPICS is rebooted.
consequences are permanent communication lose with the MDrive until
EPICS is rebooted.
*/
#include <string.h>
@@ -68,16 +68,16 @@ DESIGN LIMITATIONS...
#include "asynOctetSyncIO.h"
#include "epicsExport.h"
#define MDrive_NUM_CARDS 8
#define MAX_AXES 8
#define BUFF_SIZE 13 /* Maximum length of string to/from MDrive */
#define MDrive_NUM_CARDS 8
#define MAX_AXES 8
#define BUFF_SIZE 13 /* Maximum length of string to/from MDrive */
/*----------------debugging-----------------*/
#ifdef __GNUG__
#ifdef DEBUG
#define Debug(l, f, args...) {if (l <= drvMDrivedebug) printf(f, ## args);}
#ifdef DEBUG
#define Debug(l, f, args...) {if (l <= drvMDrivedebug) printf(f, ## args);}
#else
#define Debug(l, f, args...)
#define Debug(l, f, args...)
#endif
#else
#define Debug()
@@ -90,7 +90,7 @@ int MDrive_num_cards = 0;
static char *MDrive_axis[] = {"1", "2", "3", "4", "5", "6", "7", "8"};
/* Local data required for every driver; see "motordrvComCode.h" */
#include "motordrvComCode.h"
#include "motordrvComCode.h"
/*----------------functions-----------------*/
static int recv_mess(int, char *, int);
@@ -147,24 +147,24 @@ static long report(int level)
int card;
if (MDrive_num_cards <=0)
printf(" No MDrive controllers configured.\n");
printf(" No MDrive controllers configured.\n");
else
{
for (card = 0; card < MDrive_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
for (card = 0; card < MDrive_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
if (brdptr == NULL)
printf(" MDrive controller %d connection failed.\n", card);
else
{
struct IM483controller *cntrl;
if (brdptr == NULL)
printf(" MDrive controller %d connection failed.\n", card);
else
{
struct IM483controller *cntrl;
cntrl = (struct IM483controller *) brdptr->DevicePrivate;
printf(" IM483SM controller #%d, port=%s, id: %s \n", card,
cntrl->asyn_port, brdptr->ident);
}
}
cntrl = (struct IM483controller *) brdptr->DevicePrivate;
printf(" IM483SM controller #%d, port=%s, id: %s \n", card,
cntrl->asyn_port, brdptr->ident);
}
}
}
return(OK);
}
@@ -172,7 +172,7 @@ static long report(int level)
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
@@ -181,7 +181,7 @@ static long init()
/* Check for setup */
if (MDrive_num_cards <= 0)
{
Debug(1, "init(): MDrive driver disabled. MDriveSetup() missing from startup script.\n");
Debug(1, "init(): MDrive driver disabled. MDriveSetup() missing from startup script.\n");
}
return((long) 0);
}
@@ -193,32 +193,32 @@ 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 *
* *
* *
* *
* 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)
@@ -244,32 +244,32 @@ static int set_status(int card, int signal)
rtn_state = recv_mess(card, buff, 1);
if (rtn_state > 0)
{
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 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;
}
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 = atoi(buff);
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
@@ -282,25 +282,25 @@ static int set_status(int card, int signal)
if (motorData == motor_info->position)
{
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
}
else
{
epicsInt32 newposition;
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;
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;
if (confptr->plusLS == 0 || confptr->minusLS == 0)
{
status.Bits.RA_PLUS_LS = 0;
status.Bits.RA_MINUS_LS = 0;
status.Bits.RA_PLUS_LS = 0;
status.Bits.RA_MINUS_LS = 0;
}
else
{
@@ -310,60 +310,60 @@ static int set_status(int card, int signal)
Lswitch = atoi(buff);
/* 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;
if (Lswitch != 0)
{
status.Bits.RA_PLUS_LS = 1;
if (plusdir == true)
ls_active = true;
}
else
status.Bits.RA_PLUS_LS = 0;
sprintf(buff, "PR I%d", confptr->minusLS);
send_mess(card, buff, MDrive_axis[signal]);
recv_mess(card, buff, 1);
Lswitch = atoi(buff);
if (Lswitch != 0)
{
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
}
else
status.Bits.RA_MINUS_LS = 0;
if (Lswitch != 0)
{
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
}
else
status.Bits.RA_MINUS_LS = 0;
}
if (confptr->homeLS == 0)
status.Bits.RA_HOME = 0;
status.Bits.RA_HOME = 0;
else
{
sprintf(buff, "PR I%d", confptr->homeLS);
send_mess(card, buff, MDrive_axis[signal]);
recv_mess(card, buff, 1);
Lswitch = atoi(buff);
status.Bits.RA_HOME = (Lswitch) ? 1 : 0;
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 = 0;
status.Bits.EA_SLIP_STALL = 0;
status.Bits.EA_HOME = 0;
status.Bits.EA_HOME = 0;
if (motor_state[card]->motor_info[signal].encoder_present == NO)
motor_info->encoder_position = 0;
motor_info->encoder_position = 0;
else
{
send_mess(card, "PR C2", MDrive_axis[signal]);
recv_mess(card, buff, 1);
motorData = atof(buff);
motor_info->encoder_position = (int32_t) motorData;
send_mess(card, "PR C2", MDrive_axis[signal]);
recv_mess(card, buff, 1);
motorData = atof(buff);
motor_info->encoder_position = (int32_t) motorData;
}
status.Bits.RA_PROBLEM = 0;
status.Bits.RA_PROBLEM = 0;
/* Parse motor velocity? */
/* NEEDS WORK */
@@ -371,18 +371,18 @@ static int set_status(int card, int signal)
motor_info->velocity = 0;
if (!status.Bits.RA_DIRECTION)
motor_info->velocity *= -1;
motor_info->velocity *= -1;
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
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)
nodeptr->postmsgptr != 0)
{
strcpy(buff, nodeptr->postmsgptr);
send_mess(card, buff, MDrive_axis[signal]);
nodeptr->postmsgptr = NULL;
strcpy(buff, nodeptr->postmsgptr);
send_mess(card, buff, MDrive_axis[signal]);
nodeptr->postmsgptr = NULL;
}
exit:
@@ -392,47 +392,47 @@ exit:
/*****************************************************/
/* send a message to the MDrive board */
/* send_mess() */
/* send a message to the MDrive board */
/* send_mess() */
/*****************************************************/
static RTN_STATUS send_mess(int card, char const *com, char *name)
{
char local_buff[MAX_MSG_SIZE];
struct IM483controller *cntrl;
int comsize, namesize;
int nwrite;
size_t nwrite;
comsize = (com == NULL) ? 0 : strlen(com);
namesize = (name == NULL) ? 0 : strlen(name);
if ((comsize + namesize) > MAX_MSG_SIZE)
{
errlogMessage("drvMDrive.c:send_mess(); message size violation.\n");
return(ERROR);
errlogMessage("drvMDrive.c:send_mess(); message size violation.\n");
return(ERROR);
}
else if (comsize == 0) /* Normal exit on empty input message. */
return(OK);
else if (comsize == 0) /* Normal exit on empty input message. */
return(OK);
if (!motor_state[card])
{
errlogPrintf("drvMDrive.c:send_mess() - invalid card #%d\n", card);
return(ERROR);
errlogPrintf("drvMDrive.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);
strcpy(local_buff, name); /* put in axis */
strcat(local_buff, com);
}
else
strcpy(local_buff, com);
strcpy(local_buff, com);
Debug(2, "send_mess(): message = %s\n", local_buff);
cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate;
pasynOctetSyncIO->write(cntrl->pasynUser, local_buff, strlen(local_buff),
COMM_TIMEOUT, &nwrite);
COMM_TIMEOUT, &nwrite);
return(OK);
}
@@ -440,32 +440,32 @@ static RTN_STATUS send_mess(int card, char const *com, char *name)
/*****************************************************/
/* receive a message from the MDrive board */
/* recv_mess() */
/* recv_mess() */
/*****************************************************/
static int recv_mess(int card, char *com, int flag)
{
struct IM483controller *cntrl;
const double timeout = 1.0;
int nread = 0;
size_t nread = 0;
asynStatus status = asynError;
int eomReason;
/* Check that card exists */
if (!motor_state[card])
return(ERROR);
return(ERROR);
cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate;
if (flag == FLUSH)
pasynOctetSyncIO->flush(cntrl->pasynUser);
pasynOctetSyncIO->flush(cntrl->pasynUser);
else
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
timeout, &nread, &eomReason);
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
timeout, &nread, &eomReason);
if ((status != asynSuccess) || (nread <= 0))
{
com[0] = '\0';
nread = 0;
com[0] = '\0';
nread = 0;
}
Debug(2, "recv_mess(): message = \"%s\"\n", com);
@@ -478,33 +478,33 @@ static int recv_mess(int card, char *com, int flag)
/* MDriveSetup() */
/*****************************************************/
RTN_STATUS
MDriveSetup(int num_cards, /* maximum number of chains in system. */
int scan_rate) /* polling rate - 1/60 sec units. */
MDriveSetup(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 > MDrive_NUM_CARDS)
MDrive_num_cards = MDrive_NUM_CARDS;
MDrive_num_cards = MDrive_NUM_CARDS;
else
MDrive_num_cards = num_cards;
MDrive_num_cards = num_cards;
/* Set motor polling task rate */
if (scan_rate >= 1 && scan_rate <= 60)
targs.motor_scan_rate = scan_rate;
targs.motor_scan_rate = scan_rate;
else
targs.motor_scan_rate = SCAN_RATE;
targs.motor_scan_rate = SCAN_RATE;
/*
/*
* Allocate space for motor_state structures. Note this must be done
* before IM483Config 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(MDrive_num_cards *
sizeof(struct controller *));
sizeof(struct controller *));
for (itera = 0; itera < MDrive_num_cards; itera++)
motor_state[itera] = (struct controller *) NULL;
motor_state[itera] = (struct controller *) NULL;
return(OK);
}
@@ -515,8 +515,8 @@ MDriveSetup(int num_cards, /* maximum number of chains in system. */
/* MDriveConfig() */
/*****************************************************/
RTN_STATUS
MDriveConfig(int card, /* chain being configured */
const char *name) /* ASYN port name */
MDriveConfig(int card, /* chain being configured */
const char *name) /* ASYN port name */
{
struct IM483controller *cntrl;
@@ -533,10 +533,10 @@ MDriveConfig(int card, /* chain being configured */
/*****************************************************/
/* initialize all software and hardware */
/* initialize all software and hardware */
/* This is called from the initialization routine in */
/* device support. */
/* motor_init() */
/* motor_init() */
/*****************************************************/
static int motor_init()
{
@@ -550,137 +550,137 @@ static int motor_init()
static const char output_terminator[] = "\n";
static const char input_terminator[] = "\r\n";
initialized = true; /* Indicate that driver is initialized. */
initialized = true; /* Indicate that driver is initialized. */
/* Check for setup */
if (MDrive_num_cards <= 0)
return(ERROR);
return(ERROR);
for (card_index = 0; card_index < MDrive_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 IM483controller *) brdptr->DevicePrivate;
if (!motor_state[card_index])
continue;
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port, 0,
&cntrl->pasynUser, NULL);
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 IM483controller *) brdptr->DevicePrivate;
if (success_rtn == asynSuccess)
{
pasynOctetSyncIO->setOutputEos(cntrl->pasynUser, output_terminator,
strlen(output_terminator));
pasynOctetSyncIO->setInputEos(cntrl->pasynUser, input_terminator,
strlen(input_terminator));
/* Send a message to the board, see if it exists */
/* flush any junk at input port - should not be any data available */
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port, 0,
&cntrl->pasynUser, NULL);
if (success_rtn == asynSuccess)
{
pasynOctetSyncIO->setOutputEos(cntrl->pasynUser, output_terminator,
strlen(output_terminator));
pasynOctetSyncIO->setInputEos(cntrl->pasynUser, input_terminator,
strlen(input_terminator));
/* 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 < MAX_AXES; total_axis++)
{
int retry = 0;
/* Try 3 times to connect to controller. */
do
{
send_mess(card_index, "PR VR", MDrive_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;
cntrl->inconfig = (input_config *) malloc(
sizeof(struct IM483controller) * total_axis);
}
for (total_axis = 0; total_axis < MAX_AXES; total_axis++)
{
int retry = 0;
if (success_rtn == asynSuccess && total_axis > 0)
{
input_config *confptr = cntrl->inconfig;
/* Try 3 times to connect to controller. */
do
{
send_mess(card_index, "PR VR", MDrive_axis[total_axis]);
status = recv_mess(card_index, buff, 1);
retry++;
} while (status == 0 && retry < 3);
brdptr->localaddr = (char *) NULL;
brdptr->motor_in_motion = 0;
if (status <= 0)
break;
else if (total_axis == 0)
strcpy(brdptr->ident, buff);
}
brdptr->total_axis = total_axis;
cntrl->inconfig = (input_config *) malloc(
sizeof(struct IM483controller) * total_axis);
}
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
int itera;
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
if (success_rtn == asynSuccess && total_axis > 0)
{
input_config *confptr = cntrl->inconfig;
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;
/* Assume no encoder support. */
motor_info->encoder_present = NO;
brdptr->localaddr = (char *) NULL;
brdptr->motor_in_motion = 0;
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
int itera;
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;
/* Assume no encoder support. */
motor_info->encoder_present = NO;
/* Determine if encoder present based last character of "ident". */
if (brdptr->ident[strlen(brdptr->ident) - 1] == 'E')
{
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
motor_info->encoder_present = YES;
motor_info->status.Bits.EA_PRESENT = 1;
}
if (brdptr->ident[strlen(brdptr->ident) - 1] == 'E')
{
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
motor_info->encoder_present = YES;
motor_info->status.Bits.EA_PRESENT = 1;
}
/* Determine input configuration. */
confptr->homeLS = confptr->minusLS = confptr->plusLS = 0;
confptr->homeLS = confptr->minusLS = confptr->plusLS = 0;
for (itera = 1; itera <= 4; itera++)
{
int type, active;
for (itera = 1; itera <= 4; itera++)
{
int type, active;
sprintf(buff, "PR S%d", itera);
send_mess(card_index, buff, MDrive_axis[motor_index]);
status = recv_mess(card_index, buff, 1);
if (status == 0)
{
errlogPrintf("Error reading I/O configuration.\n");
break;
}
status = sscanf(buff, "%d,%d", &type, &active);
switch (type)
{
case 0:
break;
case 1: // Home switch.
confptr->homeLS = itera;
break;
case 2: // Plus limit switch.
confptr->plusLS = itera;
break;
case 3: // Minus limit switch.
confptr->minusLS = itera;
break;
default:
errlogPrintf("Invalid I/O type: %d.\n", type);
sprintf(buff, "PR S%d", itera);
send_mess(card_index, buff, MDrive_axis[motor_index]);
status = recv_mess(card_index, buff, 1);
if (status == 0)
{
errlogPrintf("Error reading I/O configuration.\n");
break;
}
}
}
// Test for missing configuration.
if (confptr->minusLS == 0 || confptr->plusLS == 0)
{
const char p_label[6] = "Plus", m_label[6] = "Minus";
errlogPrintf("MDrive chain #%d, motor #%d %s LS not configured.\n",
card_index, motor_index,
(confptr->minusLS == 0) ? m_label : p_label);
}
status = sscanf(buff, "%d,%d", &type, &active);
switch (type)
{
case 0:
break;
case 1: // Home switch.
confptr->homeLS = itera;
break;
case 2: // Plus limit switch.
confptr->plusLS = itera;
break;
case 3: // Minus limit switch.
confptr->minusLS = itera;
break;
default:
errlogPrintf("Invalid I/O type: %d.\n", type);
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
}
}
// Test for missing configuration.
if (confptr->minusLS == 0 || confptr->plusLS == 0)
{
const char p_label[6] = "Plus", m_label[6] = "Minus";
errlogPrintf("MDrive chain #%d, motor #%d %s LS not configured.\n",
card_index, motor_index,
(confptr->minusLS == 0) ? m_label : p_label);
}
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
}
any_motor_in_motion = 0;
@@ -692,8 +692,8 @@ static int motor_init()
free_list.tail = (struct mess_node *) NULL;
epicsThreadCreate((char *) "MDrive_motor", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
return(OK);
}
+56 -57
View File
@@ -14,9 +14,9 @@
* .04 07-12-2004 rls Converted from MPF to asyn.
* .05 09-20-2004 rls support for 32axes/controller.
* .08 12-16-2004 rls - asyn R4.0 support.
* - make debug variables always available.
* - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
* - make debug variables always available.
* - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
*/
@@ -29,7 +29,7 @@
#define WAIT 1
#define COMM_TIMEOUT 2 /* Command timeout in seconds. */
#define COMM_TIMEOUT 2 /* Command timeout in seconds. */
#define BUFF_SIZE 100 /* Maximum length of string to/from Micos */
@@ -42,10 +42,10 @@ struct mess_queue
/*----------------debugging-----------------*/
#ifdef __GNUG__
#ifdef DEBUG
#define Debug(l, f, args...) {if (l <= drvMicosDebug) printf(f, ## args);}
#ifdef DEBUG
#define Debug(l, f, args...) {if (l <= drvMicosDebug) printf(f, ## args);}
#else
#define Debug(l, f, args...)
#define Debug(l, f, args...)
#endif
#else
#define Debug()
@@ -56,10 +56,10 @@ extern "C" {epicsExportAddress(int, drvMicosDebug);}
/* Debugging notes:
* drvMicosDebug == 0 No debugging information is printed
* drvMicosDebug >= 1 Warning information is printed
* drvMicosDebug >= 2 Time-stamped messages are printed for each string
* drvMicosDebug >= 2 Time-stamped messages are printed for each string
* sent to and received from the controller
* drvMicosDebug >= 3 Additional debugging messages
*/
*/
volatile int Micos_num_cards = 0;
volatile int Micos_num_axis = 0;
@@ -224,22 +224,22 @@ static int set_status(int card, int signal)
/* check limits */
status.Bits.RA_PLUS_LS = status.Bits.RA_MINUS_LS = 0;
if ((bytes[5] & 0x04) & (bytes[3] & 0x04)) { /* if +lim AND pos move */
status.Bits.RA_PLUS_LS = 1;
ls_active = true;
status.Bits.RA_PLUS_LS = 1;
ls_active = true;
}
if ((bytes[5] & 0x01) & !(bytes[3] & 0x04)) { /* if -lim AND neg move */
status.Bits.RA_MINUS_LS = 1;
ls_active = true;
status.Bits.RA_MINUS_LS = 1;
ls_active = true;
}
/* encoder status */
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP = 0;
status.Bits.EA_POSITION = 0;
status.Bits.EA_SLIP_STALL = 0;
status.Bits.EA_HOME = 0;
status.Bits.EA_HOME = 0;
if ((bytes[3] & 0x08) | (bytes[3] & 0x40)) {
printf("drvMicos: set_status: EA_SLIP_STALL = 1, %ld\n", bytes[3]);
status.Bits.EA_SLIP_STALL = 1;
status.Bits.EA_SLIP_STALL = 1;
}
/* Request the position of this motor */
@@ -255,12 +255,12 @@ static int set_status(int card, int signal)
/* derive direction information */
if (motorData == motor_info->position)
{
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
}
else
{
status.Bits.RA_DIRECTION = (bytes[3] & 0x04) ? 1 : 0;
status.Bits.RA_DIRECTION = (bytes[3] & 0x04) ? 1 : 0;
motor_info->position = motorData;
motor_info->encoder_position = motorData;
motor_info->no_motion_count = 0;
@@ -275,11 +275,11 @@ static int set_status(int card, int signal)
motor_info->velocity *= -1;
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
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)
nodeptr->postmsgptr != 0)
{
strcpy(buff, nodeptr->postmsgptr);
send_mess(card, buff, (char) NULL);
@@ -301,7 +301,7 @@ static RTN_STATUS send_mess(int card, const char *com, char *name)
{
struct MicosController *cntrl;
int size;
int nwrite;
size_t nwrite;
size = strlen(com);
@@ -318,8 +318,7 @@ static RTN_STATUS send_mess(int card, const char *com, char *name)
Debug(2, "send_mess: sending message to card %d, message=%s\n", card, buff);
cntrl = (struct MicosController *) motor_state[card]->DevicePrivate;
pasynOctetSyncIO->write(cntrl->pasynUser, com, size, COMM_TIMEOUT,
&nwrite);
pasynOctetSyncIO->write(cntrl->pasynUser, com, size, COMM_TIMEOUT, &nwrite);
return (OK);
}
@@ -332,7 +331,7 @@ static RTN_STATUS send_mess(int card, const char *com, char *name)
static int recv_mess(int card, char *com, int flag)
{
struct MicosController *cntrl;
int nread = 0;
size_t nread = 0;
asynStatus status = asynError;
int eomReason;
@@ -347,23 +346,23 @@ static int recv_mess(int card, char *com, int flag)
Debug(3, "recv_mess entry: card %d, flag=%d\n", card, flag);
if (flag == FLUSH)
pasynOctetSyncIO->flush(cntrl->pasynUser);
pasynOctetSyncIO->flush(cntrl->pasynUser);
else
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
COMM_TIMEOUT, &nread, &eomReason);
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
COMM_TIMEOUT, &nread, &eomReason);
if ((status != asynSuccess) || (nread <= 0))
{
com[0] = '\0';
nread = 0;
if (flag != FLUSH)
{
Debug(1, "recv_mess: card %d ERROR: no response\n", card);
}
com[0] = '\0';
nread = 0;
if (flag != FLUSH)
{
Debug(1, "recv_mess: card %d ERROR: no response\n", card);
}
}
else
{
Debug(2, "recv_mess: card %d, message = \"%s\"\n", card, com);
Debug(2, "recv_mess: card %d, message = \"%s\"\n", card, com);
}
return (nread);
}
@@ -393,9 +392,9 @@ MicosSetup(int num_cards, /* maximum number of "controllers" in system */
/* Set motor polling task rate */
if (scan_rate >= 1 && scan_rate <= 60)
targs.motor_scan_rate = scan_rate;
targs.motor_scan_rate = scan_rate;
else
targs.motor_scan_rate = SCAN_RATE;
targs.motor_scan_rate = SCAN_RATE;
/*
* Allocate space for motor_state structure pointers. Note this must be done
@@ -418,8 +417,8 @@ MicosSetup(int num_cards, /* maximum number of "controllers" in system */
/* MicosConfig() */
/*****************************************************/
RTN_STATUS
MicosConfig(int card, /* "controller" being configured */
const char *name) /* asyn server task name */
MicosConfig(int card, /* "controller" being configured */
const char *name) /* asyn server task name */
{
struct MicosController *cntrl;
@@ -428,7 +427,7 @@ MicosConfig(int card, /* "controller" being configured */
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
motor_state[card]->DevicePrivate = malloc(sizeof(struct MicosController));
cntrl = (struct MicosController *) motor_state[card]->DevicePrivate;
strcpy(cntrl->asyn_port, name);
return(OK);
@@ -477,17 +476,17 @@ static int motor_init()
/* Initialize communications channel */
errind = false;
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port, 0,
&cntrl->pasynUser, NULL);
if (success_rtn == asynSuccess)
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port, 0,
&cntrl->pasynUser, NULL);
if (success_rtn == asynSuccess)
{
int retry = 0;
pasynOctetSyncIO->setOutputEos(cntrl->pasynUser, output_terminator,
strlen(output_terminator));
pasynOctetSyncIO->setInputEos(cntrl->pasynUser, input_terminator,
strlen(input_terminator));
pasynOctetSyncIO->setOutputEos(cntrl->pasynUser, output_terminator,
strlen(output_terminator));
pasynOctetSyncIO->setInputEos(cntrl->pasynUser, input_terminator,
strlen(input_terminator));
/* Each "controller" can have max 16 axes. */
total_axis = Micos_num_axis;
@@ -529,12 +528,12 @@ static int motor_init()
sprintf(buff, "%c%def", CTLA, motor_index);
send_mess(card_index, buff, 0);
/* Don't turn on motor power, too dangerous */
/*sprintf(buff,"#%02dW=1", motor_index); */
/*sprintf(buff,"#%02dW=1", motor_index); */
/* send_mess(card_index, buff, 0); */
/* Stop motor */
sprintf(buff,"%c%dab1", CTLA, motor_index);
send_mess(card_index, buff, 0);
/* recv_mess(card_index, buff, WAIT); Throw away response */
/* recv_mess(card_index, buff, WAIT); Throw away response */
strcpy(brdptr->ident, "MICOS");
motor_info->status.All = 0;
@@ -543,9 +542,9 @@ static int motor_init()
motor_info->position = 0;
motor_info->encoder_present = YES;
motor_info->status.Bits.EA_PRESENT = 1;
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
motor_info->status.Bits.EA_PRESENT = 1;
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
set_status(card_index, motor_index); /* Read status of each motor */
}
@@ -556,7 +555,7 @@ static int motor_init()
}
Debug(3, "motor_init: spawning motor task\n");
any_motor_in_motion = 0;
mess_queue.head = (struct mess_node *) NULL;
@@ -566,8 +565,8 @@ static int motor_init()
free_list.tail = (struct mess_node *) NULL;
epicsThreadCreate((char *) "tMicos", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
return (0);
}
+281 -282
View File
@@ -1,11 +1,11 @@
/*
FILENAME... drvMVP2001.cc
USAGE... Motor record driver level support for MicroMo
MVP 2001 B02 (Linear, RS-485).
FILENAME... drvMVP2001.cc
USAGE... Motor record driver level support for MicroMo
MVP 2001 B02 (Linear, RS-485).
Version: $Revision: 1.7 $
Modified By: $Author: sluiter $
Last Modified: $Date: 2005-03-30 19:07:09 $
Version: $Revision: 1.8 $
Modified By: $Author: dkline $
Last Modified: $Date: 2005-04-14 18:52:29 $
*/
/*
@@ -48,7 +48,7 @@ Last Modified: $Date: 2005-03-30 19:07:09 $
* documentation and/or other materials provided with the distribution.
*
*
* Neither the names of UNICAT, Frederick Seitz Materials Research
* Neither the names of UNICAT, Frederick Seitz Materials Research
* Laboratory, University of Illinois at Urbana-Champaign,
* nor the names of its contributors may be used to endorse or promote
* products derived from this Software without specific prior written
@@ -66,58 +66,58 @@ Last Modified: $Date: 2005-03-30 19:07:09 $
*
* Modification Log:
* -----------------
* .01 08/27/02 kmp copied from drvIM483PL.c (rev 1.7, mod .03) and
* customized for the MVP2001.
* .02 08/27/02 kmp changed message construction to allow for addresses
* larger than 9.
* .03 09/06/02 kmp added an extra loop to motor_init() that sends the HO
* command a second time to ensure the position is set to
* zero. Previously, saved positions would not be loaded
* if the controller was power-cycled.
* .01 08/27/02 kmp copied from drvIM483PL.c (rev 1.7, mod .03) and
* customized for the MVP2001.
* .02 08/27/02 kmp changed message construction to allow for addresses
* larger than 9.
* .03 09/06/02 kmp added an extra loop to motor_init() that sends the HO
* command a second time to ensure the position is set to
* zero. Previously, saved positions would not be loaded
* if the controller was power-cycled.
* .04 02/06/04 rls Eliminate erroneous "Motor motion timeout ERROR".
* .05 02/13/04 rls port to R3.14.x
* .06 07/12/04 rls Converted from MPF to asyn.
* .05 02/13/04 rls port to R3.14.x
* .06 07/12/04 rls Converted from MPF to asyn.
* .07 12/16/04 rls - asyn R4.0 support.
* - make debug variables always available.
* - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
* - retry on initial communication.
* - make debug variables always available.
* - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
* - retry on initial communication.
*
*/
/*
DESIGN LIMITATIONS...
1 - Like all controllers, the MVP2001 must be powered-on when EPICS is first
booted up.
booted up.
2 - The MVP2001 cannot be power cycled while EPICS is up and running. The
consequences are permanent communication loss with the MVP2001 until
EPICS is rebooted.
3 - Translation between the MVP2001 and the ACCL/BACC fields is not obvious.
consequences are permanent communication loss with the MVP2001 until
EPICS is rebooted.
3 - Translation between the MVP2001 and the ACCL/BACC fields is not obvious.
*/
/*
MORE DESIGN LIMITATIONS
1 - For the most part the standard terminology (card-signal-axis) has been
used here so that this code resembles other drivers. Unfortunately,
the terminology is not the best for this controller. The MVP2001 is a
single-axis, RS-485-daisy-chainable, DC controller. The following
equations succinctly illustrate the relationship between the physical
setup and the standard terminology:
card = chain of MVP2001 controllers
signal = axis = one of the MVP2001 controllers on a chain
2 - Strtol and strtoul have been switched in the vxWorks that KMP used
at the time that this was being written. If your vxWorks functions
behave correctly, then they will have to be switched in the code.
used here so that this code resembles other drivers. Unfortunately,
the terminology is not the best for this controller. The MVP2001 is a
single-axis, RS-485-daisy-chainable, DC controller. The following
equations succinctly illustrate the relationship between the physical
setup and the standard terminology:
card = chain of MVP2001 controllers
signal = axis = one of the MVP2001 controllers on a chain
2 - Strtol and strtoul have been switched in the vxWorks that KMP used
at the time that this was being written. If your vxWorks functions
behave correctly, then they will have to be switched in the code.
3 - Factors that currently limit the number of controllers on one chain:
A. MVP2001 addresses
The MVP2001 can have an address of 1-64 for serial communication.
B. RS-485 communication degradation
There is a practical limit to how many controllers can be on one chain
C. The motor_info array of the controller structure in motordrvCom.h
For a chain to work correctly, there needs to be one element in the
motor_info array for every controller on the chain. The limit is
set by the constant MAX_AXIS, which is defined in motor.h. The end
result is that the number of controllers is limited by the motor
record. The current maximum number of controllers is 10.
A. MVP2001 addresses
The MVP2001 can have an address of 1-64 for serial communication.
B. RS-485 communication degradation
There is a practical limit to how many controllers can be on one chain
C. The motor_info array of the controller structure in motordrvCom.h
For a chain to work correctly, there needs to be one element in the
motor_info array for every controller on the chain. The limit is
set by the constant MAX_AXIS, which is defined in motor.h. The end
result is that the number of controllers is limited by the motor
record. The current maximum number of controllers is 10.
*/
#include <string.h>
@@ -127,15 +127,15 @@ MORE DESIGN LIMITATIONS
#include "drvMVP2001.h"
#include "epicsExport.h"
#define MVP2001_NUM_CARDS 8
#define BUFF_SIZE 20 /* Maximum length of string to/from MVP2001 */
#define MVP2001_NUM_CARDS 8
#define BUFF_SIZE 20 /* Maximum length of string to/from MVP2001 */
/*----------------debugging-----------------*/
#ifdef __GNUG__
#ifdef DEBUG
#define Debug(l, f, args...) { if(l<=drvMVP2001debug) printf(f,## args); }
#ifdef DEBUG
#define Debug(l, f, args...) { if(l<=drvMVP2001debug) printf(f,## args); }
#else
#define Debug(l, f, args...)
#define Debug(l, f, args...)
#endif
#else
#define Debug()
@@ -147,7 +147,7 @@ extern "C" {epicsExportAddress(int, drvMVP2001debug);}
int MVP2001_num_cards = 0;
/* Local data required for every driver; see "motordrvComCode.h" */
#include "motordrvComCode.h"
#include "motordrvComCode.h"
/*----------------functions-----------------*/
static int recv_mess(int, char *, int);
@@ -203,23 +203,23 @@ static long report(int level)
int card;
if (MVP2001_num_cards <=0)
printf(" No MVP2001 CHAINS configured.\n");
printf(" No MVP2001 CHAINS configured.\n");
else
{
for (card = 0; card < MVP2001_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
for (card = 0; card < MVP2001_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
if (brdptr == NULL)
printf(" MVP2001 controller chain #%d connection failed.\n", card);
else
{
struct MVPcontroller *cntrl;
cntrl = (struct MVPcontroller *) brdptr->DevicePrivate;
printf(" MVP2001 controller chain #%d, port=%s, id: %s \n", card,
cntrl->asyn_port, brdptr->ident);
}
}
if (brdptr == NULL)
printf(" MVP2001 controller chain #%d connection failed.\n", card);
else
{
struct MVPcontroller *cntrl;
cntrl = (struct MVPcontroller *) brdptr->DevicePrivate;
printf(" MVP2001 controller chain #%d, port=%s, id: %s \n", card,
cntrl->asyn_port, brdptr->ident);
}
}
}
return (0);
}
@@ -229,12 +229,12 @@ static long init()
{
/* initialize all hardware and software */
motor_init();
/* Check for setup */
if (MVP2001_num_cards <= 0)
{
Debug(1, "init(): MVP2001 driver disabled. MVP2001Setup() missing \
from startup script.\n");
Debug(1, "init(): MVP2001 driver disabled. MVP2001Setup() missing \
from startup script.\n");
}
return ((long) 0);
@@ -247,35 +247,35 @@ 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 *
* *
* *
* *
* 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 *
* *
* *
********************************************************************************/
/*
/*
* When the motor record calls set_status it passes it card and signal values
* that are found in the mvpMotors template (or the OUT field of the M.R.)
*/
@@ -306,25 +306,25 @@ static int set_status(int card, int signal)
rtn_state = recv_mess(card, buff, 1);
if (rtn_state > 0)
{
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 0;
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 0;
}
else
{
if (cntrl->status == NORMAL)
{
cntrl->status = RETRY;
rtn_state = 0;
goto exit;
}
else
{
cntrl->status = COMM_ERR;
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
if (cntrl->status == NORMAL)
{
cntrl->status = RETRY;
rtn_state = 0;
goto exit;
}
else
{
cntrl->status = COMM_ERR;
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
}
/*
@@ -342,53 +342,53 @@ static int set_status(int card, int signal)
send_mess(card, buff, (char) NULL);
recv_mess(card, buff, 1);
/*
/*
* Parse motor position
* Position string format: 0001 FFFFFFFF
* Skip to position substring for this motor, convert from hex to int
*/
strncat(positionStr, &buff[5], 8);
motorData = (epicsInt32) strtoul(positionStr, NULL, 16);
buff[0] = '\0';
buff[0] = '\0';
/*
* Set direction by comparing positions since the MVP2001
* Set direction by comparing positions since the MVP2001
* does not have a direction bit.
*/
if (motorData == motor_info->position)
{
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
}
else
{
epicsInt32 newposition;
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;
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;
/* Set limit switch error indicators. */
if (mstat.Bits.plusLS == false)
status.Bits.RA_PLUS_LS = 0;
status.Bits.RA_PLUS_LS = 0;
else
{
status.Bits.RA_PLUS_LS = 1;
if (plusdir == true)
ls_active = true;
status.Bits.RA_PLUS_LS = 1;
if (plusdir == true)
ls_active = true;
}
if (mstat.Bits.minusLS == false)
status.Bits.RA_MINUS_LS = 0;
status.Bits.RA_MINUS_LS = 0;
else
{
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
}
/* The MVP2001 doesn't have a home feature */
@@ -398,19 +398,19 @@ static int set_status(int card, int signal)
status.Bits.EA_POSITION = 0;
/* encoder status */
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP_STALL = 0;
status.Bits.EA_HOME = 0;
status.Bits.EA_HOME = 0;
if (motor_state[card]->motor_info[signal].encoder_present == NO)
motor_info->encoder_position = 0;
motor_info->encoder_position = 0;
else
{
/*
* There is not a seperate call for "encoder_position" as every call
* for the position of the DC motor reads the encoder.
*/
motor_info->encoder_position = motorData;
/*
* There is not a seperate call for "encoder_position" as every call
* for the position of the DC motor reads the encoder.
*/
motor_info->encoder_position = motorData;
}
status.Bits.RA_PROBLEM = 0;
@@ -421,18 +421,18 @@ static int set_status(int card, int signal)
motor_info->velocity = 0;
if (!status.Bits.RA_DIRECTION)
motor_info->velocity *= -1;
motor_info->velocity *= -1;
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
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)
nodeptr->postmsgptr != 0)
{
strcpy(buff, nodeptr->postmsgptr);
send_mess(card, buff, (char) NULL);
nodeptr->postmsgptr = NULL;
strcpy(buff, nodeptr->postmsgptr);
send_mess(card, buff, (char) NULL);
nodeptr->postmsgptr = NULL;
}
exit:
@@ -442,36 +442,35 @@ exit:
/*****************************************************/
/* send a message to the MVP2001 board */
/* send_mess() */
/* send a message to the MVP2001 board */
/* send_mess() */
/*****************************************************/
static RTN_STATUS send_mess(int card, char const *com, char *name)
{
struct MVPcontroller *cntrl;
int size;
int nwrite;
size_t nwrite;
size = strlen(com);
if (size > MAX_MSG_SIZE)
{
errlogMessage("drvMVP2001.c:send_mess(); message size violation.\n");
return(ERROR);
errlogMessage("drvMVP2001.c:send_mess(); message size violation.\n");
return(ERROR);
}
else if (size == 0) /* Normal exit on empty input message. */
return(OK);
else if (size == 0) /* Normal exit on empty input message. */
return(OK);
if (!motor_state[card])
{
errlogPrintf("drvMVP2001.c:send_mess() - invalid card #%d\n", card);
return(ERROR);
errlogPrintf("drvMVP2001.c:send_mess() - invalid card #%d\n", card);
return(ERROR);
}
Debug(2, "send_mess(): message = %s\n", com);
cntrl = (struct MVPcontroller *) motor_state[card]->DevicePrivate;
pasynOctetSyncIO->write(cntrl->pasynUser, com, size, COMM_TIMEOUT,
&nwrite);
pasynOctetSyncIO->write(cntrl->pasynUser, com, size, COMM_TIMEOUT, &nwrite);
return(OK);
}
@@ -479,41 +478,41 @@ static RTN_STATUS send_mess(int card, char const *com, char *name)
/*****************************************************/
/* receive a message from the MVP2001 board */
/* recv_mess() */
/* recv_mess() */
/*****************************************************/
static int recv_mess(int card, char *com, int flag)
{
struct MVPcontroller *cntrl;
char temp[BUFF_SIZE];
int nread = 0;
size_t nread = 0, lenTemp = 0;
asynStatus status = asynError;
int timeout;
int flush = 0;
int len=0, lenTemp=0;
int len=0;
int eomReason;
/* Check that card exists */
if (!motor_state[card])
return (-1);
return (-1);
cntrl = (struct MVPcontroller *) motor_state[card]->DevicePrivate;
if (flag == FLUSH)
timeout = 0;
timeout = 0;
else
timeout = COMM_TIMEOUT;
timeout = COMM_TIMEOUT;
len = pasynOctetSyncIO->read(cntrl->pasynUser, temp, BUFF_SIZE,
COMM_TIMEOUT, &lenTemp, &eomReason);
COMM_TIMEOUT, &lenTemp, &eomReason);
len = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
COMM_TIMEOUT, &nread, &eomReason);
COMM_TIMEOUT, &nread, &eomReason);
Debug(5, "bytes: 1st call: %d\t2nd call: %d\n", lenTemp, nread);
if ((status != asynSuccess) || (nread <= 0))
{
com[0] = '\0';
nread = 0;
com[0] = '\0';
nread = 0;
}
Debug(2, "recv_mess(): message = \"%s\"\n", com);
@@ -526,44 +525,44 @@ static int recv_mess(int card, char *com, int flag)
/* MVP2001Setup() */
/*****************************************************/
RTN_STATUS
MVP2001Setup(int num_cards, /* number of CHAINS of controllers */
int scan_rate) /* polling rate (Min=1Hz, max=60Hz) */
MVP2001Setup(int num_cards, /* number of CHAINS of controllers */
int scan_rate) /* polling rate (Min=1Hz, max=60Hz) */
{
if (num_cards < 1 || num_cards > MVP2001_NUM_CARDS)
MVP2001_num_cards = MVP2001_NUM_CARDS;
MVP2001_num_cards = MVP2001_NUM_CARDS;
else
MVP2001_num_cards = num_cards;
MVP2001_num_cards = num_cards;
/* Set motor polling task rate */
if (scan_rate >= 1 && scan_rate <= 60)
targs.motor_scan_rate = scan_rate;
targs.motor_scan_rate = scan_rate;
else
targs.motor_scan_rate = SCAN_RATE;
targs.motor_scan_rate = SCAN_RATE;
/*
/*
* Allocate space for motor_state structures. Note this must be done
* before MVP2001Config 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 **) calloc(MVP2001_num_cards,
sizeof(struct controller *));
sizeof(struct controller *));
return(OK);
}
/*******************************************************
* Configure a CHAIN of controllers *
* *
* Configure a CHAIN of controllers *
* *
* Note: Addresses of controllers on a chain must *
* begin at 1 and follow sequentially. *
* *
* MVP2001Config() *
* begin at 1 and follow sequentially. *
* *
* MVP2001Config() *
********************************************************/
RTN_STATUS
MVP2001Config(int card, /* CHAIN being configured */
const char *name) /* asyn server task name */
MVP2001Config(int card, /* CHAIN being configured */
const char *name) /* asyn server task name */
{
struct MVPcontroller *cntrl;
@@ -580,8 +579,8 @@ MVP2001Config(int card, /* CHAIN being configured */
/*****************************************************/
/* initialize all software and hardware */
/* motor_init() */
/* initialize all software and hardware */
/* motor_init() */
/*****************************************************/
static int motor_init()
{
@@ -597,124 +596,124 @@ static int motor_init()
buff[0] = limitStr[0] = '\0';
initialized = true; /* Indicate that driver is initialized. */
initialized = true; /* Indicate that driver is initialized. */
/* Check for setup */
if (MVP2001_num_cards <= 0)
return (ERROR);
return (ERROR);
for (card_index = 0; card_index < MVP2001_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; /* The MVP doesn't respond to every command */
total_cards = card_index + 1;
cntrl = (struct MVPcontroller *) brdptr->DevicePrivate;
if (!motor_state[card_index])
continue;
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port, 0,
&cntrl->pasynUser, NULL);
brdptr = motor_state[card_index];
brdptr->ident[0] = (char) NULL; /* No controller identification message. */
brdptr->cmnd_response = false; /* The MVP doesn't respond to every command */
total_cards = card_index + 1;
cntrl = (struct MVPcontroller *) brdptr->DevicePrivate;
if (success_rtn == asynSuccess)
{
pasynOctetSyncIO->setOutputEos(cntrl->pasynUser, output_terminator,
strlen(output_terminator));
pasynOctetSyncIO->setInputEos(cntrl->pasynUser, input_terminator,
strlen(input_terminator));
/* Send a message to the board, see if it exists */
for (total_axis = 0; total_axis < MAX_AXIS; total_axis++)
{
int retry = 0;
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port, 0,
&cntrl->pasynUser, NULL);
/* flush any junk at input port - should not be any data available */
do
recv_mess(card_index, buff, FLUSH);
while (strlen(buff) != 0);
if (success_rtn == asynSuccess)
{
pasynOctetSyncIO->setOutputEos(cntrl->pasynUser, output_terminator,
strlen(output_terminator));
pasynOctetSyncIO->setInputEos(cntrl->pasynUser, input_terminator,
strlen(input_terminator));
do
{
sprintf(buff, "%d ST", (total_axis + 1));
send_mess(card_index, buff, (char) NULL);
status = recv_mess(card_index, buff, 1);
retry++;
} while (status <= 0 && retry < 3);
if (status <= 0)
break;
}
brdptr->total_axis = total_axis;
Debug(5, "brdptr->total_axis (number of controllers on chain %d) = %d\n", card_index, brdptr->total_axis);
}
/* Send a message to the board, see if it exists */
for (total_axis = 0; total_axis < MAX_AXIS; total_axis++)
{
int retry = 0;
if (success_rtn == asynSuccess && total_axis > 0)
{
brdptr->localaddr = (char *) NULL;
brdptr->motor_in_motion = 0;
/* flush any junk at input port - should not be any data available */
do
recv_mess(card_index, buff, FLUSH);
while (strlen(buff) != 0);
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
do
{
sprintf(buff, "%d ST", (total_axis + 1));
send_mess(card_index, buff, (char) NULL);
status = recv_mess(card_index, buff, 1);
retry++;
} while (status <= 0 && retry < 3);
if (status <= 0)
break;
}
brdptr->total_axis = total_axis;
Debug(5, "brdptr->total_axis (number of controllers on chain %d) = %d\n", card_index, brdptr->total_axis);
}
/* stop and initialize the controller */
sprintf(buff, "%d V 0", (motor_index + 1));
send_mess(card_index, buff, (char) NULL);
sprintf(buff, "%d HO", (motor_index + 1));
send_mess(card_index, buff, (char) NULL);
sprintf(buff, "%d EN", (motor_index + 1));
send_mess(card_index, buff, (char) NULL);
if (success_rtn == asynSuccess && total_axis > 0)
{
brdptr->localaddr = (char *) NULL;
brdptr->motor_in_motion = 0;
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;
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
/* no encoder support for correct DC controller interaction */
motor_info->encoder_present = NO;
motor_info->status.Bits.EA_PRESENT = 0;
/* stop and initialize the controller */
sprintf(buff, "%d V 0", (motor_index + 1));
send_mess(card_index, buff, (char) NULL);
sprintf(buff, "%d HO", (motor_index + 1));
send_mess(card_index, buff, (char) NULL);
sprintf(buff, "%d EN", (motor_index + 1));
send_mess(card_index, buff, (char) NULL);
/* MVP2001 has PID capabilities */
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
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;
limitStr[0] = '\0';
/* Determine low limit */
sprintf(buff, "%d LL -", (motor_index + 1));
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
strncat(limitStr, &buff[5], 8);
motor_info->low_limit = (epicsInt32) strtoul(limitStr, NULL, 16);
/* no encoder support for correct DC controller interaction */
motor_info->encoder_present = NO;
motor_info->status.Bits.EA_PRESENT = 0;
limitStr[0] = '\0';
/* Determine high limit */
sprintf(buff, "%d LL", (motor_index + 1));
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
strncat(limitStr, &buff[5], 8);
motor_info->high_limit = (epicsInt32) strtoul(limitStr, NULL, 16);
}
/* MVP2001 has PID capabilities */
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
/*
* Ensure that the position is correctly set to zero so that auto_sr
* loads the saved positions. The task delay is necessary because
* sending the HO command too soon after the EN command results in
* reading back a position within ten encoder pulses away from zero.
*/
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
epicsThreadSleep(0.2);
limitStr[0] = '\0';
/* Determine low limit */
sprintf(buff, "%d LL -", (motor_index + 1));
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
strncat(limitStr, &buff[5], 8);
motor_info->low_limit = (epicsInt32) strtoul(limitStr, NULL, 16);
sprintf(buff, "%d HO", (motor_index + 1));
send_mess(card_index, buff, (char) NULL);
limitStr[0] = '\0';
/* Determine high limit */
sprintf(buff, "%d LL", (motor_index + 1));
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
strncat(limitStr, &buff[5], 8);
motor_info->high_limit = (epicsInt32) strtoul(limitStr, NULL, 16);
}
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
/*
* Ensure that the position is correctly set to zero so that auto_sr
* loads the saved positions. The task delay is necessary because
* sending the HO command too soon after the EN command results in
* reading back a position within ten encoder pulses away from zero.
*/
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
epicsThreadSleep(0.2);
sprintf(buff, "%d HO", (motor_index + 1));
send_mess(card_index, buff, (char) NULL);
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
}
any_motor_in_motion = 0;
@@ -726,9 +725,9 @@ static int motor_init()
free_list.tail = (struct mess_node *) NULL;
epicsThreadCreate((char *) "MVP2001_motor", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
return(0);
}
+229 -230
View File
@@ -1,16 +1,16 @@
/*
FILENAME... drvESP300.cc
USAGE... Motor record driver level support for Newport ESP300.
FILENAME... drvESP300.cc
USAGE... Motor record driver level support for Newport ESP300.
Version: $Revision: 1.18 $
Modified By: $Author: sluiter $
Last Modified: $Date: 2005-03-30 19:10:47 $
Version: $Revision: 1.19 $
Modified By: $Author: dkline $
Last Modified: $Date: 2005-04-14 18:52:47 $
*/
/*
* Original Author: Ron Sluiter
* Date: 02/19/03
* Current Author: Ron Sluiter
* Current Author: Ron Sluiter
*
* Experimental Physics and Industrial Control System (EPICS)
*
@@ -22,21 +22,21 @@ Last Modified: $Date: 2005-03-30 19:10:47 $
* 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
* 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
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
* .01 02-19-03 rls copied from drvMM3000
* .02 05-23-03 rls Converted to R3.14.x.
* .02 05-23-03 rls Converted to R3.14.x.
* .03 10-28-03 rls initialize "drive_resolution".
* .04 02-03-04 rls Eliminate erroneous "Motor motion timeout ERROR".
* .05 07/09/04 rls removed unused <driver>Setup() argument.
@@ -44,9 +44,9 @@ Last Modified: $Date: 2005-03-30 19:10:47 $
* .07 09/21/04 rls support for 32axes/controller.
* .08 12/21/04 rls - retry on initial communication.
* - using asyn's set[Out/In]putEos().
* - make debug variables always available.
* - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
* - make debug variables always available.
* - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
*/
@@ -60,21 +60,21 @@ Last Modified: $Date: 2005-03-30 19:10:47 $
#include "epicsExport.h"
#define READ_POSITION "%.2dTP"
#define STOP_AXIS "%.2dST"
#define STOP_AXIS "%.2dST"
#define GET_IDENT "VE?"
#define ESP300_NUM_CARDS 4
#define ESP300_NUM_CARDS 4
#define BUFF_SIZE 100 /* Maximum length of string to/from ESP300 */
/* The ESP300 does not respond for 2 to 5 seconds after hitting a travel limit. */
#define SERIAL_TIMEOUT 5.0 /* Command timeout in sec. */
#define SERIAL_TIMEOUT 5.0 /* Command timeout in sec. */
/*----------------debugging-----------------*/
#ifdef __GNUG__
#ifdef DEBUG
#define Debug(l, f, args...) { if(l<=drvESP300debug) printf(f,## args); }
#ifdef DEBUG
#define Debug(l, f, args...) { if(l<=drvESP300debug) printf(f,## args); }
#else
#define Debug(l, f, args...)
#define Debug(l, f, args...)
#endif
#else
#define Debug()
@@ -85,7 +85,7 @@ extern "C" {epicsExportAddress(int, drvESP300debug);}
int ESP300_num_cards = 0;
/* Local data required for every driver; see "motordrvComCode.h" */
#include "motordrvComCode.h"
#include "motordrvComCode.h"
/*----------------functions-----------------*/
static int recv_mess(int, char *, int);
@@ -146,25 +146,25 @@ static long report(int level)
int card;
if (ESP300_num_cards <=0)
printf(" No ESP300 controllers configured.\n");
printf(" No ESP300 controllers configured.\n");
else
{
for (card = 0; card < ESP300_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
for (card = 0; card < ESP300_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
if (brdptr == NULL)
printf(" ESP300 controller %d connection failed.\n", card);
else
{
struct MMcontroller *cntrl;
if (brdptr == NULL)
printf(" ESP300 controller %d connection failed.\n", card);
else
{
struct MMcontroller *cntrl;
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
printf(" ESP300 controller %d port=%s, address=%d, id: %s \n",
card, cntrl->asyn_port, cntrl->asyn_address,
brdptr->ident);
}
}
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
printf(" ESP300 controller %d port=%s, address=%d, id: %s \n",
card, cntrl->asyn_port, cntrl->asyn_address,
brdptr->ident);
}
}
}
return(OK);
}
@@ -172,7 +172,7 @@ static long report(int level)
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
@@ -181,7 +181,7 @@ static long init()
/* Check for setup */
if (ESP300_num_cards <= 0)
{
Debug(1, "init(): ESP300 driver disabled. ESP300Setup() missing from startup script.\n");
Debug(1, "init(): ESP300 driver disabled. ESP300Setup() missing from startup script.\n");
}
return((long) 0);
}
@@ -222,49 +222,49 @@ static int set_status(int card, int signal)
if (charcnt == 1 && (inbuff[0] == '0' || inbuff[0] == '1'))
{
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 0;
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 0;
}
else
{
if (cntrl->status == NORMAL)
{
cntrl->status = RETRY;
rtn_state = 0;
goto exit;
}
else
{
cntrl->status = COMM_ERR;
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
if (cntrl->status == NORMAL)
{
cntrl->status = RETRY;
rtn_state = 0;
goto exit;
}
else
{
cntrl->status = COMM_ERR;
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
}
status.Bits.RA_DONE = (inbuff[0] == '1') ? 1 : 0;
/* Get motor position. */
sprintf(outbuff, READ_POSITION, signal + 1);
send_mess(card, outbuff, (char) NULL);
charcnt = recv_mess(card, inbuff, 1);
motorData = atof(inbuff) / cntrl->drive_resolution[signal];
if (motorData == motor_info->position)
{
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
}
else
{
epicsInt32 newposition;
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;
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;
@@ -276,29 +276,29 @@ static int set_status(int card, int signal)
cptr = strchr(inbuff, 'H');
if (cptr == NULL)
{
Debug(2, "set_status(): PH error = %s\n", inbuff);
rtn_state = 1;
goto exit;
Debug(2, "set_status(): PH error = %s\n", inbuff);
rtn_state = 1;
goto exit;
}
mstatus = strtol(inbuff, &cptr, 16);
/* Set Travel limit switch status bits. */
if (((mstatus >> signal) & 0x01) == false)
status.Bits.RA_PLUS_LS = 0;
status.Bits.RA_PLUS_LS = 0;
else
{
status.Bits.RA_PLUS_LS = 1;
if (plusdir == true)
ls_active = true;
status.Bits.RA_PLUS_LS = 1;
if (plusdir == true)
ls_active = true;
}
if (((mstatus >> (signal + 8)) & 0x01) == false)
status.Bits.RA_MINUS_LS = 0;
status.Bits.RA_MINUS_LS = 0;
else
{
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
}
/* Set home switch status. */
@@ -317,10 +317,10 @@ static int set_status(int card, int signal)
status.Bits.EA_POSITION = (power == true) ? 1 : 0;
/* encoder status */
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP_STALL = 0;
status.Bits.EA_HOME = 0;
status.Bits.RA_PROBLEM = 0;
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP_STALL = 0;
status.Bits.EA_HOME = 0;
status.Bits.RA_PROBLEM = 0;
/* Parse motor velocity? */
/* NEEDS WORK */
@@ -328,18 +328,18 @@ static int set_status(int card, int signal)
motor_info->velocity = 0;
if (!status.Bits.RA_DIRECTION)
motor_info->velocity *= -1;
motor_info->velocity *= -1;
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
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)
nodeptr->postmsgptr != 0)
{
strcpy(outbuff, nodeptr->postmsgptr);
send_mess(card, outbuff, (char) NULL);
nodeptr->postmsgptr = NULL;
strcpy(outbuff, nodeptr->postmsgptr);
send_mess(card, outbuff, (char) NULL);
nodeptr->postmsgptr = NULL;
}
exit:
@@ -349,44 +349,43 @@ exit:
/*****************************************************/
/* send a message to the ESP300 board */
/* send_mess() */
/* send a message to the ESP300 board */
/* send_mess() */
/*****************************************************/
static RTN_STATUS send_mess(int card, char const *com, char *name)
{
struct MMcontroller *cntrl;
int size;
int nwrite;
size_t nwrite;
size = strlen(com);
if (size > MAX_MSG_SIZE)
{
errlogMessage("drvESP300:send_mess(); message size violation.\n");
return(ERROR);
errlogMessage("drvESP300:send_mess(); message size violation.\n");
return(ERROR);
}
else if (size == 0) /* Normal exit on empty input message. */
return(OK);
else if (size == 0) /* Normal exit on empty input message. */
return(OK);
if (!motor_state[card])
{
errlogPrintf("drvESP300:send_mess() - invalid card #%d\n", card);
return(ERROR);
errlogPrintf("drvESP300:send_mess() - invalid card #%d\n", card);
return(ERROR);
}
if (name != NULL)
{
errlogPrintf("drvESP300:send_mess() - invalid argument = %s\n", name);
return(ERROR);
errlogPrintf("drvESP300:send_mess() - invalid argument = %s\n", name);
return(ERROR);
}
Debug(2, "send_mess(): message = %s\n", com);
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
pasynOctetSyncIO->write(cntrl->pasynUser, com, strlen(com),
SERIAL_TIMEOUT, &nwrite);
pasynOctetSyncIO->write(cntrl->pasynUser, com, strlen(com), SERIAL_TIMEOUT, &nwrite);
return(OK);
}
@@ -395,42 +394,42 @@ static RTN_STATUS send_mess(int card, char const *com, char *name)
* FUNCTION... recv_mess(int card, char *com, int flag)
*
* INPUT ARGUMENTS...
* card - controller card # (0,1,...).
* *com - caller's response buffer.
* flag | FLUSH = flush controller's output buffer; set timeout = 0.
* | !FLUSH = retrieve response into caller's buffer; set timeout.
* card - controller card # (0,1,...).
* *com - caller's response buffer.
* flag | FLUSH = flush controller's output buffer; set timeout = 0.
* | !FLUSH = retrieve response into caller's buffer; set timeout.
*
* LOGIC...
* Initialize:
* - receive timeout to zero
* - received string length to zero.
* - receive timeout to zero
* - received string length to zero.
*
* IF controller card does not exist.
* ERROR RETURN.
* ERROR RETURN.
* ENDIF
*
* SWITCH on port type.
* CASE port type is GPIB.
* BREAK.
* CASE port type is RS232.
* IF input "flag" indicates NOT flushing the input buffer.
* Set receive timeout nonzero.
* ENDIF
* Call pasynOctetSyncIO->read().
* CASE port type is GPIB.
* BREAK.
* CASE port type is RS232.
* IF input "flag" indicates NOT flushing the input buffer.
* Set receive timeout nonzero.
* ENDIF
* Call pasynOctetSyncIO->read().
*
* NOTE: The ESP300 sometimes responds to an MS command with an error
* message (see ESP300 User's Manual Appendix A). This is an
* unconfirmed ESP300 bug. Retry read if this is a Hard Travel
* limit switch error. This effectively flushes the error message.
* NOTE: The ESP300 sometimes responds to an MS command with an error
* message (see ESP300 User's Manual Appendix A). This is an
* unconfirmed ESP300 bug. Retry read if this is a Hard Travel
* limit switch error. This effectively flushes the error message.
*
* IF input "com" buffer length is > 3 characters, AND, the 1st
* character is an "E" (Maybe this an unsolicited error
* message response?).
* Call pasynOctetSyncIO->read().
* ENDIF
* BREAK
* IF input "com" buffer length is > 3 characters, AND, the 1st
* character is an "E" (Maybe this an unsolicited error
* message response?).
* Call pasynOctetSyncIO->read().
* ENDIF
* BREAK
* ENDSWITCH
*
*
* NORMAL RETURN.
*/
@@ -439,39 +438,39 @@ static int recv_mess(int card, char *com, int flag)
struct MMcontroller *cntrl;
double timeout = 0.;
int flush = 1;
int nread = 0;
size_t nread = 0;
asynStatus status;
int eomReason;
/* Check that card exists */
if (!motor_state[card])
return(ERROR);
return(ERROR);
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
if (flag != FLUSH) {
flush = 0;
timeout = SERIAL_TIMEOUT;
timeout = SERIAL_TIMEOUT;
}
if (flush) status = pasynOctetSyncIO->flush(cntrl->pasynUser);
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
timeout, &nread, &eomReason);
if (nread > 3 && com[0] == 'E')
{
long error;
long error;
error = strtol(&com[1], NULL, 0);
if (error >= 35 && error <= 42) {
error = strtol(&com[1], NULL, 0);
if (error >= 35 && error <= 42) {
if (flush) status = pasynOctetSyncIO->flush(cntrl->pasynUser);
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
timeout, &nread, &eomReason);
}
}
if ((status != asynSuccess) || (nread <= 0))
{
com[0] = '\0';
nread = 0;
com[0] = '\0';
nread = 0;
}
Debug(2, "recv_mess(): message = \"%s\"\n", com);
@@ -484,33 +483,33 @@ static int recv_mess(int card, char *com, int flag)
/* ESP300Setup() */
/*****************************************************/
RTN_STATUS
ESP300Setup(int num_cards, /* maximum number of controllers in system. */
int scan_rate) /* polling rate - 1/60 sec units. */
ESP300Setup(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 > ESP300_NUM_CARDS)
ESP300_num_cards = ESP300_NUM_CARDS;
ESP300_num_cards = ESP300_NUM_CARDS;
else
ESP300_num_cards = num_cards;
ESP300_num_cards = num_cards;
/* Set motor polling task rate */
if (scan_rate >= 1 && scan_rate <= 60)
targs.motor_scan_rate = scan_rate;
targs.motor_scan_rate = scan_rate;
else
targs.motor_scan_rate = SCAN_RATE;
targs.motor_scan_rate = SCAN_RATE;
/*
/*
* Allocate space for motor_state structures. Note this must be done
* before ESP300Config 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(ESP300_num_cards *
sizeof(struct controller *));
sizeof(struct controller *));
for (itera = 0; itera < ESP300_num_cards; itera++)
motor_state[itera] = (struct controller *) NULL;
motor_state[itera] = (struct controller *) NULL;
return(OK);
}
@@ -521,7 +520,7 @@ ESP300Setup(int num_cards, /* maximum number of controllers in system. */
/* ESP300Config() */
/*****************************************************/
RTN_STATUS
ESP300Config(int card, /* card being configured */
ESP300Config(int card, /* card being configured */
const char *name, /* asyn port name */
int address) /* asyn address (GPIB) */
{
@@ -542,10 +541,10 @@ ESP300Config(int card, /* card being configured */
/*****************************************************/
/* initialize all software and hardware */
/* initialize all software and hardware */
/* This is called from the initialization routine in */
/* device support. */
/* motor_init() */
/* motor_init() */
/*****************************************************/
static int motor_init()
{
@@ -559,100 +558,100 @@ static int motor_init()
static const char output_terminator[] = "\r";
static const char input_terminator[] = "\r\n";
initialized = true; /* Indicate that driver is initialized. */
initialized = true; /* Indicate that driver is initialized. */
/* Check for setup */
if (ESP300_num_cards <= 0)
return(ERROR);
return(ERROR);
for (card_index = 0; card_index < ESP300_num_cards; card_index++)
{
if (!motor_state[card_index])
continue;
if (!motor_state[card_index])
continue;
brdptr = motor_state[card_index];
brdptr->cmnd_response = false;
total_cards = card_index + 1;
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
brdptr = motor_state[card_index];
brdptr->cmnd_response = false;
total_cards = card_index + 1;
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port,
cntrl->asyn_address, &cntrl->pasynUser, NULL);
pasynOctetSyncIO->setOutputEos(cntrl->pasynUser, output_terminator,
strlen(output_terminator));
pasynOctetSyncIO->setInputEos(cntrl->pasynUser, input_terminator,
strlen(input_terminator));
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port,
cntrl->asyn_address, &cntrl->pasynUser, NULL);
pasynOctetSyncIO->setOutputEos(cntrl->pasynUser, output_terminator,
strlen(output_terminator));
pasynOctetSyncIO->setInputEos(cntrl->pasynUser, input_terminator,
strlen(input_terminator));
if (success_rtn == asynSuccess)
{
int retry = 0;
/* Send a message to the board, see if it exists */
/* flush any junk at input port - should not be any data available */
if (success_rtn == asynSuccess)
{
int retry = 0;
/* 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);
do
{
send_mess(card_index, GET_IDENT, (char) NULL);
status = recv_mess(card_index, buff, 1);
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;
strcpy(brdptr->ident, &buff[1]); /* Skip "\n" */
do
{
send_mess(card_index, GET_IDENT, (char) NULL);
status = recv_mess(card_index, buff, 1);
retry++;
/* Return value is length of response string */
} while (status == 0 && retry < 3);
}
send_mess(card_index, "ZU", (char) NULL);
recv_mess(card_index, buff, 1);
total_axis = buff[0] >> 4;
if (total_axis > 4)
{
Debug(2, "motor_init(): ZU = %s\n", buff);
total_axis = 4;
}
if (success_rtn == asynSuccess && status > 0)
{
brdptr->localaddr = (char *) NULL;
brdptr->motor_in_motion = 0;
strcpy(brdptr->ident, &buff[1]); /* Skip "\n" */
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
sprintf(buff, STOP_AXIS, motor_index + 1); /* Stop motor */
send_mess(card_index, buff, (char) NULL);
/* Initialize. */
brdptr->motor_info[motor_index].motor_motion = NULL;
}
send_mess(card_index, "ZU", (char) NULL);
recv_mess(card_index, buff, 1);
total_axis = buff[0] >> 4;
if (total_axis > 4)
{
Debug(2, "motor_init(): ZU = %s\n", buff);
total_axis = 4;
}
brdptr->total_axis = total_axis;
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
sprintf(buff, STOP_AXIS, motor_index + 1); /* Stop motor */
send_mess(card_index, buff, (char) NULL);
/* Initialize. */
brdptr->motor_info[motor_index].motor_motion = NULL;
}
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
brdptr->total_axis = total_axis;
/* Set axis resolution. */
sprintf(buff, "%.2dSU?", motor_index + 1);
send_mess(card_index, buff, 0);
recv_mess(card_index, buff, 1);
cntrl->drive_resolution[motor_index] = atof(&buff[0]);
motor_info->status.All = 0;
motor_info->no_motion_count = 0;
motor_info->encoder_position = 0;
motor_info->position = 0;
motor_info->encoder_present = YES;
if (motor_info->encoder_present == YES)
{
motor_info->status.Bits.EA_PRESENT = 1;
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
}
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
/* Set axis resolution. */
sprintf(buff, "%.2dSU?", motor_index + 1);
send_mess(card_index, buff, 0);
recv_mess(card_index, buff, 1);
cntrl->drive_resolution[motor_index] = atof(&buff[0]);
motor_info->status.All = 0;
motor_info->no_motion_count = 0;
motor_info->encoder_position = 0;
motor_info->position = 0;
motor_info->encoder_present = YES;
if (motor_info->encoder_present == YES)
{
motor_info->status.Bits.EA_PRESENT = 1;
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
}
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
}
any_motor_in_motion = 0;
@@ -664,8 +663,8 @@ static int motor_init()
free_list.tail = (struct mess_node *) NULL;
epicsThreadCreate((char *) "ESP300_motor", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
return(OK);
}
+263 -264
View File
@@ -1,16 +1,16 @@
/*
FILENAME... drvMM3000.cc
USAGE... Motor record driver level support for Newport MM3000.
FILENAME... drvMM3000.cc
USAGE... Motor record driver level support for Newport MM3000.
Version: $Revision: 1.17 $
Modified By: $Author: sluiter $
Last Modified: $Date: 2005-03-30 19:10:48 $
Version: $Revision: 1.18 $
Modified By: $Author: dkline $
Last Modified: $Date: 2005-04-14 18:52:47 $
*/
/*
* Original Author: Mark Rivers
* Date: 10/20/97
* Current Author: Ron Sluiter
* Current Author: Ron Sluiter
*
* Experimental Physics and Industrial Control System (EPICS)
*
@@ -22,16 +22,16 @@ Last Modified: $Date: 2005-03-30 19:10:48 $
* 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
* 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
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
@@ -39,26 +39,26 @@ Last Modified: $Date: 2005-03-30 19:10:48 $
* .02 10-30-97 mlr Replaced driver calls with gpipIO functions
* .03 10-30-98 mlr Minor code cleanup, improved formatting
* .04 02-01-99 mlr Added temporary fix to delay reading motor positions at
* the end of a move.
* the end of a move.
* .05 04-18-00 rls MM3000 takes 2 to 5 seconds to respond to queries after
* hitting a hard travel limit. Adjusted GPIB and SERIAL
* timeouts accordingly. Deleted communication retries.
* Reworked travel limit processing so that direction
* status bit matches limit switch. Copied recv_mess()
* logic from drvMM4000.c. Use TPE command to determine
* if motor has an encoder.
* hitting a hard travel limit. Adjusted GPIB and SERIAL
* timeouts accordingly. Deleted communication retries.
* Reworked travel limit processing so that direction
* status bit matches limit switch. Copied recv_mess()
* logic from drvMM4000.c. Use TPE command to determine
* if motor has an encoder.
* .06 10/02/01 rls - allow one retry after a communication error.
* - use motor status response bit-field.
* .07 05-22-03 rls - Converted to R3.14.2.
* - use motor status response bit-field.
* .07 05-22-03 rls - Converted to R3.14.2.
* .08 10/23/03 rls - recv_mess() eats the controller error response, outputs
* an error message and retries.
* an error message and retries.
* .09 02/03/04 rls - Eliminate erroneous "Motor motion timeout ERROR".
* .10 07/09/04 rls - removed unused <driver>Setup() argument.
* .11 07/28/04 rls - "epicsExport" debug variable.
* .12 09/21/04 rls - support for 32axes/controller.
* .13 12/21/04 rls - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
* - make debug variables always available.
* extern "C" linkage.
* - make debug variables always available.
*
*/
@@ -89,18 +89,18 @@ Last Modified: $Date: 2005-03-30 19:10:48 $
#define M_MINUS_LIMIT 0x10
#define M_HOME_SIGNAL 0x20
#define MM3000_NUM_CARDS 4
#define MM3000_NUM_CARDS 4
#define BUFF_SIZE 100 /* Maximum length of string to/from MM3000 */
/* The MM3000 does not respond for 2 to 5 seconds after hitting a travel limit. */
#define SERIAL_TIMEOUT 5.0 /* Command timeout in sec. */
#define SERIAL_TIMEOUT 5.0 /* Command timeout in sec. */
/*----------------debugging-----------------*/
#ifdef __GNUG__
#ifdef DEBUG
#define Debug(l, f, args...) { if(l<=drvMM3000debug) printf(f,## args); }
#ifdef DEBUG
#define Debug(l, f, args...) { if(l<=drvMM3000debug) printf(f,## args); }
#else
#define Debug(l, f, args...)
#define Debug(l, f, args...)
#endif
#else
#define Debug()
@@ -112,7 +112,7 @@ extern "C" {epicsExportAddress(int, drvMM3000debug);}
int MM3000_num_cards = 0;
/* Local data required for every driver; see "motordrvComCode.h" */
#include "motordrvComCode.h"
#include "motordrvComCode.h"
/*----------------functions-----------------*/
STATIC int recv_mess(int, char *, int);
@@ -168,26 +168,26 @@ static long report(int level)
int card;
if (MM3000_num_cards <=0)
printf(" No MM3000 controllers configured.\n");
printf(" No MM3000 controllers configured.\n");
else
{
for (card = 0; card < MM3000_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
for (card = 0; card < MM3000_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
if (brdptr == NULL)
printf(" MM3000 controller %d connection failed.\n", card);
else
{
struct MMcontroller *cntrl;
if (brdptr == NULL)
printf(" MM3000 controller %d connection failed.\n", card);
else
{
struct MMcontroller *cntrl;
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
printf(" MM3000 controller %d asyn port= %s, address=%d, id: %s \n",
card, cntrl->asyn_port, cntrl->asyn_address,
brdptr->ident);
break;
}
}
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
printf(" MM3000 controller %d asyn port= %s, address=%d, id: %s \n",
card, cntrl->asyn_port, cntrl->asyn_address,
brdptr->ident);
break;
}
}
}
return(OK);
}
@@ -195,7 +195,7 @@ static long report(int level)
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
@@ -204,7 +204,7 @@ static long init()
/* Check for setup */
if (MM3000_num_cards <= 0)
{
Debug(1, "init(): MM3000 driver disabled. MM3000Setup() missing from startup script.\n");
Debug(1, "init(): MM3000 driver disabled. MM3000Setup() missing from startup script.\n");
}
return((long) 0);
}
@@ -243,25 +243,25 @@ STATIC int set_status(int card, int signal)
charcnt = recv_mess(card, inbuff, 1);
if (charcnt > 0)
{
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 0;
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 0;
}
else
{
if (cntrl->status == NORMAL)
{
cntrl->status = RETRY;
rtn_state = 0;
goto exit;
}
else
{
cntrl->status = COMM_ERR;
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
if (cntrl->status == NORMAL)
{
cntrl->status = RETRY;
rtn_state = 0;
goto exit;
}
else
{
cntrl->status = COMM_ERR;
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
}
mstat.All = inbuff[0];
@@ -277,21 +277,21 @@ STATIC int set_status(int card, int signal)
/* Set Travel limit switch status bits. */
if (mstat.Bits.plustTL == false)
status.Bits.RA_PLUS_LS = 0;
status.Bits.RA_PLUS_LS = 0;
else
{
status.Bits.RA_PLUS_LS = 1;
if (plusdir == true)
ls_active = true;
status.Bits.RA_PLUS_LS = 1;
if (plusdir == true)
ls_active = true;
}
if (mstat.Bits.minusTL == false)
status.Bits.RA_MINUS_LS = 0;
status.Bits.RA_MINUS_LS = 0;
else
{
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
}
status.Bits.RA_HOME = (mstat.Bits.homels == false) ? 0 : 1;
@@ -299,34 +299,34 @@ STATIC int set_status(int card, int signal)
status.Bits.EA_POSITION = (mstat.Bits.NOT_power == false) ? 1 : 0;
/* encoder status */
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP_STALL = 0;
status.Bits.EA_HOME = 0;
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP_STALL = 0;
status.Bits.EA_HOME = 0;
sprintf(outbuff, "%dTP", signal + 1);
send_mess(card, outbuff, (char) NULL);
charcnt = recv_mess(card, inbuff, 1);
if (charcnt > 0)
{
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 0;
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 0;
}
else
{
if (cntrl->status == NORMAL)
{
cntrl->status = RETRY;
rtn_state = 0;
goto exit;
}
else
{
cntrl->status = COMM_ERR;
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
if (cntrl->status == NORMAL)
{
cntrl->status = RETRY;
rtn_state = 0;
goto exit;
}
else
{
cntrl->status = COMM_ERR;
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
}
tok_save = NULL;
@@ -335,18 +335,18 @@ STATIC int set_status(int card, int signal)
if (motorData == motor_info->position)
{
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
}
else
{
motor_info->position = (epicsInt32) motorData;
if (motor_state[card]->motor_info[signal].encoder_present == YES)
motor_info->encoder_position = (epicsInt32) motorData;
else
motor_info->encoder_position = 0;
motor_info->position = (epicsInt32) motorData;
if (motor_state[card]->motor_info[signal].encoder_present == YES)
motor_info->encoder_position = (epicsInt32) motorData;
else
motor_info->encoder_position = 0;
motor_info->no_motion_count = 0;
motor_info->no_motion_count = 0;
}
status.Bits.RA_PROBLEM = 0;
@@ -357,18 +357,18 @@ STATIC int set_status(int card, int signal)
motor_info->velocity = 0;
if (!status.Bits.RA_DIRECTION)
motor_info->velocity *= -1;
motor_info->velocity *= -1;
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
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)
nodeptr->postmsgptr != 0)
{
strcpy(outbuff, nodeptr->postmsgptr);
send_mess(card, outbuff, (char) NULL);
nodeptr->postmsgptr = NULL;
strcpy(outbuff, nodeptr->postmsgptr);
send_mess(card, outbuff, (char) NULL);
nodeptr->postmsgptr = NULL;
}
exit:
@@ -378,44 +378,43 @@ exit:
/*****************************************************/
/* send a message to the MM3000 board */
/* send_mess() */
/* send a message to the MM3000 board */
/* send_mess() */
/*****************************************************/
STATIC RTN_STATUS send_mess(int card, char const *com, char *name)
{
struct MMcontroller *cntrl;
int size;
int nwrite;
size_t nwrite;
size = strlen(com);
if (size > MAX_MSG_SIZE)
{
errlogMessage("drvMM3000:send_mess(); message size violation.\n");
return(ERROR);
errlogMessage("drvMM3000:send_mess(); message size violation.\n");
return(ERROR);
}
else if (size == 0) /* Normal exit on empty input message. */
return(OK);
else if (size == 0) /* Normal exit on empty input message. */
return(OK);
if (!motor_state[card])
{
errlogPrintf("drvMM3000:send_mess() - invalid card #%d\n", card);
return(ERROR);
errlogPrintf("drvMM3000:send_mess() - invalid card #%d\n", card);
return(ERROR);
}
if (name != NULL)
{
errlogPrintf("drvMM3000:send_mess() - invalid argument = %s\n", name);
return(ERROR);
errlogPrintf("drvMM3000:send_mess() - invalid argument = %s\n", name);
return(ERROR);
}
Debug(2, "send_mess(): message = %s\n", com);
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
pasynOctetSyncIO->write(cntrl->pasynUser, com, strlen(com),
SERIAL_TIMEOUT, &nwrite);
pasynOctetSyncIO->write(cntrl->pasynUser, com, strlen(com), SERIAL_TIMEOUT, &nwrite);
return(OK);
}
@@ -424,42 +423,42 @@ STATIC RTN_STATUS send_mess(int card, char const *com, char *name)
* FUNCTION... recv_mess(int card, char *com, int flag)
*
* INPUT ARGUMENTS...
* card - controller card # (0,1,...).
* *com - caller's response buffer.
* flag | FLUSH = flush controller's output buffer; set timeout = 0.
* | !FLUSH = retrieve response into caller's buffer; set timeout.
* card - controller card # (0,1,...).
* *com - caller's response buffer.
* flag | FLUSH = flush controller's output buffer; set timeout = 0.
* | !FLUSH = retrieve response into caller's buffer; set timeout.
*
* LOGIC...
* Initialize:
* - receive timeout to zero
* - received string length to zero.
* - receive timeout to zero
* - received string length to zero.
*
* IF controller card does not exist.
* ERROR RETURN.
* ERROR RETURN.
* ENDIF
*
* SWITCH on port type.
* CASE port type is GPIB.
* BREAK.
* CASE port type is RS232.
* IF input "flag" indicates NOT flushing the input buffer.
* Set receive timeout nonzero.
* ENDIF
* Call pasynOctetSyncIO->read().
* CASE port type is GPIB.
* BREAK.
* CASE port type is RS232.
* IF input "flag" indicates NOT flushing the input buffer.
* Set receive timeout nonzero.
* ENDIF
* Call pasynOctetSyncIO->read().
*
* NOTE: The MM3000 sometimes responds to an MS command with an error
* message (see MM3000 User's Manual Appendix A). This is an
* unconfirmed MM3000 bug. Retry read if this is a Hard Travel
* limit switch error. This effectively flushes the error message.
* NOTE: The MM3000 sometimes responds to an MS command with an error
* message (see MM3000 User's Manual Appendix A). This is an
* unconfirmed MM3000 bug. Retry read if this is a Hard Travel
* limit switch error. This effectively flushes the error message.
*
* IF input "com" buffer length is > 3 characters, AND, the 1st
* character is an "E" (Maybe this an unsolicited error
* message response?).
* Call pasynOctetSyncIO->read().
* ENDIF
* BREAK
* IF input "com" buffer length is > 3 characters, AND, the 1st
* character is an "E" (Maybe this an unsolicited error
* message response?).
* Call pasynOctetSyncIO->read().
* ENDIF
* BREAK
* ENDSWITCH
*
*
* NORMAL RETURN.
*/
@@ -468,48 +467,48 @@ STATIC int recv_mess(int card, char *com, int flag)
struct MMcontroller *cntrl;
double timeout = 0.;
int flush = 1;
int nread = 0;
size_t nread = 0;
int eomReason;
asynStatus status;
/* Check that card exists */
if (!motor_state[card])
return(ERROR);
return(ERROR);
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
if (flag != FLUSH) {
flush = 0;
timeout = SERIAL_TIMEOUT;
timeout = SERIAL_TIMEOUT;
}
if (flush) status = pasynOctetSyncIO->flush(cntrl->pasynUser);
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
timeout, &nread, &eomReason);
if (nread > 3 && com[0] == 'E')
{
long error;
long error;
error = strtol(&com[1], NULL, 0);
if (error >= 35 && error <= 42) {
error = strtol(&com[1], NULL, 0);
if (error >= 35 && error <= 42) {
if (flush) status = pasynOctetSyncIO->flush(cntrl->pasynUser);
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
timeout, &nread, &eomReason);
}
}
if ((status != asynSuccess) || (nread <= 0))
{
com[0] = '\0';
nread = 0;
com[0] = '\0';
nread = 0;
}
else
{
/* Test for "system error" response. */
if (com[0] == 'E')
{
errPrintf( -1, __FILE__, __LINE__, "%s\n", com);
return(recv_mess(card, com, flag));
}
/* Test for "system error" response. */
if (com[0] == 'E')
{
errPrintf( -1, __FILE__, __LINE__, "%s\n", com);
return(recv_mess(card, com, flag));
}
}
Debug(2, "recv_mess(): message = \"%s\"\n", com);
@@ -522,33 +521,33 @@ STATIC int recv_mess(int card, char *com, int flag)
/* MM3000Setup() */
/*****************************************************/
RTN_STATUS
MM3000Setup(int num_cards, /* maximum number of controllers in system. */
int scan_rate) /* polling rate - 1/60 sec units. */
MM3000Setup(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 > MM3000_NUM_CARDS)
MM3000_num_cards = MM3000_NUM_CARDS;
MM3000_num_cards = MM3000_NUM_CARDS;
else
MM3000_num_cards = num_cards;
MM3000_num_cards = num_cards;
/* Set motor polling task rate */
if (scan_rate >= 1 && scan_rate <= 60)
targs.motor_scan_rate = scan_rate;
targs.motor_scan_rate = scan_rate;
else
targs.motor_scan_rate = SCAN_RATE;
targs.motor_scan_rate = SCAN_RATE;
/*
/*
* Allocate space for motor_state structures. Note this must be done
* before MM3000Config 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(MM3000_num_cards *
sizeof(struct controller *));
sizeof(struct controller *));
for (itera = 0; itera < MM3000_num_cards; itera++)
motor_state[itera] = (struct controller *) NULL;
motor_state[itera] = (struct controller *) NULL;
return(OK);
}
@@ -559,7 +558,7 @@ MM3000Setup(int num_cards, /* maximum number of controllers in system. */
/* MM3000Config() */
/*****************************************************/
RTN_STATUS
MM3000Config(int card, /* card being configured */
MM3000Config(int card, /* card being configured */
const char *port, /* asyn port name */
int address) /* asyn address (GPIB) */
{
@@ -580,10 +579,10 @@ MM3000Config(int card, /* card being configured */
/*****************************************************/
/* initialize all software and hardware */
/* initialize all software and hardware */
/* This is called from the initialization routine in */
/* device support. */
/* motor_init() */
/* motor_init() */
/*****************************************************/
STATIC int motor_init()
{
@@ -597,115 +596,115 @@ STATIC int motor_init()
int status=0;
asynStatus success_rtn;
initialized = true; /* Indicate that driver is initialized. */
initialized = true; /* Indicate that driver is initialized. */
/* Check for setup */
if (MM3000_num_cards <= 0)
return(ERROR);
return(ERROR);
tok_save = NULL;
for (card_index = 0; card_index < MM3000_num_cards; card_index++)
{
if (!motor_state[card_index])
continue;
if (!motor_state[card_index])
continue;
brdptr = motor_state[card_index];
brdptr->cmnd_response = false;
total_cards = card_index + 1;
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
brdptr = motor_state[card_index];
brdptr->cmnd_response = false;
total_cards = card_index + 1;
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port,
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port,
cntrl->asyn_address, &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);
send_mess(card_index, GET_IDENT, (char) NULL);
status = recv_mess(card_index, axis_pos, 1);
/* Return value is length of response string */
}
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);
if (success_rtn == asynSuccess && status > 0)
{
brdptr->localaddr = (char *) NULL;
brdptr->motor_in_motion = 0;
send_mess(card_index, STOP_ALL, (char) NULL); /* Stop all motors */
send_mess(card_index, GET_IDENT, (char) NULL); /* Read controller ID string */
recv_mess(card_index, buff, 1);
strncpy(brdptr->ident, &buff[0], MAX_IDENT_LEN); /* Skip "VE" */
send_mess(card_index, GET_IDENT, (char) NULL);
status = recv_mess(card_index, axis_pos, 1);
/* Return value is length of response string */
}
send_mess(card_index, "RC", (char) NULL);
recv_mess(card_index, buff, 1);
bufptr = strtok_r(buff, "=", &tok_save);
bufptr = strtok_r(NULL, " ", &tok_save);
if (success_rtn == asynSuccess && status > 0)
{
brdptr->localaddr = (char *) NULL;
brdptr->motor_in_motion = 0;
send_mess(card_index, STOP_ALL, (char) NULL); /* Stop all motors */
send_mess(card_index, GET_IDENT, (char) NULL); /* Read controller ID string */
recv_mess(card_index, buff, 1);
strncpy(brdptr->ident, &buff[0], MAX_IDENT_LEN); /* Skip "VE" */
/* The return string will tell us how many axes this controller has */
for (total_axis = 0; bufptr != NULL; total_axis++)
{
if (strcmp(bufptr, "unused") == 0)
{
cntrl->type[total_axis] = UNUSED;
bufptr = NULL;
}
else
{
if (strcmp(bufptr, "stepper1.5M") == 0)
cntrl->type[total_axis] = STEPPER;
else if (strcmp(bufptr, "dc") == 0)
cntrl->type[total_axis] = DC;
else
errlogPrintf("drvMM3000:motor_init() - invalid RC response = %s\n",
bufptr);
send_mess(card_index, "RC", (char) NULL);
recv_mess(card_index, buff, 1);
bufptr = strtok_r(buff, "=", &tok_save);
bufptr = strtok_r(NULL, " ", &tok_save);
bufptr = strtok_r(NULL, "=", &tok_save);
bufptr = strtok_r(NULL, " ", &tok_save);
}
/* The return string will tell us how many axes this controller has */
for (total_axis = 0; bufptr != NULL; total_axis++)
{
if (strcmp(bufptr, "unused") == 0)
{
cntrl->type[total_axis] = UNUSED;
bufptr = NULL;
}
else
{
if (strcmp(bufptr, "stepper1.5M") == 0)
cntrl->type[total_axis] = STEPPER;
else if (strcmp(bufptr, "dc") == 0)
cntrl->type[total_axis] = DC;
else
errlogPrintf("drvMM3000:motor_init() - invalid RC response = %s\n",
bufptr);
/* Initialize. */
brdptr->motor_info[total_axis].motor_motion = NULL;
}
bufptr = strtok_r(NULL, "=", &tok_save);
bufptr = strtok_r(NULL, " ", &tok_save);
}
brdptr->total_axis = total_axis;
/* Initialize. */
brdptr->motor_info[total_axis].motor_motion = NULL;
}
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
brdptr->total_axis = total_axis;
motor_info->status.All = 0;
motor_info->no_motion_count = 0;
motor_info->encoder_position = 0;
motor_info->position = 0;
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
if (cntrl->type[total_axis] == DC)
motor_info->encoder_present = YES;
else
{
sprintf(buff, "%dTPE", motor_index + 1);
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
motor_info->status.All = 0;
motor_info->no_motion_count = 0;
motor_info->encoder_position = 0;
motor_info->position = 0;
if (strcmp(buff, "E01") == 0)
motor_info->encoder_present = NO;
else
motor_info->encoder_present = YES;
}
if (motor_info->encoder_present == YES)
{
motor_info->status.Bits.EA_PRESENT = 1;
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
}
if (cntrl->type[total_axis] == DC)
motor_info->encoder_present = YES;
else
{
sprintf(buff, "%dTPE", motor_index + 1);
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
if (strcmp(buff, "E01") == 0)
motor_info->encoder_present = NO;
else
motor_info->encoder_present = YES;
}
if (motor_info->encoder_present == YES)
{
motor_info->status.Bits.EA_PRESENT = 1;
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
}
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
}
any_motor_in_motion = 0;
@@ -717,8 +716,8 @@ STATIC int motor_init()
free_list.tail = (struct mess_node *) NULL;
epicsThreadCreate((char *) "MM3000_motor", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
return(OK);
}
+279 -280
View File
@@ -1,16 +1,16 @@
/*
FILENAME... drvMM4000.cc
USAGE... Motor record driver level support for Newport MM4000.
FILENAME... drvMM4000.cc
USAGE... Motor record driver level support for Newport MM4000.
Version: $Revision: 1.17 $
Modified By: $Author: rivers $
Last Modified: $Date: 2005-03-30 00:48:40 $
Version: $Revision: 1.18 $
Modified By: $Author: dkline $
Last Modified: $Date: 2005-04-14 18:52:47 $
*/
/*
* Original Author: Mark Rivers
* Date: 10/20/97
* Current Author: Ron Sluiter
* Current Author: Ron Sluiter
*
* Experimental Physics and Industrial Control System (EPICS)
*
@@ -22,16 +22,16 @@ Last Modified: $Date: 2005-03-30 00:48:40 $
* 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
* 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
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
@@ -39,14 +39,14 @@ Last Modified: $Date: 2005-03-30 00:48:40 $
* .02 10-30-97 mlr Replaced driver calls with gpipIO functions
* .03 10-30-98 mlr Minor code cleanup, improved formatting
* .04 02-01-99 mlr Added temporary fix to delay reading motor positions at
* the end of a move.
* the end of a move.
* .05 10-13-99 rls modified for standardized motor record.
* .06 09-17-01 rls
* - created a bit-field for motor status response.
* - start_status() allows one retry after a communication error.
* - set_status() sets RA_PROBLEM along with CNTRL_COMM_ERR to terminate
* node.
* .07 05-19-03 rls Converted to R3.14.x.
* - created a bit-field for motor status response.
* - start_status() allows one retry after a communication error.
* - set_status() sets RA_PROBLEM along with CNTRL_COMM_ERR to terminate
* node.
* .07 05-19-03 rls Converted to R3.14.x.
* .08 11-04-03 mlr Added a final poll of motor status if drvMM4000ReadbackDelay is
* non-zero. This is required to work around a bug in the firmware
* (versions 2.40 and 2.44) that the motor is reported as done moving
@@ -56,9 +56,9 @@ Last Modified: $Date: 2005-03-30 00:48:40 $
* .11 07/28/04 rls "epicsExport" debug variable.
* .12 09/21/04 rls support for 32axes/controller.
* .13 12/21/04 rls - support for MM4006.
* - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
* - make debug variables always available.
* - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
* - make debug variables always available.
*/
@@ -87,17 +87,17 @@ Last Modified: $Date: 2005-03-30 00:48:40 $
#define M_MINUS_LIMIT 0x10
#define M_HOME_SIGNAL 0x20
#define MM4000_NUM_CARDS 4
#define MM4000_NUM_CARDS 4
#define BUFF_SIZE 100 /* Maximum length of string to/from MM4000 */
#define TIMEOUT 2.0 /* Command timeout in sec. */
#define TIMEOUT 2.0 /* Command timeout in sec. */
/*----------------debugging-----------------*/
#ifdef __GNUG__
#ifdef DEBUG
#define Debug(l, f, args...) { if(l<=drvMM4000debug) printf(f,## args); }
#ifdef DEBUG
#define Debug(l, f, args...) { if(l<=drvMM4000debug) printf(f,## args); }
#else
#define Debug(l, f, args...)
#define Debug(l, f, args...)
#endif
#else
#define Debug()
@@ -109,7 +109,7 @@ extern "C" {epicsExportAddress(int, drvMM4000debug);}
int MM4000_num_cards = 0;
/* Local data required for every driver; see "motordrvComCode.h" */
#include "motordrvComCode.h"
#include "motordrvComCode.h"
/* This is a temporary fix to introduce a delayed reading of the motor
* position after a move completes
@@ -177,25 +177,25 @@ static long report(int level)
int card;
if (MM4000_num_cards <=0)
printf(" No MM4000 controllers configured.\n");
printf(" No MM4000 controllers configured.\n");
else
{
for (card = 0; card < MM4000_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
for (card = 0; card < MM4000_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
if (brdptr == NULL)
printf(" MM4000 controller %d connection failed.\n", card);
else
{
struct MMcontroller *cntrl;
if (brdptr == NULL)
printf(" MM4000 controller %d connection failed.\n", card);
else
{
struct MMcontroller *cntrl;
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
printf(" MM4000 controller %d, port=%s, address=%d, id: %s \n",
card, cntrl->asyn_port, cntrl->asyn_address,
brdptr->ident);
}
}
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
printf(" MM4000 controller %d, port=%s, address=%d, id: %s \n",
card, cntrl->asyn_port, cntrl->asyn_address,
brdptr->ident);
}
}
}
return(OK);
}
@@ -203,7 +203,7 @@ static long report(int level)
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
@@ -212,7 +212,7 @@ static long init()
/* Check for setup */
if (MM4000_num_cards <= 0)
{
Debug(1, "init(): MM4000 driver disabled. MM4000Setup() missing from startup script.\n");
Debug(1, "init(): MM4000 driver disabled. MM4000Setup() missing from startup script.\n");
}
return((long) 0);
}
@@ -235,52 +235,52 @@ static void start_status(int card)
if (card >= 0)
{
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
send_mess(card, READ_STATUS, (char) NULL);
status = recv_mess(card, cntrl->status_string, 1);
if (status > 0)
{
cntrl->status = NORMAL;
send_mess(card, READ_POSITION, (char) NULL);
recv_mess(card, cntrl->position_string, 1);
}
else
{
if (cntrl->status == NORMAL)
cntrl->status = RETRY;
else
cntrl->status = COMM_ERR;
}
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
send_mess(card, READ_STATUS, (char) NULL);
status = recv_mess(card, cntrl->status_string, 1);
if (status > 0)
{
cntrl->status = NORMAL;
send_mess(card, READ_POSITION, (char) NULL);
recv_mess(card, cntrl->position_string, 1);
}
else
{
/*
* For efficiency we send messages to all cards, then read all
* responses. This minimizes the latency due to processing on each card
*/
for (itera = 0; (itera < total_cards) && motor_state[itera]; itera++)
send_mess(itera, READ_STATUS, (char) NULL);
for (itera = 0; (itera < total_cards) && motor_state[itera]; itera++)
{
cntrl = (struct MMcontroller *) motor_state[itera]->DevicePrivate;
status = recv_mess(itera, cntrl->status_string, 1);
if (status > 0)
cntrl->status = NORMAL;
else
{
if (cntrl->status == NORMAL)
cntrl->status = RETRY;
else
cntrl->status = COMM_ERR;
}
}
for (itera = 0; (itera < total_cards) && motor_state[itera]; itera++)
send_mess(itera, READ_POSITION, (char) NULL);
for (itera = 0; (itera < total_cards) && motor_state[itera]; itera++)
{
cntrl = (struct MMcontroller *) motor_state[itera]->DevicePrivate;
recv_mess(itera, cntrl->position_string, 1);
}
if (cntrl->status == NORMAL)
cntrl->status = RETRY;
else
cntrl->status = COMM_ERR;
}
}
else
{
/*
* For efficiency we send messages to all cards, then read all
* responses. This minimizes the latency due to processing on each card
*/
for (itera = 0; (itera < total_cards) && motor_state[itera]; itera++)
send_mess(itera, READ_STATUS, (char) NULL);
for (itera = 0; (itera < total_cards) && motor_state[itera]; itera++)
{
cntrl = (struct MMcontroller *) motor_state[itera]->DevicePrivate;
status = recv_mess(itera, cntrl->status_string, 1);
if (status > 0)
cntrl->status = NORMAL;
else
{
if (cntrl->status == NORMAL)
cntrl->status = RETRY;
else
cntrl->status = COMM_ERR;
}
}
for (itera = 0; (itera < total_cards) && motor_state[itera]; itera++)
send_mess(itera, READ_POSITION, (char) NULL);
for (itera = 0; (itera < total_cards) && motor_state[itera]; itera++)
{
cntrl = (struct MMcontroller *) motor_state[itera]->DevicePrivate;
recv_mess(itera, cntrl->position_string, 1);
}
}
}
@@ -311,30 +311,30 @@ static int set_status(int card, int signal)
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;
}
if (cntrl->status == COMM_ERR)
{
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
else
status.Bits.CNTRL_COMM_ERR = 0;
{
rtn_state = 0;
goto exit;
}
}
else
status.Bits.CNTRL_COMM_ERR = 0;
nodeptr = motor_info->motor_motion;
/*
/*
* Parse the status string
* Status string format: 1MSx,2MSy,3MSz,... where x, y and z are the status
* bytes for the motors
*/
pos = signal*5 + 3; /* Offset in status string */
pos = signal*5 + 3; /* Offset in status string */
mstat.All = cntrl->status_string[pos];
Debug(5, "set_status(): status byte = %x\n", mstat.All);
@@ -344,7 +344,7 @@ static int set_status(int card, int signal)
if (mstat.Bits.inmotion == false)
{
status.Bits.RA_DONE = 1;
status.Bits.RA_DONE = 1;
/* TEMPORARY FIX, Mark Rivers, 2/1/99. The MM4000 has reported that the
* motor is done moving, which means that the "jerk time" is done. However,
* the axis can still be settling. For now we put in a delay and poll the
@@ -354,52 +354,52 @@ static int set_status(int card, int signal)
* the motor is done moving. However, if the motor power was off, and the firmware
* version is 2.43 or 2.44 then the controller "lies" and says the motor is done
* on the first poll, when it is really moving. We work around this by reading
* the status again after the delay, in case it is really still moving.
* the status again after the delay, in case it is really still moving.
*/
if (motor_info->pid_present == YES && drvMM4000ReadbackDelay != 0.)
{
epicsThreadSleep(drvMM4000ReadbackDelay);
send_mess(card, READ_POSITION, (char) NULL);
recv_mess(card, cntrl->position_string, 1);
pos = signal*5 + 3; /* Offset in status string */
mstat.All = cntrl->status_string[pos];
if (mstat.Bits.inmotion == true)
status.Bits.RA_DONE = 0;
send_mess(card, READ_POSITION, 0);
recv_mess(card, cntrl->position_string, 1);
}
if (motor_info->pid_present == YES && drvMM4000ReadbackDelay != 0.)
{
epicsThreadSleep(drvMM4000ReadbackDelay);
send_mess(card, READ_POSITION, (char) NULL);
recv_mess(card, cntrl->position_string, 1);
pos = signal*5 + 3; /* Offset in status string */
mstat.All = cntrl->status_string[pos];
if (mstat.Bits.inmotion == true)
status.Bits.RA_DONE = 0;
send_mess(card, READ_POSITION, 0);
recv_mess(card, cntrl->position_string, 1);
}
}
else
status.Bits.RA_DONE = 0;
status.Bits.RA_DONE = 0;
/* Set Travel limit switch status bits. */
if (mstat.Bits.plustTL == false)
status.Bits.RA_PLUS_LS = 0;
status.Bits.RA_PLUS_LS = 0;
else
{
status.Bits.RA_PLUS_LS = 1;
if (plusdir == true)
ls_active = true;
status.Bits.RA_PLUS_LS = 1;
if (plusdir == true)
ls_active = true;
}
if (mstat.Bits.minusTL == false)
status.Bits.RA_MINUS_LS = 0;
status.Bits.RA_MINUS_LS = 0;
else
{
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
status.Bits.RA_MINUS_LS = 1;
if (plusdir == false)
ls_active = true;
}
status.Bits.RA_HOME = (mstat.Bits.homels == false) ? 0 : 1;
status.Bits.EA_POSITION = (mstat.Bits.NOT_power == false) ? 1 : 0;
/* encoder status */
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP_STALL = 0;
status.Bits.EA_HOME = 0;
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP_STALL = 0;
status.Bits.EA_HOME = 0;
/*
/*
* Parse motor position
* Position string format: 1TP5.012,2TP1.123,3TP-100.567,...
* Skip to substring for this motor, convert to double
@@ -409,24 +409,24 @@ static int set_status(int card, int signal)
tok_save = NULL;
p = strtok_r(buff, ",", &tok_save);
for (itera = 0; itera < signal; itera++)
p = strtok_r(NULL, ",", &tok_save);
p = strtok_r(NULL, ",", &tok_save);
Debug(6, "set_status(): position substring = %s\n", p);
motorData = atof(p+3) / cntrl->drive_resolution[signal];
if (motorData == motor_info->position)
{
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
}
else
{
motor_info->position = NINT(motorData);
if (motor_state[card]->motor_info[signal].encoder_present == YES)
motor_info->encoder_position = (epicsInt32) motorData;
else
motor_info->encoder_position = 0;
motor_info->position = NINT(motorData);
if (motor_state[card]->motor_info[signal].encoder_present == YES)
motor_info->encoder_position = (epicsInt32) motorData;
else
motor_info->encoder_position = 0;
motor_info->no_motion_count = 0;
motor_info->no_motion_count = 0;
}
status.Bits.RA_PROBLEM = 0;
@@ -437,18 +437,18 @@ static int set_status(int card, int signal)
motor_info->velocity = 0;
if (!status.Bits.RA_DIRECTION)
motor_info->velocity *= -1;
motor_info->velocity *= -1;
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
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)
nodeptr->postmsgptr != 0)
{
strcpy(buff, nodeptr->postmsgptr);
send_mess(card, buff, (char) NULL);
nodeptr->postmsgptr = NULL;
strcpy(buff, nodeptr->postmsgptr);
send_mess(card, buff, (char) NULL);
nodeptr->postmsgptr = NULL;
}
exit:
@@ -458,43 +458,42 @@ exit:
/*****************************************************/
/* send a message to the MM4000 board */
/* send_mess() */
/* send a message to the MM4000 board */
/* send_mess() */
/*****************************************************/
static RTN_STATUS send_mess(int card, char const *com, char *name)
{
struct MMcontroller *cntrl;
int size;
int nwrite;
size_t nwrite;
size = strlen(com);
if (size > MAX_MSG_SIZE)
{
errlogMessage("drvMM4000.c:send_mess(); message size violation.\n");
return(ERROR);
errlogMessage("drvMM4000.c:send_mess(); message size violation.\n");
return(ERROR);
}
else if (size == 0) /* Normal exit on empty input message. */
return(OK);
else if (size == 0) /* Normal exit on empty input message. */
return(OK);
if (!motor_state[card])
{
errlogPrintf("drvMM4000.c:send_mess() - invalid card #%d\n", card);
return(ERROR);
errlogPrintf("drvMM4000.c:send_mess() - invalid card #%d\n", card);
return(ERROR);
}
if (name != NULL)
{
errlogPrintf("drvMM4000.c:send_mess() - invalid argument = %s\n", name);
return(ERROR);
errlogPrintf("drvMM4000.c:send_mess() - invalid argument = %s\n", name);
return(ERROR);
}
Debug(2, "send_mess(): message = %s\n", com);
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
pasynOctetSyncIO->write(cntrl->pasynUser, com, strlen(com),
TIMEOUT, &nwrite);
pasynOctetSyncIO->write(cntrl->pasynUser, com, strlen(com), TIMEOUT, &nwrite);
return(OK);
}
@@ -504,14 +503,14 @@ static RTN_STATUS send_mess(int card, char const *com, char *name)
* FUNCTION... recv_mess(int card, char *com, int flag)
*
* INPUT ARGUMENTS...
* card - controller card # (0,1,...).
* *com - caller's response buffer.
* flag | FLUSH = flush controller's output buffer; set timeout = 0.
* | !FLUSH = retrieve response into caller's buffer; set timeout.
* card - controller card # (0,1,...).
* *com - caller's response buffer.
* flag | FLUSH = flush controller's output buffer; set timeout = 0.
* | !FLUSH = retrieve response into caller's buffer; set timeout.
*
* LOGIC...
* IF controller card does not exist.
* ERROR RETURN.
* ERROR RETURN.
* ENDIF
* NORMAL RETURN.
*/
@@ -520,24 +519,24 @@ static int recv_mess(int card, char *com, int flag)
{
struct MMcontroller *cntrl;
double timeout = 0.;
int nread = 0;
size_t nread = 0;
asynStatus status;
int eomReason;
/* Check that card exists */
if (!motor_state[card])
return(ERROR);
return(ERROR);
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
timeout = TIMEOUT;
timeout = TIMEOUT;
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
timeout, &nread, &eomReason);
if ((status != asynSuccess) || (nread <= 0))
{
com[0] = '\0';
nread = 0;
com[0] = '\0';
nread = 0;
}
Debug(2, "recv_mess(): message = \"%s\"\n", com);
@@ -550,33 +549,33 @@ static int recv_mess(int card, char *com, int flag)
/* MM4000Setup() */
/*****************************************************/
RTN_STATUS
MM4000Setup(int num_cards, /* maximum number of controllers in system. */
int scan_rate) /* polling rate - 1/60 sec units. */
MM4000Setup(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 > MM4000_NUM_CARDS)
MM4000_num_cards = MM4000_NUM_CARDS;
MM4000_num_cards = MM4000_NUM_CARDS;
else
MM4000_num_cards = num_cards;
MM4000_num_cards = num_cards;
/* Set motor polling task rate */
if (scan_rate >= 1 && scan_rate <= 60)
targs.motor_scan_rate = scan_rate;
targs.motor_scan_rate = scan_rate;
else
targs.motor_scan_rate = SCAN_RATE;
targs.motor_scan_rate = SCAN_RATE;
/*
/*
* Allocate space for motor_state structures. Note this must be done
* before MM4000Config 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(MM4000_num_cards *
sizeof(struct controller *));
sizeof(struct controller *));
for (itera = 0; itera < MM4000_num_cards; itera++)
motor_state[itera] = (struct controller *) NULL;
motor_state[itera] = (struct controller *) NULL;
return(OK);
}
@@ -587,7 +586,7 @@ MM4000Setup(int num_cards, /* maximum number of controllers in system. */
/* MM4000Config() */
/*****************************************************/
RTN_STATUS
MM4000Config(int card, /* card being configured */
MM4000Config(int card, /* card being configured */
const char *name, /* asyn port name */
int addr) /* asyn address (GPIB) */
{
@@ -608,10 +607,10 @@ MM4000Config(int card, /* card being configured */
/*****************************************************/
/* initialize all software and hardware */
/* initialize all software and hardware */
/* This is called from the initialization routine in */
/* device support. */
/* motor_init() */
/* motor_init() */
/*****************************************************/
static int motor_init()
{
@@ -625,140 +624,140 @@ static int motor_init()
int status, model_num, digits;
asynStatus success_rtn;
initialized = true; /* Indicate that driver is initialized. */
initialized = true; /* Indicate that driver is initialized. */
/* Check for setup */
if (MM4000_num_cards <= 0)
return(ERROR);
return(ERROR);
for (card_index = 0; card_index < MM4000_num_cards; card_index++)
{
if (!motor_state[card_index])
continue;
if (!motor_state[card_index])
continue;
brdptr = motor_state[card_index];
brdptr->cmnd_response = false;
total_cards = card_index + 1;
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
brdptr = motor_state[card_index];
brdptr->cmnd_response = false;
total_cards = card_index + 1;
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port,
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port,
cntrl->asyn_address, &cntrl->pasynUser, NULL);
if (success_rtn == asynSuccess)
{
int retry = 0;
if (success_rtn == asynSuccess)
{
int retry = 0;
/* Send a message to the board, see if it exists */
/* flush any junk at input port - should not be any data available */
/* 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);
do
{
send_mess(card_index, READ_POSITION, (char) NULL);
status = recv_mess(card_index, axis_pos, 1);
retry++;
/* Return value is length of response string */
} while(status == 0 && retry < 3);
}
do
{
send_mess(card_index, READ_POSITION, (char) NULL);
status = recv_mess(card_index, axis_pos, 1);
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;
send_mess(card_index, STOP_ALL, (char) NULL); /* Stop all motors */
send_mess(card_index, GET_IDENT, (char) NULL); /* Read controller ID string */
recv_mess(card_index, buff, 1);
strcpy(brdptr->ident, &buff[2]); /* Skip "VE" */
if (success_rtn == asynSuccess && status > 0)
{
brdptr->localaddr = (char *) NULL;
brdptr->motor_in_motion = 0;
send_mess(card_index, STOP_ALL, (char) NULL); /* Stop all motors */
send_mess(card_index, GET_IDENT, (char) NULL); /* Read controller ID string */
recv_mess(card_index, buff, 1);
strcpy(brdptr->ident, &buff[2]); /* Skip "VE" */
/* Set Motion Master model indicator. */
pos_ptr = strstr(brdptr->ident, "MM");
if (pos_ptr == NULL)
{
errlogPrintf("drvMM4000.c:motor_init() - invalid model = %s\n", brdptr->ident);
motor_state[card_index] = (struct controller *) NULL;
continue;
}
model_num = atoi(pos_ptr + 2);
if (model_num == 4000)
cntrl->model = MM4000;
else if (model_num == 4005 || model_num == 4006)
cntrl->model = MM4005;
else
{
errlogPrintf("drvMM4000.c:motor_init() - invalid model = %s\n", brdptr->ident);
motor_state[card_index] = (struct controller *) NULL;
continue;
}
/* Set Motion Master model indicator. */
pos_ptr = strstr(brdptr->ident, "MM");
if (pos_ptr == NULL)
{
errlogPrintf("drvMM4000.c:motor_init() - invalid model = %s\n", brdptr->ident);
motor_state[card_index] = (struct controller *) NULL;
continue;
}
model_num = atoi(pos_ptr + 2);
if (model_num == 4000)
cntrl->model = MM4000;
else if (model_num == 4005 || model_num == 4006)
cntrl->model = MM4005;
else
{
errlogPrintf("drvMM4000.c:motor_init() - invalid model = %s\n", brdptr->ident);
motor_state[card_index] = (struct controller *) NULL;
continue;
}
send_mess(card_index, READ_POSITION, (char) NULL);
recv_mess(card_index, axis_pos, 1);
send_mess(card_index, READ_POSITION, (char) NULL);
recv_mess(card_index, axis_pos, 1);
/* 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;
/* 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;
brdptr->total_axis = total_axis;
start_status(card_index);
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
int loop_state;
start_status(card_index);
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
int loop_state;
motor_info->status.All = 0;
motor_info->no_motion_count = 0;
motor_info->encoder_position = 0;
motor_info->position = 0;
motor_info->status.All = 0;
motor_info->no_motion_count = 0;
motor_info->encoder_position = 0;
motor_info->position = 0;
/* Determine if encoder present based on open/closed loop mode. */
sprintf(buff, "%dTC", motor_index + 1);
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
loop_state = atoi(&buff[3]); /* Skip first 3 characters */
if (loop_state != 0)
{
sprintf(buff, "%dTC", motor_index + 1);
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
loop_state = atoi(&buff[3]); /* Skip first 3 characters */
if (loop_state != 0)
{
motor_info->encoder_present = YES;
motor_info->status.Bits.EA_PRESENT = 1;
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
}
motor_info->status.Bits.EA_PRESENT = 1;
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
}
/* Determine drive resolution. */
sprintf(buff, "%dTU", motor_index + 1);
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
cntrl->drive_resolution[motor_index] = atof(&buff[3]);
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
cntrl->drive_resolution[motor_index] = atof(&buff[3]);
digits = (int) -log10(cntrl->drive_resolution[motor_index]) + 2;
if (digits < 1)
digits = 1;
cntrl->res_decpts[motor_index] = digits;
digits = (int) -log10(cntrl->drive_resolution[motor_index]) + 2;
if (digits < 1)
digits = 1;
cntrl->res_decpts[motor_index] = digits;
/* Save home preset position. */
/* Save home preset position. */
sprintf(buff, "%dXH", motor_index + 1);
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
cntrl->home_preset[motor_index] = atof(&buff[3]);
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
cntrl->home_preset[motor_index] = atof(&buff[3]);
/* Determine low limit */
sprintf(buff, "%dTL", motor_index + 1);
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
motor_info->low_limit = atof(&buff[3]);
/* Determine high limit */
sprintf(buff, "%dTR", motor_index + 1);
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
motor_info->high_limit = atof(&buff[3]);
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
}
any_motor_in_motion = 0;
@@ -769,7 +768,7 @@ static int motor_init()
free_list.head = (struct mess_node *) NULL;
free_list.tail = (struct mess_node *) NULL;
epicsThreadCreate((char *) "MM4000_motor",
epicsThreadCreate((char *) "MM4000_motor",
epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
+238 -239
View File
@@ -1,16 +1,16 @@
/*
FILENAME... drvPM500.cc
USAGE... Motor record driver level support for Newport PM500.
FILENAME... drvPM500.cc
USAGE... Motor record driver level support for Newport PM500.
Version: $Revision: 1.16 $
Modified By: $Author: sluiter $
Last Modified: $Date: 2005-03-30 19:10:48 $
Version: $Revision: 1.17 $
Modified By: $Author: dkline $
Last Modified: $Date: 2005-04-14 18:52:48 $
*/
/* Device Driver Support routines for PM500 motor controller */
/*
* Original Author: Mark Rivers
* Current Author: Ron Sluiter
* Current Author: Ron Sluiter
*
* Experimental Physics and Industrial Control System (EPICS)
*
@@ -22,30 +22,30 @@ Last Modified: $Date: 2005-03-30 19:10:48 $
* 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
* 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
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
* .01 11-19-98 mlr Initial development, based on drvMM4000.c
* .02 06-02-00 rls integrated into standard motor record
* .02 06-02-00 rls integrated into standard motor record
* .03 10/02/01 rls allow one retry after a communication error.
* .04 05-23-03 rls Converted to R3.14.x.
* .04 05-23-03 rls Converted to R3.14.x.
* .05 02/03/04 rls Eliminate erroneous "Motor motion timeout ERROR".
* .06 07/09/04 rls removed unused <driver>Setup() argument.
* .07 07/28/04 rls "epicsExport" debug variable.
* .08 09/21/04 rls support for 32axes/controller.
* .09 12/21/04 rls - MS Visual C compatibility; make all epicsExportAddress
* extern "C" linkage.
* - make debug variables always available.
* extern "C" linkage.
* - make debug variables always available.
*/
@@ -73,18 +73,18 @@ Last Modified: $Date: 2005-03-30 19:10:48 $
#define M_MINUS_LIMIT 0x10
#define M_HOME_SIGNAL 0x20
#define PM500_NUM_CARDS 4
#define PM500_NUM_CARDS 4
#define PM500_NUM_CHANNELS 12
#define BUFF_SIZE 100 /* Maximum length of string to/from PM500 */
#define SERIAL_TIMEOUT 2.0 /* Command timeout in sec. */
#define SERIAL_TIMEOUT 2.0 /* Command timeout in sec. */
/*----------------debugging-----------------*/
#ifdef __GNUG__
#ifdef DEBUG
#define Debug(l, f, args...) { if(l<=drvPM500debug) printf(f,## args); }
#ifdef DEBUG
#define Debug(l, f, args...) { if(l<=drvPM500debug) printf(f,## args); }
#else
#define Debug(l, f, args...)
#define Debug(l, f, args...)
#endif
#else
#define Debug()
@@ -95,10 +95,10 @@ extern "C" {epicsExportAddress(int, drvPM500debug);}
/* --- Local data. --- */
int PM500_num_cards = 0;
static char *PM500_axis_names[] = {"X", "Y", "Z", "A", "B", "C", "D", "E", "F",
"G", "H", "I"};
"G", "H", "I"};
/* Local data required for every driver; see "motordrvComCode.h" */
#include "motordrvComCode.h"
#include "motordrvComCode.h"
/*----------------functions-----------------*/
static int recv_mess(int, char *, int);
@@ -159,25 +159,25 @@ static long report(int level)
int card;
if (PM500_num_cards <=0)
printf(" No PM500 controllers configured.\n");
printf(" No PM500 controllers configured.\n");
else
{
for (card = 0; card < PM500_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
for (card = 0; card < PM500_num_cards; card++)
{
struct controller *brdptr = motor_state[card];
if (brdptr == NULL)
printf(" PM500 controller #%d connection failed.\n", card);
else
{
struct MMcontroller *cntrl;
if (brdptr == NULL)
printf(" PM500 controller #%d connection failed.\n", card);
else
{
struct MMcontroller *cntrl;
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
printf(" PM500 controller %d port=%s, address=%d, id: %s \n",
card, cntrl->asyn_port, cntrl->asyn_address,
brdptr->ident);
}
}
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
printf(" PM500 controller %d port=%s, address=%d, id: %s \n",
card, cntrl->asyn_port, cntrl->asyn_address,
brdptr->ident);
}
}
}
return(OK);
}
@@ -185,7 +185,7 @@ static long report(int level)
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
@@ -194,7 +194,7 @@ static long init()
/* Check for setup */
if (PM500_num_cards <= 0)
{
Debug(1, "init(): PM500 driver disabled. PM500Setup() missing from startup script.\n");
Debug(1, "init(): PM500 driver disabled. PM500Setup() missing from startup script.\n");
}
return((long) 0);
}
@@ -217,7 +217,7 @@ static int set_status(int card, int signal)
register struct mess_info *motor_info;
/* Message parsing variables */
char *axis_name, status_char, dir_char, buff[BUFF_SIZE],
response[BUFF_SIZE];
response[BUFF_SIZE];
int rtnval, rtn_state = 0;
double motorData;
bool ls_active;
@@ -235,59 +235,59 @@ static int set_status(int card, int signal)
rtnval = recv_mess(card, response, 1);
if (rtnval > 0)
{
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 0;
cntrl->status = NORMAL;
status.Bits.CNTRL_COMM_ERR = 0;
}
else
{
if (cntrl->status == NORMAL)
{
cntrl->status = RETRY;
rtn_state = 0;
goto exit;
}
else
{
cntrl->status = COMM_ERR;
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
if (cntrl->status == NORMAL)
{
cntrl->status = RETRY;
rtn_state = 0;
goto exit;
}
else
{
cntrl->status = COMM_ERR;
status.Bits.CNTRL_COMM_ERR = 1;
status.Bits.RA_PROBLEM = 1;
rtn_state = 1;
goto exit;
}
}
status_char = response[1];
dir_char = response[2];
motorData = atof(&response[2]) / cntrl->drive_resolution[signal];
status.Bits.RA_DONE = (status_char == 'B') ? 0 : 1;
status.Bits.RA_DONE = (status_char == 'B') ? 0 : 1;
status.Bits.RA_PROBLEM = (status_char == 'E') ? 1 : 0;
status.Bits.RA_DIRECTION = (dir_char == '+') ? 1 : 0;
if (status_char == 'L')
{
ls_active = true;
if (dir_char == '+')
status.Bits.RA_PLUS_LS = 1;
else
status.Bits.RA_MINUS_LS = 1;
ls_active = true;
if (dir_char == '+')
status.Bits.RA_PLUS_LS = 1;
else
status.Bits.RA_MINUS_LS = 1;
}
else
{
ls_active = false;
status.Bits.RA_PLUS_LS = 0;
status.Bits.RA_MINUS_LS = 0;
ls_active = false;
status.Bits.RA_PLUS_LS = 0;
status.Bits.RA_MINUS_LS = 0;
}
status.Bits.RA_HOME = 0;
/* encoder status */
status.Bits.EA_POSITION = 0;
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP_STALL = 0;
status.Bits.EA_HOME = 0;
status.Bits.EA_POSITION = 0;
status.Bits.EA_SLIP = 0;
status.Bits.EA_SLIP_STALL = 0;
status.Bits.EA_HOME = 0;
/*
/*
* Parse motor position
* Position string format: 1TP5.012,2TP1.123,3TP-100.567,...
* Skip to substring for this motor, convert to double
@@ -295,18 +295,18 @@ static int set_status(int card, int signal)
if (motorData == motor_info->position)
{
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
if (nodeptr != 0) /* Increment counter only if motor is moving. */
motor_info->no_motion_count++;
}
else
{
motor_info->position = NINT(motorData);
if (motor_state[card]->motor_info[signal].encoder_present == YES)
motor_info->encoder_position = (epicsInt32) motorData;
else
motor_info->encoder_position = 0;
motor_info->position = NINT(motorData);
if (motor_state[card]->motor_info[signal].encoder_present == YES)
motor_info->encoder_position = (epicsInt32) motorData;
else
motor_info->encoder_position = 0;
motor_info->no_motion_count = 0;
motor_info->no_motion_count = 0;
}
status.Bits.RA_PROBLEM = 0;
@@ -317,19 +317,19 @@ static int set_status(int card, int signal)
motor_info->velocity = 0;
if (!status.Bits.RA_DIRECTION)
motor_info->velocity *= -1;
motor_info->velocity *= -1;
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
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)
nodeptr->postmsgptr != 0)
{
strcpy(buff, nodeptr->postmsgptr);
strcat(buff, "\r");
send_mess(card, buff, (char) NULL);
nodeptr->postmsgptr = NULL;
strcpy(buff, nodeptr->postmsgptr);
strcat(buff, "\r");
send_mess(card, buff, (char) NULL);
nodeptr->postmsgptr = NULL;
}
exit:
@@ -339,37 +339,36 @@ exit:
/*****************************************************/
/* send a message to the PM500 board */
/* send_mess() */
/* send a message to the PM500 board */
/* send_mess() */
/*****************************************************/
static RTN_STATUS send_mess(int card, char const *com, char *name)
{
struct MMcontroller *cntrl;
int size;
int nwrite;
size_t nwrite;
size = strlen(com);
if (size > MAX_MSG_SIZE)
{
errlogMessage("drvPM500.c:send_mess(); message size violation.\n");
return(ERROR);
errlogMessage("drvPM500.c:send_mess(); message size violation.\n");
return(ERROR);
}
else if (size == 0) /* Normal exit on empty input message. */
return(OK);
else if (size == 0) /* Normal exit on empty input message. */
return(OK);
if (!motor_state[card])
{
errlogPrintf("drvPM500.c:send_mess() - invalid card #%d\n", card);
return(ERROR);
errlogPrintf("drvPM500.c:send_mess() - invalid card #%d\n", card);
return(ERROR);
}
Debug(2, "send_mess(): message = %s\n", com);
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
pasynOctetSyncIO->write(cntrl->pasynUser, com, strlen(com),
SERIAL_TIMEOUT, &nwrite);
pasynOctetSyncIO->write(cntrl->pasynUser, com, strlen(com), SERIAL_TIMEOUT, &nwrite);
return(OK);
}
@@ -379,14 +378,14 @@ static RTN_STATUS send_mess(int card, char const *com, char *name)
* FUNCTION... recv_mess(int card, char *com, int flag)
*
* INPUT ARGUMENTS...
* card - controller card # (0,1,...).
* *com - caller's response buffer.
* flag | FLUSH = flush controller's output buffer; set timeout = 0.
* | !FLUSH = retrieve response into caller's buffer; set timeout.
* card - controller card # (0,1,...).
* *com - caller's response buffer.
* flag | FLUSH = flush controller's output buffer; set timeout = 0.
* | !FLUSH = retrieve response into caller's buffer; set timeout.
*
* LOGIC...
* IF controller card does not exist.
* ERROR RETURN.
* ERROR RETURN.
* ENDIF
* NORMAL RETURN.
*/
@@ -396,19 +395,19 @@ static int recv_mess(int card, char *com, int flag)
struct MMcontroller *cntrl;
double timeout = 0.;
int flush=1;
int nread = 0;
size_t nread = 0;
asynStatus status;
int eomReason;
/* Check that card exists */
if (!motor_state[card])
return(ERROR);
return(ERROR);
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
if (flag != FLUSH) {
flush=0;
timeout = SERIAL_TIMEOUT;
timeout = SERIAL_TIMEOUT;
}
if (flush) status = pasynOctetSyncIO->flush(cntrl->pasynUser);
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
@@ -416,14 +415,14 @@ static int recv_mess(int card, char *com, int flag)
if ((status != asynSuccess) || (nread <= 0))
{
com[0] = '\0';
nread = 0;
com[0] = '\0';
nread = 0;
}
else
{
/* Test for "system error" response. */
if (strncmp(com, "SE", 2) == 0)
errlogMessage("recv_mess(): PM500 system error.\n");
/* Test for "system error" response. */
if (strncmp(com, "SE", 2) == 0)
errlogMessage("recv_mess(): PM500 system error.\n");
}
Debug(2, "recv_mess(): message = \"%s\"\n", com);
@@ -436,33 +435,33 @@ static int recv_mess(int card, char *com, int flag)
/* PM500Setup() */
/*****************************************************/
RTN_STATUS
PM500Setup(int num_cards, /* maximum number of controllers in system. */
int scan_rate) /* polling rate - 1/60 sec units. */
PM500Setup(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 > PM500_NUM_CARDS)
PM500_num_cards = PM500_NUM_CARDS;
PM500_num_cards = PM500_NUM_CARDS;
else
PM500_num_cards = num_cards;
PM500_num_cards = num_cards;
/* Set motor polling task rate */
if (scan_rate >= 1 && scan_rate <= 60)
targs.motor_scan_rate = scan_rate;
targs.motor_scan_rate = scan_rate;
else
targs.motor_scan_rate = SCAN_RATE;
targs.motor_scan_rate = SCAN_RATE;
/*
/*
* Allocate space for motor_state structures. Note this must be done
* before PM500Config 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(PM500_num_cards *
sizeof(struct controller *));
sizeof(struct controller *));
for (itera = 0; itera < PM500_num_cards; itera++)
motor_state[itera] = (struct controller *) NULL;
motor_state[itera] = (struct controller *) NULL;
return(OK);
}
@@ -473,7 +472,7 @@ PM500Setup(int num_cards, /* maximum number of controllers in system. */
/* PM500Config() */
/*****************************************************/
RTN_STATUS
PM500Config(int card, /* card being configured */
PM500Config(int card, /* card being configured */
const char *name, /*asyn port name */
int address) /*asyn address (GPIB) */
{
@@ -494,10 +493,10 @@ PM500Config(int card, /* card being configured */
/*****************************************************/
/* initialize all software and hardware */
/* initialize all software and hardware */
/* This is called from the initialization routine in */
/* device support. */
/* motor_init() */
/* motor_init() */
/*****************************************************/
static int motor_init()
{
@@ -509,81 +508,81 @@ static int motor_init()
int status, digits;
asynStatus success_rtn;
initialized = true; /* Indicate that driver is initialized. */
initialized = true; /* Indicate that driver is initialized. */
/* Check for setup */
if (PM500_num_cards <= 0)
return(ERROR);
return(ERROR);
for (card_index = 0; card_index < PM500_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 MMcontroller *) brdptr->DevicePrivate;
if (!motor_state[card_index])
continue;
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port,
brdptr = motor_state[card_index];
brdptr->cmnd_response = true;
total_cards = card_index + 1;
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port,
cntrl->asyn_address, &cntrl->pasynUser, NULL);
if (success_rtn == asynSuccess)
{
/* flush any junk at input port - should not be any data available */
if (success_rtn == asynSuccess)
{
/* flush any junk at input port - should not be any data available */
pasynOctetSyncIO->flush(cntrl->pasynUser);
/* Send a SCUM 1 command to put device in this mode. */
send_mess(card_index, "SCUM 1", (char) NULL);
recv_mess(card_index, buff, 1);
/* Set up basic controller parameters
* "ENAINT $AF" means the following:
* Bit 0=1, only affected axis halts on limit
* Bit 1=1, No message when moving axis beyond limit
* Bit 2=1, No query echo, prepends status character to axis.
* Bit 3=1, NO status character inserted in responses.
* Bit 4=0, No acknowledgement when command is received
* Bit 5=1, Disable sign-on message at power-up
* Bit 6=0, No echo
* Bit 7=1, CR terminator only on commands and responses
* Bit 8=0, CR terminator only on commands and responses
* Bit 9=0, No EOI sent
* Bit 10=0, CR terminator only on commands and responses
* Bit 11=0, CR terminator only on commands and responses
* Bit 12=0, Decimal number format
* Bit 13=0, Eearly serial poll mapping
* Bit 14=0, No SRQ assertion
*/
send_mess(card_index, "SENAINT $AF", (char) NULL);
recv_mess(card_index, buff, 1);
/* Send a message and read response from controller to see if
* it exists */
send_mess(card_index, GET_IDENT, (char) NULL);
status = recv_mess(card_index, buff, 1);
/* Return value is length of response string */
}
if (success_rtn == asynSuccess && status > 0)
{
brdptr->localaddr = (char *) NULL;
brdptr->motor_in_motion = 0;
send_mess(card_index, GET_IDENT, (char) NULL); /* Read controller ID string */
recv_mess(card_index, buff, 1);
strncpy(brdptr->ident, &buff[2], 50); /* Skip "XD" */
/* Send a SCUM 1 command to put device in this mode. */
send_mess(card_index, "SCUM 1", (char) NULL);
recv_mess(card_index, buff, 1);
/* Set up basic controller parameters
* "ENAINT $AF" means the following:
* Bit 0=1, only affected axis halts on limit
* Bit 1=1, No message when moving axis beyond limit
* Bit 2=1, No query echo, prepends status character to axis.
* Bit 3=1, NO status character inserted in responses.
* Bit 4=0, No acknowledgement when command is received
* Bit 5=1, Disable sign-on message at power-up
* Bit 6=0, No echo
* Bit 7=1, CR terminator only on commands and responses
* Bit 8=0, CR terminator only on commands and responses
* Bit 9=0, No EOI sent
* Bit 10=0, CR terminator only on commands and responses
* Bit 11=0, CR terminator only on commands and responses
* Bit 12=0, Decimal number format
* Bit 13=0, Eearly serial poll mapping
* Bit 14=0, No SRQ assertion
*/
send_mess(card_index, "SENAINT $AF", (char) NULL);
recv_mess(card_index, buff, 1);
/* Send a message and read response from controller to see if
* it exists */
send_mess(card_index, GET_IDENT, (char) NULL);
status = recv_mess(card_index, buff, 1);
/* Return value is length of response string */
}
if (success_rtn == asynSuccess && status > 0)
{
brdptr->localaddr = (char *) NULL;
brdptr->motor_in_motion = 0;
send_mess(card_index, GET_IDENT, (char) NULL); /* Read controller ID string */
recv_mess(card_index, buff, 1);
strncpy(brdptr->ident, &buff[2], 50); /* Skip "XD" */
/* Figure out how many axes this controller has.
* Do this by querying status of each axis in order */
for (total_axis = 0; total_axis < PM500_NUM_CHANNELS; total_axis++)
{
brdptr->motor_info[total_axis].motor_motion = NULL;
sprintf(buff, "%cSTAT?", PM500_axis_names[total_axis]);
{
brdptr->motor_info[total_axis].motor_motion = NULL;
sprintf(buff, "%cSTAT?", PM500_axis_names[total_axis]);
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
if (buff[1] == 'E')
break;
break;
/* Determine axis type and resolution.
* This is a real pain, since the only way to get this
* information is to ask for the axis firmware and use a
@@ -596,72 +595,72 @@ static int motor_init()
*/
}
brdptr->total_axis = total_axis;
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];
char *firmware, *axis_name = PM500_axis_names[motor_index];
double res = 0.0;
for (motor_index = 0; motor_index < total_axis; motor_index++)
{
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
char *firmware, *axis_name = PM500_axis_names[motor_index];
double res = 0.0;
sprintf(buff, "%sCONFIG?", axis_name);
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
send_mess(card_index, buff, (char) NULL);
recv_mess(card_index, buff, 1);
firmware = &buff[8];
Debug(3, "motor_init: firmware = %s\n", firmware);
if (!strcmp(firmware, "302"))
{
/* 50 nm translator */
res = .01;
Debug(3, "motor_init: axis %d is a 50 nm translator\n", motor_index);
}
else if (!strcmp(firmware, "309"))
{
/* 25 nm translator */
res = .01;
Debug(3, "motor_init: axis %d is a 25 nm translator\n", motor_index);
}
else if (!strcmp(firmware, "300"))
{
/* ????? translator ?????? */
res = .01;
Debug(3, "motor_init: axis %d is a ?????? translator\n", motor_index);
}
else if (!strcmp(firmware, "XXX"))
{
/* Rotator */
res = .01;
}
Debug(3, "motor_init: firmware = %s\n", firmware);
if (!strcmp(firmware, "302"))
{
/* 50 nm translator */
res = .01;
Debug(3, "motor_init: axis %d is a 50 nm translator\n", motor_index);
}
else if (!strcmp(firmware, "309"))
{
/* 25 nm translator */
res = .01;
Debug(3, "motor_init: axis %d is a 25 nm translator\n", motor_index);
}
else if (!strcmp(firmware, "300"))
{
/* ????? translator ?????? */
res = .01;
Debug(3, "motor_init: axis %d is a ?????? translator\n", motor_index);
}
else if (!strcmp(firmware, "XXX"))
{
/* Rotator */
res = .01;
}
/* Set drive resolution. */
cntrl->drive_resolution[motor_index] = res;
cntrl->drive_resolution[motor_index] = res;
digits = (int) -log10(cntrl->drive_resolution[motor_index]) + 2;
if (digits < 1)
digits = 1;
cntrl->res_decpts[motor_index] = digits;
digits = (int) -log10(cntrl->drive_resolution[motor_index]) + 2;
if (digits < 1)
digits = 1;
cntrl->res_decpts[motor_index] = digits;
/* PM500 only supports DC motors. */
motor_info->encoder_present = YES;
motor_info->status.Bits.EA_PRESENT = 1;
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
/* PM500 only supports DC motors. */
motor_info->encoder_present = YES;
motor_info->status.Bits.EA_PRESENT = 1;
motor_info->pid_present = YES;
motor_info->status.Bits.GAIN_SUPPORT = 1;
motor_info->status.All = 0;
motor_info->no_motion_count = 0;
motor_info->encoder_position = 0;
motor_info->position = 0;
motor_info->status.All = 0;
motor_info->no_motion_count = 0;
motor_info->encoder_position = 0;
motor_info->position = 0;
motor_info->encoder_present = NO;
motor_info->pid_present = NO;
motor_info->encoder_present = NO;
motor_info->pid_present = NO;
cntrl->home_preset[motor_index] = 0;
cntrl->home_preset[motor_index] = 0;
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
set_status(card_index, motor_index); /* Read status of each motor */
}
}
else
motor_state[card_index] = (struct controller *) NULL;
}
any_motor_in_motion = 0;
@@ -673,8 +672,8 @@ static int motor_init()
free_list.tail = (struct mess_node *) NULL;
epicsThreadCreate((char *) "PM500_motor", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);
return(OK);
}