forked from epics_driver_modules/motorBase
Removed PiSrc; Added motorPi submodule
This commit is contained in:
@@ -40,3 +40,6 @@
|
||||
[submodule "modules/motorPiJena"]
|
||||
path = modules/motorPiJena
|
||||
url = https://github.com/epics-motor/motorPiJena.git
|
||||
[submodule "modules/motorPi"]
|
||||
path = modules/motorPi
|
||||
url = https://github.com/epics-motor/motorPi.git
|
||||
|
||||
@@ -57,51 +57,6 @@ dbLoadRecords("$(MOTOR)/db/motorUtil.db", "P=IOC:")
|
||||
#!asynOctetSetOutputEos("a-Serial[0]",0,"\r")
|
||||
#!drvMCB4BDebug=4
|
||||
|
||||
# PI C-844 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
#!PIC844Setup(1, 10)
|
||||
|
||||
# PI C-844 driver configuration parameters:
|
||||
# (1) controller# being configured
|
||||
# (2) ASYN port name
|
||||
# (3) address (GPIB only)
|
||||
#!PIC844Config(0, "a-Serial[0]")
|
||||
#!drvPIC844debug = 4
|
||||
|
||||
# PI C-848 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
#!PIC848Setup(1, 2)
|
||||
|
||||
# PI C-848 driver configuration parameters:
|
||||
# (1) controller# being configured,
|
||||
# (2) ASYN port name
|
||||
#!PIC848Config(0, "a-Serial[0]")
|
||||
#!drvPIC848debug = 4
|
||||
|
||||
# PI E-662 Piezo driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz, max=60Hz)
|
||||
#!PIC662Setup(1, 60)
|
||||
|
||||
# PI E-662 Piezo driver configuration parameters:
|
||||
# (1) controller being configured
|
||||
# (2) asyn port name (string)
|
||||
#!PIC662Config(0, "serial1")
|
||||
#!drvPIC662debug = 4
|
||||
|
||||
# PI C-862 DC-motor driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz, max=60Hz)
|
||||
#!PIC862Setup(1, 60)
|
||||
|
||||
# PI C-862 DC-motor driver configuration parameters:
|
||||
# (1) controller being configured
|
||||
# (2) asyn port name (string)
|
||||
#!PIC862Config(0, "serial1")
|
||||
#!drvPIC862debug = 4
|
||||
|
||||
# New Focus Picomotor Network Controller (model 8750/2) (setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) maximum number of drivers per controller (1 - 3)
|
||||
|
||||
@@ -50,29 +50,6 @@ asynSetOption("L0", -1, "crtscts", "N")
|
||||
#!asynOctetSetOutputEos("L0",0,"\r")
|
||||
#!var drvMCB4BDebug 4
|
||||
|
||||
# PI C-844 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
#!PIC844Setup(1, 10)
|
||||
|
||||
# PI C-844 driver configuration parameters:
|
||||
# (1) controller# being configured,
|
||||
# (2) ASYN port name
|
||||
# (3) address (GPIB only)
|
||||
#!PIC844Config(0, "L0")
|
||||
#!var drvPIC844debug 4
|
||||
|
||||
# PI C-848 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
#!PIC848Setup(1, 2)
|
||||
|
||||
# PI C-848 driver configuration parameters:
|
||||
# (1) controller# being configured,
|
||||
# (2) ASYN port name
|
||||
#!PIC848Config(0, "L0")
|
||||
#!drvPIC848debug = 4
|
||||
|
||||
# Micos MoCo driver setup parameters:
|
||||
# Load MicosSetup once.
|
||||
# (1) max # of controller groups. Controller groups are per serial
|
||||
|
||||
@@ -39,18 +39,6 @@ dbLoadRecords("$(MOTOR)/db/motorUtil.db", "P=IOC:")
|
||||
#!asynOctetSetOutputEos("L0",0,"\r")
|
||||
#!var drvMCB4BDebug 4
|
||||
|
||||
# PI C-844 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
#!PIC844Setup(1, 10)
|
||||
|
||||
# PI C-844 driver configuration parameters:
|
||||
# (1) controller# being configured,
|
||||
# (2) ASYN port name
|
||||
# (3) address (GPIB only)
|
||||
#!PIC844Config(0, "L0")
|
||||
#!var drvPIC844debug 4
|
||||
|
||||
# Micos MoCo driver setup parameters:
|
||||
# Load MicosSetup once.
|
||||
# (1) max # of controller groups. Controller groups are per serial
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
# ### PI_C630.iocsh ###
|
||||
|
||||
#- ###################################################
|
||||
#- PORT - Serial port for communications
|
||||
#- CONTROLLER - Optional: Which controller is being configured
|
||||
#- Default: 0
|
||||
#-
|
||||
#- MAX_CONTROLLERS - Optional: Max number of controllers that will be configured
|
||||
#- Default: 1
|
||||
#-
|
||||
#- NUM_AXES - Optional: Max number of axes per controller
|
||||
#- Default: 1
|
||||
#-
|
||||
#- POLL_RATE - Optional: Controller poll rate in hertz
|
||||
#- Default: 10
|
||||
#-
|
||||
#- CURR[1-9] - Optional: Current settings for axes 1 through 9
|
||||
#- Current equals 100mA * setting, maximum 800mA.
|
||||
#- Default: 0 (off)
|
||||
#- ###################################################
|
||||
|
||||
|
||||
#-################################################
|
||||
#- PI C-630 driver setup parameters:
|
||||
#- Load PIC630Setup once.
|
||||
#- (1) max # of controller groups. Controller groups are per serial port.
|
||||
#- (2) max # axes per controller group. Maximum 9. (addr 1-9)
|
||||
#- (3) motor task polling rate (min=1Hz, max=60Hz, 10Hz works well)
|
||||
#- Example:
|
||||
#- PIC630Setup(1, 2, 10) 1 group. 2 axes (controllers) in the group. 10Hz poll.
|
||||
$(PI_C630_INIT_COMPLETE="") PIC630Setup($(MAX_CONTROLLERS=1), $(NUM_AXES=1), $(POLL_RATE=10))
|
||||
|
||||
# PI C630 serial connection settings
|
||||
iocshLoad("$(IP)/iocsh/setSerialParams.iocsh", "PORT=$(PORT), BAUD=19200, BITS=8, STOP=1, PARITY=none")
|
||||
asynOctetSetInputEos( "$(PORT)", -1, "\r")
|
||||
asynOctetSetOutputEos("$(PORT)", -1, "\r")
|
||||
|
||||
#- PIC630 driver configuration parameters:
|
||||
#- Load one PIC630Config for each group of PI C-630 drivers.
|
||||
#- (1) "Controller group" number
|
||||
#- (2) MPF card
|
||||
#- (3)-(11) Current setting per axis (1-9). Leave at 0 if unused.
|
||||
#- Choices: 0=OFF, 1=100mA, 2=200mA, ... 8=800mA.
|
||||
#- Example:
|
||||
#- PIC630Config(0, "serial1, 5, 3, 0, 0, 0, 0, 0, 0, 0")
|
||||
#- Group 0, asyn serial port 1, Axis1=.5A, Axis2=.3A, others OFF
|
||||
PIC630Config($(CONTROLLER=0), "$(PORT)", $(CURR1=0), $(CURR2=0), $(CURR3=0), $(CURR4=0), $(CURR5=0), $(CURR6=0), $(CURR7=0), $(CURR8=0), $(CURR9=0))
|
||||
|
||||
epicsEnvSet("PI_C630_INIT_COMPLETE", "#")
|
||||
@@ -1,28 +0,0 @@
|
||||
# ### PI_C867.iocsh ###
|
||||
|
||||
#- ###################################################
|
||||
#- PORT - Serial port for communications
|
||||
#- CONTROLLER - Optional: Which controller is being configured
|
||||
#- Controller port name will be PIC867$(CONTROLLER)
|
||||
#- Default: 0
|
||||
#-
|
||||
#- NUM_AXES - Optional: Max number of axes per controller
|
||||
#- Default: 1
|
||||
#-
|
||||
#- MOVING_POLL - Optional: Moving poll rate (in msec)
|
||||
#- Default: POLL_RATE
|
||||
#-
|
||||
#- IDLE_POLL - Optional: Idle poll rate (in msec)
|
||||
#- Default: POLL_RATE
|
||||
#-
|
||||
#- POLL_RATE - Optional: Poll rate in msec
|
||||
#- Default: 100
|
||||
#- ###################################################
|
||||
|
||||
|
||||
# PI C867 serial connection settings
|
||||
iocshLoad("$(IP)/iocsh/setSerialParams.iocsh", "PORT=$(PORT), BAUD=38400, BITS=8, STOP=1, PARITY=none")
|
||||
asynOctetSetInputEos( "$(PORT)", -1, "\n\r")
|
||||
asynOctetSetOutputEos("$(PORT)", -1, "\n")
|
||||
|
||||
PI_GCS2_CreateController("PIC867$(CONTROLLER)", "$(PORT)", $(NUM_AXES=0), 0, 0, $(MOVING_POLL=$(POLL_RATE=100)), $(IDLE_POLL=$(POLL_RATE=100)))
|
||||
@@ -1,31 +0,0 @@
|
||||
# ### PI_E710.iocsh ###
|
||||
|
||||
#- ###################################################
|
||||
#- PORT - Serial port for communications
|
||||
#- CONTROLLER - Optional: Which controller is being configured
|
||||
#- Default: 0
|
||||
#-
|
||||
#- MAX_CONTROLLERS - Optional: Max number of controllers that will be configured
|
||||
#- Default: 1
|
||||
#-
|
||||
#- POLL_RATE - Optional: Controller poll rate in hertz
|
||||
#- Default: 10
|
||||
#- ###################################################
|
||||
|
||||
#- PI E-710 driver setup parameters:
|
||||
#- (1) maximum # of controllers,
|
||||
#- (2) motor task polling rate (min=1Hz, max=60Hz)
|
||||
$(E710_INIT_COMPLETE="") PIE710Setup($(MAX_CONTROLLERS=1), $(POLL_RATE=10))
|
||||
|
||||
# PI E710 serial connection settings
|
||||
iocshLoad("$(IP)/iocsh/setSerialParams.iocsh", "PORT=$(PORT), BAUD=9600, BITS=8, STOP=1, PARITY=none")
|
||||
asynOctetSetInputEos( "$(PORT)", -1, "\n")
|
||||
asynOctetSetOutputEos("$(PORT)", -1, "\n")
|
||||
|
||||
#- PI E-710 driver configuration parameters:
|
||||
#- (1) controller
|
||||
#- (2) asyn port name (e.g. serial1 or gpib1)
|
||||
#- (3) GPIB address (0 for serial)
|
||||
PIE710Config($(CONTROLLER=0), "$(PORT)", 0)
|
||||
|
||||
epicsEnvSet("E710_INIT_COMPLETE", "#")
|
||||
@@ -1,30 +0,0 @@
|
||||
# ### PI_E816.iocsh ###
|
||||
|
||||
#- ###################################################
|
||||
#- PORT - Serial port for communications
|
||||
#- CONTROLLER - Optional: Which controller is being configured
|
||||
#- Default: 0
|
||||
#-
|
||||
#- MAX_CONTROLLERS - Optional: Max number of controllers that will be configured
|
||||
#- Default: 1
|
||||
#-
|
||||
#- POLL_RATE - Optional: Controller poll rate in hertz
|
||||
#- Default: 10
|
||||
#- ###################################################
|
||||
|
||||
#- PI E-816 driver setup parameters:
|
||||
#- (1) maximum number of controllers in system
|
||||
#- (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
$(E816_INIT_COMPLETE="") PIE816Setup($(MAX_CONTROLLERS=1), $(POLL_RATE=10))
|
||||
|
||||
# PI E816 serial connection settings
|
||||
iocshLoad("$(IP)/iocsh/setSerialParams.iocsh", "PORT=$(PORT), BAUD=38400, BITS=8, STOP=1, PARITY=none, HANDSHAKE=hardware")
|
||||
asynOctetSetInputEos( "$(PORT)", -1, "\n")
|
||||
asynOctetSetOutputEos("$(PORT)", -1, "\n")
|
||||
|
||||
# PI E-816 driver configuration parameters:
|
||||
# (1) controller# being configured,
|
||||
# (2) ASYN port name
|
||||
PIE816Config($(CONTROLLER=0), "$(PORT)")
|
||||
|
||||
epicsEnvSet("E816_INIT_COMPLETE", "#")
|
||||
@@ -19,6 +19,7 @@ SUBMODULES += motorMicronix
|
||||
SUBMODULES += motorNPoint
|
||||
SUBMODULES += motorOriel
|
||||
SUBMODULES += motorPiJena
|
||||
SUBMODULES += motorPi
|
||||
|
||||
# Allow sites to add extra submodules
|
||||
-include Makefile.local
|
||||
|
||||
Submodule
+1
Submodule modules/motorPi added at afb55469ab
@@ -27,9 +27,6 @@ ImsSrc_DEPEND_DIRS = MotorSrc
|
||||
DIRS += AcsSrc
|
||||
AcsSrc_DEPEND_DIRS = MotorSrc
|
||||
|
||||
DIRS += PiSrc
|
||||
PiSrc_DEPEND_DIRS = MotorSrc
|
||||
|
||||
DIRS += PIGCS2Src
|
||||
PIGCS2Src_DEPEND_DIRS = MotorSrc
|
||||
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
# Makefile
|
||||
TOP = ../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
# Both the following line, and a line in the *.dbd file,
|
||||
# must be uncommented to use diagnostic debugging messages.
|
||||
#!USR_CXXFLAGS += -DDEBUG
|
||||
|
||||
DBD += devPIMotor.dbd
|
||||
|
||||
LIBRARY_IOC = PI
|
||||
|
||||
# Intelligent Motion Systems driver support.
|
||||
SRCS += devPIC844.cc drvPIC844.cc PiRegister.cc
|
||||
SRCS += devPIC630.cc drvPIC630.cc PIC630Register.cc
|
||||
SRCS += devPIC848.cc drvPIC848.cc PIC848Register.cc
|
||||
SRCS += devPIC662.cc drvPIC662.cc PIC662Register.cc
|
||||
SRCS += devPIC862.cc drvPIC862.cc PIC862Register.cc
|
||||
SRCS += devPIC663.cc drvPIC663.cc PIC663Register.cc
|
||||
SRCS += devPIE710.cc drvPIE710.cc PIE710Register.cc
|
||||
SRCS += devPIE516.cc drvPIE516.cc PIE516Register.cc
|
||||
SRCS += devPIE517.cc drvPIE517.cc PIE517Register.cc
|
||||
SRCS += devPIE816.cc drvPIE816.cc PIE816Register.cc
|
||||
|
||||
|
||||
PI_LIBS += motor asyn
|
||||
PI_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
FILENAME... PIC630Register.cc
|
||||
USAGE... Register PIC630 motor device driver shell commands.
|
||||
|
||||
Version: 1.4
|
||||
Modified By: sluiter
|
||||
Last Modified: 2004/07/16 19:06:58
|
||||
*/
|
||||
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
|
||||
#include <iocsh.h>
|
||||
#include "PIC630Register.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// PIC630 Setup arguments
|
||||
static const iocshArg setupArg0 = {"Max. controller groups", iocshArgInt};
|
||||
static const iocshArg setupArg1 = {"Max. axes per group", iocshArgInt};
|
||||
static const iocshArg setupArg2 = {"Polling rate", iocshArgInt};
|
||||
// PIC630 Config arguments
|
||||
static const iocshArg configArg0 = {"Card being configured", iocshArgInt};
|
||||
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
|
||||
static const iocshArg configArg2 = {"Ch 1 current setting", iocshArgInt};
|
||||
static const iocshArg configArg3 = {"Ch 2 current setting", iocshArgInt};
|
||||
static const iocshArg configArg4 = {"Ch 3 current setting", iocshArgInt};
|
||||
static const iocshArg configArg5 = {"Ch 4 current setting", iocshArgInt};
|
||||
static const iocshArg configArg6 = {"Ch 5 current setting", iocshArgInt};
|
||||
static const iocshArg configArg7 = {"Ch 6 current setting", iocshArgInt};
|
||||
static const iocshArg configArg8 = {"Ch 7 current setting", iocshArgInt};
|
||||
static const iocshArg configArg9 = {"Ch 8 current setting", iocshArgInt};
|
||||
static const iocshArg configArg10 = {"Ch 9 current setting", iocshArgInt};
|
||||
|
||||
static const iocshArg * const PIC630SetupArgs[3] = {&setupArg0, &setupArg1, &setupArg2};
|
||||
static const iocshArg * const PIC630ConfigArgs[11] = {&configArg0, &configArg1, &configArg2, &configArg3, &configArg4, &configArg5, &configArg6, &configArg7, &configArg8, &configArg9, &configArg10};
|
||||
|
||||
static const iocshFuncDef setupPIC630 = {"PIC630Setup", 3, PIC630SetupArgs};
|
||||
static const iocshFuncDef configPIC630 = {"PIC630Config", 11, PIC630ConfigArgs};
|
||||
|
||||
static void setupPIC630CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIC630Setup(args[0].ival, args[1].ival, args[2].ival);
|
||||
}
|
||||
static void configPIC630CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIC630Config(args[0].ival, args[1].sval, args[2].ival, args[3].ival, args[4].ival, args[5].ival, args[6].ival, args[7].ival, args[8].ival, args[9].ival, args[10].ival);
|
||||
}
|
||||
|
||||
static void PIC630Register(void)
|
||||
{
|
||||
iocshRegister(&setupPIC630, setupPIC630CallFunc);
|
||||
iocshRegister(&configPIC630, configPIC630CallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(PIC630Register);
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
FILENAME... PIC630Register.h
|
||||
USAGE... This file contains function prototypes for PIC630 IOC shell commands.
|
||||
|
||||
Version: 1.3
|
||||
Modified By: sluiter
|
||||
Last Modified: 2004/07/16 19:06:58
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 05/19/03
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
*/
|
||||
|
||||
#include "motor.h"
|
||||
#include "motordrvCom.h"
|
||||
|
||||
/* Function prototypes. */
|
||||
extern RTN_STATUS PIC630Setup(int, int, int);
|
||||
extern RTN_STATUS PIC630Config(int, const char *, int,int,int,int,int,int,int,int,int);
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
FILENAME... PiRegister.cc
|
||||
USAGE... Register IMS motor device driver shell commands.
|
||||
|
||||
*/
|
||||
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <iocsh.h>
|
||||
#include "motor.h"
|
||||
#include "drvPIC662.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// Pi 662 Setup arguments
|
||||
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
|
||||
static const iocshArg setupArg1 = {"Polling rate", iocshArgInt};
|
||||
// Pi 662 Config arguments
|
||||
static const iocshArg configArg0 = {"Card being configured", iocshArgInt};
|
||||
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
|
||||
|
||||
static const iocshArg * const PIC662SetupArgs[2] = {&setupArg0, &setupArg1};
|
||||
static const iocshArg * const PIC662ConfigArgs[2] = {&configArg0, &configArg1};
|
||||
|
||||
static const iocshFuncDef setupPIC662 = {"PIC662Setup", 2, PIC662SetupArgs};
|
||||
static const iocshFuncDef configPIC662 = {"PIC662Config", 2, PIC662ConfigArgs};
|
||||
|
||||
static void setupPIC662CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIC662Setup(args[0].ival, args[1].ival);
|
||||
}
|
||||
|
||||
|
||||
static void configPIC662CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIC662Config(args[0].ival, args[1].sval);
|
||||
}
|
||||
|
||||
|
||||
static void PIC662motorRegister(void)
|
||||
{
|
||||
iocshRegister(&setupPIC662, setupPIC662CallFunc);
|
||||
iocshRegister(&configPIC662, configPIC662CallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(PIC662motorRegister);
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
FILENAME... PIC663Register.cc
|
||||
USAGE... Register PI motor device driver shell commands.
|
||||
*/
|
||||
/*
|
||||
* Copied from PIC862Register.cc by Jonathan Thompson, Jan 2011
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* Jan 2011 - All references to 862 changed to 663
|
||||
* Status register definitions changed to match 663
|
||||
*/
|
||||
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <iocsh.h>
|
||||
#include "motor.h"
|
||||
#include "drvPIC663.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// Pi Setup arguments
|
||||
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
|
||||
static const iocshArg setupArg1 = {"Polling rate", iocshArgInt};
|
||||
// Pi Config arguments
|
||||
static const iocshArg configArg0 = {"Card being configured", iocshArgInt};
|
||||
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
|
||||
static const iocshArg configArg2 = {"asyn address (GPIB)", iocshArgInt};
|
||||
|
||||
static const iocshArg * const PIC663SetupArgs[2] = {&setupArg0, &setupArg1};
|
||||
static const iocshArg * const PIC663ConfigArgs[3] = {&configArg0, &configArg1,
|
||||
&configArg2};
|
||||
|
||||
static const iocshFuncDef setupPIC663 = {"PIC663Setup", 2, PIC663SetupArgs};
|
||||
static const iocshFuncDef configPIC663 = {"PIC663Config", 3, PIC663ConfigArgs};
|
||||
|
||||
static void setupPIC663CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIC663Setup(args[0].ival, args[1].ival);
|
||||
}
|
||||
|
||||
|
||||
static void configPIC663CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIC663Config(args[0].ival, args[1].sval, args[2].ival);
|
||||
}
|
||||
|
||||
|
||||
static void PIC663motorRegister(void)
|
||||
{
|
||||
iocshRegister(&setupPIC663, setupPIC663CallFunc);
|
||||
iocshRegister(&configPIC663, configPIC663CallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(PIC663motorRegister);
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
FILENAME... PIC848Register.cc
|
||||
USAGE... Register PI motor device driver shell commands.
|
||||
|
||||
*/
|
||||
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <iocsh.h>
|
||||
#include "motor.h"
|
||||
#include "drvPIC848.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// Pi Setup arguments
|
||||
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
|
||||
static const iocshArg setupArg1 = {"Polling rate", iocshArgInt};
|
||||
// Pi Config arguments
|
||||
static const iocshArg configArg0 = {"Card being configured", iocshArgInt};
|
||||
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
|
||||
static const iocshArg configArg2 = {"asyn address (GPIB)", iocshArgInt};
|
||||
|
||||
static const iocshArg * const PIC848SetupArgs[2] = {&setupArg0, &setupArg1};
|
||||
static const iocshArg * const PIC848ConfigArgs[3] = {&configArg0, &configArg1,
|
||||
&configArg2};
|
||||
|
||||
static const iocshFuncDef setupPIC848 = {"PIC848Setup", 2, PIC848SetupArgs};
|
||||
static const iocshFuncDef configPIC848 = {"PIC848Config", 3, PIC848ConfigArgs};
|
||||
|
||||
static void setupPIC848CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIC848Setup(args[0].ival, args[1].ival);
|
||||
}
|
||||
|
||||
|
||||
static void configPIC848CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIC848Config(args[0].ival, args[1].sval, args[2].ival);
|
||||
}
|
||||
|
||||
|
||||
static void PIC848motorRegister(void)
|
||||
{
|
||||
iocshRegister(&setupPIC848, setupPIC848CallFunc);
|
||||
iocshRegister(&configPIC848, configPIC848CallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(PIC848motorRegister);
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
FILENAME... PIC862Register.cc
|
||||
USAGE... Register PI motor device driver shell commands.
|
||||
|
||||
Version: 1.1
|
||||
Modified By: Ramanathan
|
||||
Last Modified: 2006/09/04 19:45:52
|
||||
*/
|
||||
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <iocsh.h>
|
||||
#include "motor.h"
|
||||
#include "drvPIC862.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// Pi Setup arguments
|
||||
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
|
||||
static const iocshArg setupArg1 = {"Polling rate", iocshArgInt};
|
||||
// Pi Config arguments
|
||||
static const iocshArg configArg0 = {"Card being configured", iocshArgInt};
|
||||
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
|
||||
static const iocshArg configArg2 = {"asyn address (GPIB)", iocshArgInt};
|
||||
|
||||
static const iocshArg * const PIC862SetupArgs[2] = {&setupArg0, &setupArg1};
|
||||
static const iocshArg * const PIC862ConfigArgs[3] = {&configArg0, &configArg1,
|
||||
&configArg2};
|
||||
|
||||
static const iocshFuncDef setupPIC862 = {"PIC862Setup", 2, PIC862SetupArgs};
|
||||
static const iocshFuncDef configPIC862 = {"PIC862Config", 3, PIC862ConfigArgs};
|
||||
|
||||
static void setupPIC862CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIC862Setup(args[0].ival, args[1].ival);
|
||||
}
|
||||
|
||||
|
||||
static void configPIC862CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIC862Config(args[0].ival, args[1].sval, args[2].ival);
|
||||
}
|
||||
|
||||
|
||||
static void PIC862motorRegister(void)
|
||||
{
|
||||
iocshRegister(&setupPIC862, setupPIC862CallFunc);
|
||||
iocshRegister(&configPIC862, configPIC862CallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(PIC862motorRegister);
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
FILENAME... PIE516Register.cc
|
||||
USAGE... Register PI motor device driver shell commands.
|
||||
|
||||
*/
|
||||
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <iocsh.h>
|
||||
#include "motor.h"
|
||||
#include "drvPIE516.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// Pi Setup arguments
|
||||
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
|
||||
static const iocshArg setupArg1 = {"Polling rate", iocshArgInt};
|
||||
// Pi Config arguments
|
||||
static const iocshArg configArg0 = {"Card being configured", iocshArgInt};
|
||||
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
|
||||
static const iocshArg configArg2 = {"asyn address (GPIB)", iocshArgInt};
|
||||
|
||||
static const iocshArg * const PIE516SetupArgs[2] = {&setupArg0, &setupArg1};
|
||||
static const iocshArg * const PIE516ConfigArgs[3] = {&configArg0, &configArg1,
|
||||
&configArg2};
|
||||
|
||||
static const iocshFuncDef setupPIE516 = {"PIE516Setup", 2, PIE516SetupArgs};
|
||||
static const iocshFuncDef configPIE516 = {"PIE516Config", 3, PIE516ConfigArgs};
|
||||
|
||||
static void setupPIE516CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIE516Setup(args[0].ival, args[1].ival);
|
||||
}
|
||||
|
||||
|
||||
static void configPIE516CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIE516Config(args[0].ival, args[1].sval, args[2].ival);
|
||||
}
|
||||
|
||||
|
||||
static void PIE516motorRegister(void)
|
||||
{
|
||||
iocshRegister(&setupPIE516, setupPIE516CallFunc);
|
||||
iocshRegister(&configPIE516, configPIE516CallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(PIE516motorRegister);
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
FILENAME... PIE517Register.cc
|
||||
USAGE... Register PI motor device driver shell commands.
|
||||
|
||||
Version: $Revision: 1.1 $
|
||||
Modified By: $Author: sullivan $
|
||||
Last Modified: $Date: 2007-03-30 20:01:05 $
|
||||
*/
|
||||
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <iocsh.h>
|
||||
#include "motor.h"
|
||||
#include "drvPIE517.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// Pi Setup arguments
|
||||
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
|
||||
static const iocshArg setupArg1 = {"Polling rate", iocshArgInt};
|
||||
// Pi Config arguments
|
||||
static const iocshArg configArg0 = {"Card being configured", iocshArgInt};
|
||||
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
|
||||
static const iocshArg configArg2 = {"asyn address (GPIB)", iocshArgInt};
|
||||
|
||||
static const iocshArg * const PIE517SetupArgs[2] = {&setupArg0, &setupArg1};
|
||||
static const iocshArg * const PIE517ConfigArgs[3] = {&configArg0, &configArg1,
|
||||
&configArg2};
|
||||
|
||||
static const iocshFuncDef setupPIE517 = {"PIE517Setup", 2, PIE517SetupArgs};
|
||||
static const iocshFuncDef configPIE517 = {"PIE517Config", 3, PIE517ConfigArgs};
|
||||
|
||||
static void setupPIE517CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIE517Setup(args[0].ival, args[1].ival);
|
||||
}
|
||||
|
||||
|
||||
static void configPIE517CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIE517Config(args[0].ival, args[1].sval, args[2].ival);
|
||||
}
|
||||
|
||||
|
||||
static void PIE517motorRegister(void)
|
||||
{
|
||||
iocshRegister(&setupPIE517, setupPIE517CallFunc);
|
||||
iocshRegister(&configPIE517, configPIE517CallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(PIE517motorRegister);
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
FILENAME... PIE710Register.cc
|
||||
USAGE... Register PI motor device driver shell commands.
|
||||
|
||||
*/
|
||||
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <iocsh.h>
|
||||
#include "motor.h"
|
||||
#include "drvPIE710.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// Pi Setup arguments
|
||||
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
|
||||
static const iocshArg setupArg1 = {"Polling rate", iocshArgInt};
|
||||
// Pi Config arguments
|
||||
static const iocshArg configArg0 = {"Card being configured", iocshArgInt};
|
||||
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
|
||||
static const iocshArg configArg2 = {"asyn address (GPIB)", iocshArgInt};
|
||||
|
||||
static const iocshArg * const PIE710SetupArgs[2] = {&setupArg0, &setupArg1};
|
||||
static const iocshArg * const PIE710ConfigArgs[3] = {&configArg0, &configArg1,
|
||||
&configArg2};
|
||||
|
||||
static const iocshFuncDef setupPIE710 = {"PIE710Setup", 2, PIE710SetupArgs};
|
||||
static const iocshFuncDef configPIE710 = {"PIE710Config", 3, PIE710ConfigArgs};
|
||||
|
||||
static void setupPIE710CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIE710Setup(args[0].ival, args[1].ival);
|
||||
}
|
||||
|
||||
|
||||
static void configPIE710CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIE710Config(args[0].ival, args[1].sval, args[2].ival);
|
||||
}
|
||||
|
||||
|
||||
static void PIE710motorRegister(void)
|
||||
{
|
||||
iocshRegister(&setupPIE710, setupPIE710CallFunc);
|
||||
iocshRegister(&configPIE710, configPIE710CallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(PIE710motorRegister);
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
FILENAME... PIE816Register.cc
|
||||
USAGE... Register PI motor device driver shell commands.
|
||||
|
||||
Version: 1.1
|
||||
Modified By: sullivan
|
||||
Last Modified: 2007/03/30 20:01:05
|
||||
*/
|
||||
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <iocsh.h>
|
||||
#include "motor.h"
|
||||
#include "drvPIE816.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// Pi Setup arguments
|
||||
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
|
||||
static const iocshArg setupArg1 = {"Polling rate", iocshArgInt};
|
||||
// Pi Config arguments
|
||||
static const iocshArg configArg0 = {"Card being configured", iocshArgInt};
|
||||
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
|
||||
static const iocshArg configArg2 = {"asyn address (GPIB)", iocshArgInt};
|
||||
|
||||
static const iocshArg * const PIE816SetupArgs[2] = {&setupArg0, &setupArg1};
|
||||
static const iocshArg * const PIE816ConfigArgs[3] = {&configArg0, &configArg1,
|
||||
&configArg2};
|
||||
|
||||
static const iocshFuncDef setupPIE816 = {"PIE816Setup", 2, PIE816SetupArgs};
|
||||
static const iocshFuncDef configPIE816 = {"PIE816Config", 3, PIE816ConfigArgs};
|
||||
|
||||
static void setupPIE816CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIE816Setup(args[0].ival, args[1].ival);
|
||||
}
|
||||
|
||||
|
||||
static void configPIE816CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIE816Config(args[0].ival, args[1].sval, args[2].ival);
|
||||
}
|
||||
|
||||
|
||||
static void PIE816motorRegister(void)
|
||||
{
|
||||
iocshRegister(&setupPIE816, setupPIE816CallFunc);
|
||||
iocshRegister(&configPIE816, configPIE816CallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(PIE816motorRegister);
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
FILENAME... PiRegister.cc
|
||||
USAGE... Register IMS motor device driver shell commands.
|
||||
|
||||
*/
|
||||
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <iocsh.h>
|
||||
#include "motor.h"
|
||||
#include "drvPI.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// Pi Setup arguments
|
||||
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
|
||||
static const iocshArg setupArg1 = {"Polling rate", iocshArgInt};
|
||||
// Pi Config arguments
|
||||
static const iocshArg configArg0 = {"Card being configured", iocshArgInt};
|
||||
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
|
||||
static const iocshArg configArg2 = {"asyn address (GPIB)", iocshArgInt};
|
||||
|
||||
static const iocshArg * const PIC844SetupArgs[2] = {&setupArg0, &setupArg1};
|
||||
static const iocshArg * const PIC844ConfigArgs[3] = {&configArg0, &configArg1,
|
||||
&configArg2};
|
||||
|
||||
static const iocshFuncDef setupPIC844 = {"PIC844Setup", 2, PIC844SetupArgs};
|
||||
static const iocshFuncDef configPIC844 = {"PIC844Config", 3, PIC844ConfigArgs};
|
||||
|
||||
static void setupPIC844CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIC844Setup(args[0].ival, args[1].ival);
|
||||
}
|
||||
|
||||
|
||||
static void configPIC844CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PIC844Config(args[0].ival, args[1].sval, args[2].ival);
|
||||
}
|
||||
|
||||
|
||||
static void PImotorRegister(void)
|
||||
{
|
||||
iocshRegister(&setupPIC844, setupPIC844CallFunc);
|
||||
iocshRegister(&configPIC844, configPIC844CallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(PImotorRegister);
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,33 +0,0 @@
|
||||
PI C-844
|
||||
========
|
||||
|
||||
Serial communication using the GreensSpring XM Octal I/O.
|
||||
---------------------------------------------------------
|
||||
|
||||
The GreensSpring XM Octal I/O has a 16 pin jumper block for each serial port.
|
||||
Assume (the manual does not define this) that the jumper pins are numbered
|
||||
from, top to bottom, and from left to right; i.e.,
|
||||
1 2 3 4
|
||||
5 6 7 8
|
||||
9 10 11 12
|
||||
13 14 15 16
|
||||
|
||||
Then the "Default jumbering ..." depicted in Fig. 2 of the GreensSpring XM
|
||||
Octal I/O manual is jumpered as follows; 1-5, 2-6, 9-13, 10-14.
|
||||
|
||||
The correct jumpering for the C-844 is; 1-2, 5-6, 13-16.
|
||||
|
||||
M-111.12S stage to ACS driver adapter
|
||||
=====================================
|
||||
|
||||
DB15 ELCO Func.
|
||||
---- ---- -----
|
||||
1 A ph1+
|
||||
9 E ph1-
|
||||
2 C ph2+
|
||||
10 H ph2-
|
||||
6 V +5V
|
||||
14 W lim+
|
||||
7 T,U,R Gnd
|
||||
8 X lim-
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
Digital Piezo Controller
|
||||
(c) 2003 Physik Instrumente GmbH
|
||||
|
||||
Model: E-516
|
||||
|
||||
Version: DSP V3.11
|
||||
MCU V5
|
||||
|
||||
RS232: <Programmable>
|
||||
12200,8,1,N (default)
|
||||
EOL: '/n' (10) LF
|
||||
Hardware Flow Control RTS/CTS
|
||||
|
||||
Commands:
|
||||
<command> <axis>[<arg>]</n>
|
||||
Where axis = A, B or C
|
||||
|
||||
* NO reply from motion commands
|
||||
* Multiple command delimiter = "/n"
|
||||
|
||||
Reply: <reply string></n>
|
||||
|
||||
|
||||
Position Resolution: 0.001 micrometers (um)
|
||||
Effective Resolution: 0.01 (on target tolerance)
|
||||
|
||||
Setup:
|
||||
NONE
|
||||
|
||||
=================== CONTROLLER SETUP =================
|
||||
Communication Enable
|
||||
ONL 1
|
||||
|
||||
Velocity Control Mode ON (required for on-target reading ONT?)
|
||||
VCO A1
|
||||
|
||||
=================== MOTION =================
|
||||
ENABLE/DISABLE Servo
|
||||
SVO <axis>[1/0]
|
||||
|
||||
MOVE Absolute
|
||||
MOV <axis><position>
|
||||
|
||||
MOVE Relative
|
||||
MVR <axis><position>
|
||||
|
||||
GO HOME
|
||||
#######
|
||||
|
||||
SET VELOCITY
|
||||
VEL <axis><velocity>
|
||||
|
||||
Units: 0.01 to 999.999 um/ms
|
||||
|
||||
STOP MOTION
|
||||
STP <axis>
|
||||
|
||||
=================== STATUS =================
|
||||
|
||||
READ Version Info
|
||||
*IDN?
|
||||
Return:
|
||||
|
||||
|
||||
READ Commanded position
|
||||
MOV? <axis>
|
||||
Response: +0000.0000
|
||||
|
||||
READ Feedback position
|
||||
POS? <axis>
|
||||
Response: +0000.0000
|
||||
Units: micrometer or microradian
|
||||
|
||||
|
||||
READ Velocity (programmed)
|
||||
VEL? <axis>
|
||||
Response: 0.000000e+1
|
||||
|
||||
ON-TARGET:
|
||||
ONT? <Axis>
|
||||
0(false) or 1(true)
|
||||
SERVO ENABLE
|
||||
SVO? <axis>
|
||||
0 or 1
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
Digital Piezo Controller
|
||||
(c) 2003 Physik Instrumente GmbH
|
||||
|
||||
Model: E-710
|
||||
|
||||
Version: V5.023
|
||||
|
||||
RS232:
|
||||
9600,8,1,N (default)
|
||||
connection:
|
||||
db9 pin 2 (Rx) -> Tx
|
||||
db9 pin 3 (Tx) -> Rx
|
||||
db9 pin 5 (Com) -> Com
|
||||
db9 pin 7 \ -> n.c.
|
||||
db9 pin 8 / -> n.c.
|
||||
|
||||
Commands:
|
||||
<axis#><command>[<arg>]</n>
|
||||
Where axis# starts at 1.
|
||||
|
||||
* NO reply from motion commands
|
||||
* Multiple command delimiter = ","
|
||||
|
||||
Reply: <reply string></n>
|
||||
|
||||
|
||||
Position Resolution: 0.0001 micrometers
|
||||
Effective Resolution: 0.01 (holding position)
|
||||
|
||||
Setup:
|
||||
Position Error Tolerance Setting (Memory address 64)
|
||||
This parameter controls the "On Target" flag (GI8) that is
|
||||
used to determine DONE. If the tolerance is too large the
|
||||
motorRecord will see DONE before the drive has reached
|
||||
it target position.
|
||||
|
||||
Set the tolerance parameter to the retry deadband.
|
||||
|
||||
<axis>DP0,64DR<#.###> - sets RAM
|
||||
<axis>DP-1,64DR<#.###> - sets EERAM <used on power cycle>
|
||||
|
||||
example:
|
||||
1DP0,64DR0.01 - set tolerance to 0.01 um
|
||||
1DP-1,64DR0.01
|
||||
|
||||
=================== MOTION =================
|
||||
ENABLE Servo
|
||||
<axis#>SL[0/1]
|
||||
|
||||
|
||||
MOVE Absolute
|
||||
<axis#>MA<position>
|
||||
|
||||
MOVE Relative
|
||||
<axis#>MR<position>
|
||||
|
||||
GO HOME
|
||||
<axis#>GH
|
||||
|
||||
SET VELOCITY
|
||||
<axis#>SV<velocity>
|
||||
|
||||
Units: um/ms or urad/ms (float or int)
|
||||
|
||||
SET P-Term (Proportional Gain)
|
||||
<axis#>SP<p>
|
||||
|
||||
STOP MOTION ?
|
||||
<axis#>MR0 /* Zero relative move */
|
||||
<axis#>SV0 /* Zero velocity */
|
||||
|
||||
=================== STATUS =================
|
||||
|
||||
READ Version Info
|
||||
GI
|
||||
Return:
|
||||
Digital Piezo Controller V5.023<\n>
|
||||
(c) 2003 Physik Instrumente GmbH<\n>
|
||||
|
||||
|
||||
READ Commanded position
|
||||
<axis#>MA
|
||||
|
||||
Response: +0000.0000
|
||||
|
||||
READ Feedback position
|
||||
<axis#>TP - tell position
|
||||
Response: +0000.0000
|
||||
Units: micrometer or microradian
|
||||
<axis#>TS - tell sensor
|
||||
|
||||
|
||||
READ Velocity (programmed)
|
||||
<axis#>TV
|
||||
|
||||
Response: 0.000000e+1
|
||||
|
||||
READ Status:
|
||||
<axis#>GI8
|
||||
|
||||
Status Byte:
|
||||
Bit 0: 0 = Servo on, 1 = Servo off
|
||||
Bit 1: 0 = Piezo voltage inside limits,1 = Piezo voltage at limit
|
||||
Bit 2: 0 = On Target: Position error smaller than tolerance 1 = Position error too large
|
||||
Bit 3: 0 = Target position higher than low limit, 1 = Target Position at low limit
|
||||
Bit 4: 0 = Target position smaller than high limit, 1 = Target position at high limit.
|
||||
Bit 5: 0 = AutoZero is not running 1 = AutoZero is running
|
||||
Bit 6: not used
|
||||
Bit 7: 0 = no error, 1 = last sent command not accepted, error during command processing.
|
||||
[The bit is reset by this command.]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,326 +0,0 @@
|
||||
/* File: devPIC630.cc */
|
||||
|
||||
/* Device Support Routines for motor */
|
||||
/*
|
||||
* Original Author: Kurt Goetze
|
||||
* Date: 02-07-2005
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 02-07-2005 kag initialized from devMicos.c
|
||||
*/
|
||||
|
||||
/* Notes regarding the motor record / PI C-630:
|
||||
* 1. JogF and JogR are implemented as moves to the corresponding soft limit.
|
||||
* 2. HomeF and HomeR will simply move the positioner to the "0" position.
|
||||
* 3. The only position you may "set" is 0. Others will be ignored.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "motordevCom.h"
|
||||
#include "drvPIC630.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define NINT(f) (long)((f)>0 ? (f)+0.5 : (f)-0.5)
|
||||
|
||||
/*----------------debugging-----------------*/
|
||||
volatile int devPIC630debug = 0;
|
||||
extern "C" {epicsExportAddress(int, devPIC630debug);}
|
||||
static inline void Debug(int level, const char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
if (level < devPIC630debug) {
|
||||
va_list pVar;
|
||||
va_start(pVar, format);
|
||||
vprintf(format, pVar);
|
||||
va_end(pVar);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Debugging levels:
|
||||
* devPIC630debug >= 3 Print new part of command and command string so far
|
||||
* at the end of PIC630_build_trans
|
||||
*/
|
||||
|
||||
extern struct driver_table PIC630_access;
|
||||
|
||||
/* ----------------Create the dsets for devPIC630----------------- */
|
||||
static struct driver_table *drvtabptr;
|
||||
static long PIC630_init(int);
|
||||
static long PIC630_init_record(void *);
|
||||
static long PIC630_start_trans(struct motorRecord *);
|
||||
static RTN_STATUS PIC630_build_trans(motor_cmnd, double *, struct motorRecord *);
|
||||
static RTN_STATUS PIC630_end_trans(struct motorRecord *);
|
||||
|
||||
struct motor_dset devPIC630 =
|
||||
{
|
||||
{8, NULL, (DEVSUPFUN) PIC630_init, (DEVSUPFUN) PIC630_init_record, NULL},
|
||||
motor_update_values,
|
||||
PIC630_start_trans,
|
||||
PIC630_build_trans,
|
||||
PIC630_end_trans
|
||||
};
|
||||
|
||||
extern "C" {epicsExportAddress(dset,devPIC630);}
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
/* This table is used to define the command types */
|
||||
|
||||
static msg_types PIC630_table[] = {
|
||||
MOTION, /* MOVE_ABS */
|
||||
MOTION, /* MOVE_REL */
|
||||
MOTION, /* HOME_FOR */
|
||||
MOTION, /* HOME_REV */
|
||||
IMMEDIATE, /* LOAD_POS */
|
||||
IMMEDIATE, /* SET_VEL_BASE */
|
||||
IMMEDIATE, /* SET_VELOCITY */
|
||||
IMMEDIATE, /* SET_ACCEL */
|
||||
IMMEDIATE, /* GO */
|
||||
IMMEDIATE, /* SET_ENC_RATIO */
|
||||
INFO, /* GET_INFO */
|
||||
MOVE_TERM, /* STOP_AXIS */
|
||||
VELOCITY, /* JOG */
|
||||
IMMEDIATE, /* SET_PGAIN */
|
||||
IMMEDIATE, /* SET_IGAIN */
|
||||
IMMEDIATE, /* SET_DGAIN */
|
||||
IMMEDIATE, /* ENABLE_TORQUE */
|
||||
IMMEDIATE, /* DISABL_TORQUE */
|
||||
IMMEDIATE, /* PRIMITIVE */
|
||||
IMMEDIATE, /* SET_HIGH_LIMIT */
|
||||
IMMEDIATE, /* SET_LOW_LIMIT */
|
||||
VELOCITY /* JOG_VELOCITY */
|
||||
};
|
||||
|
||||
|
||||
static struct board_stat **PIC630_cards;
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
|
||||
/* initialize device support for PIC630 stepper motor */
|
||||
static long PIC630_init(int after)
|
||||
{
|
||||
long rtnval;
|
||||
|
||||
Debug(5, "PIC630_init: entry\n");
|
||||
if (!after)
|
||||
{
|
||||
drvtabptr = &PIC630_access;
|
||||
(drvtabptr->init)();
|
||||
}
|
||||
|
||||
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &PIC630_cards);
|
||||
Debug(5, "PIC630_init: exit\n");
|
||||
return(rtnval);
|
||||
}
|
||||
|
||||
|
||||
/* initialize a record instance */
|
||||
static long PIC630_init_record(void *arg)
|
||||
{
|
||||
struct motorRecord *mr = (struct motorRecord *) arg;
|
||||
return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, PIC630_cards));
|
||||
}
|
||||
|
||||
|
||||
/* start building a transaction */
|
||||
static long PIC630_start_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_start_trans_com(mr, PIC630_cards);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* end building a transaction */
|
||||
static RTN_STATUS PIC630_end_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_end_trans_com(mr, drvtabptr);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/* add a part to the transaction */
|
||||
static RTN_STATUS PIC630_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
struct controller *brdptr;
|
||||
struct PIC630Controller *cntrl;
|
||||
char buff[30];
|
||||
int axis, card;
|
||||
RTN_STATUS rtnval;
|
||||
bool send;
|
||||
double dval; /* placeholder for double values passed from motor record */
|
||||
long ival; /* placeholder for ints passed from motor record */
|
||||
|
||||
send = true; /* default to send motor command */
|
||||
rtnval = OK;
|
||||
buff[0] = '\0';
|
||||
/* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */
|
||||
dval = (parms == NULL) ? 0.0 : *parms;
|
||||
|
||||
ival = NINT(dval);
|
||||
|
||||
rtnval = (RTN_STATUS) motor_start_trans_com(mr, PIC630_cards);
|
||||
Debug(5, "PIC630_build_trans: entry, motor_start_trans_com=%d\n", rtnval);
|
||||
|
||||
motor_call = &(trans->motor_call);
|
||||
motor_call->type = PIC630_table[command];
|
||||
card = motor_call->card; /* card is the group of drivers per unique serial port */
|
||||
axis = motor_call->signal; /* axis is PIC630 address, up to 9 (1-9) per serial port */
|
||||
axis++; /* Note: Each PIC630 driver drives up to 3 motors */
|
||||
brdptr = (*trans->tabptr->card_array)[card];
|
||||
Debug(5, "PIC630_build_trans: axis=%d, command=%d\n", axis, command);
|
||||
if (brdptr == NULL)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
cntrl = (struct PIC630Controller *) brdptr->DevicePrivate;
|
||||
|
||||
|
||||
if (trans->state != BUILD_STATE)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
|
||||
{
|
||||
strcpy(motor_call->message, mr->init);
|
||||
rtnval = motor_end_trans_com(mr, drvtabptr);
|
||||
rtnval = (RTN_STATUS) motor_start_trans_com(mr, PIC630_cards);
|
||||
motor_call->type = PIC630_table[command];
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
case MOVE_REL:
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
case JOG:
|
||||
if (strlen(mr->prem) != 0)
|
||||
{
|
||||
strcpy(motor_call->message, mr->prem);
|
||||
rtnval = motor_end_trans_com(mr, drvtabptr);
|
||||
rtnval = (RTN_STATUS) motor_start_trans_com(mr, PIC630_cards);
|
||||
motor_call->type = PIC630_table[command];
|
||||
}
|
||||
if (strlen(mr->post) != 0)
|
||||
motor_call->postmsgptr = (char *) &mr->post;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
sprintf(motor_call->message, "%dMA%ld", axis, ival);
|
||||
break;
|
||||
case MOVE_REL:
|
||||
sprintf(motor_call->message, "%dMR%ld", axis, ival);
|
||||
break;
|
||||
case HOME_FOR:
|
||||
sprintf(motor_call->message, "%dMA0", axis);
|
||||
break;
|
||||
case HOME_REV:
|
||||
sprintf(motor_call->message, "%dMA0", axis);
|
||||
break;
|
||||
case LOAD_POS: /* PIC630 allows you to define the zero position only */
|
||||
if (dval == 0.0)
|
||||
sprintf(motor_call->message, "%dDH", axis);
|
||||
else
|
||||
rtnval = ERROR;
|
||||
break;
|
||||
case SET_VEL_BASE:
|
||||
send = false;
|
||||
trans->state = IDLE_STATE;
|
||||
break; /* PIC630 does not use base velocity */
|
||||
case SET_VELOCITY:
|
||||
if (ival < 1) ival = 1;
|
||||
if (ival > 200000) ival = 200000;
|
||||
sprintf(motor_call->message, "%dSV%ld", axis, ival);
|
||||
break;
|
||||
case SET_ACCEL:
|
||||
/* dval is acceleration in steps/sec/sec */
|
||||
if (ival < 0) ival = 0;
|
||||
if (ival > 500000) ival = 500000;
|
||||
sprintf(motor_call->message, "%dSA%ld", axis, ival);
|
||||
break;
|
||||
case GO:
|
||||
/*
|
||||
* The PIC630 starts moving immediately on move commands, GO command
|
||||
* does nothing
|
||||
*/
|
||||
send = false;
|
||||
trans->state = IDLE_STATE;
|
||||
break;
|
||||
case SET_ENC_RATIO:
|
||||
/*
|
||||
* The PIC630 does not have the concept of encoder ratio, ignore this
|
||||
* command
|
||||
*/
|
||||
send = false;
|
||||
trans->state = IDLE_STATE;
|
||||
break;
|
||||
case GET_INFO:
|
||||
/* ? what is this for ? */
|
||||
break;
|
||||
case STOP_AXIS: /* (decelerate to a) stop */
|
||||
sprintf(motor_call->message, "%dST", axis);
|
||||
break;
|
||||
case JOG:
|
||||
/*
|
||||
* PIC630 does not have a jog command. Simulate with move absolute
|
||||
* to the appropriate software limit. The record will prevent JOG motion
|
||||
* beyond its soft limits
|
||||
* First we send the Jog velocity...
|
||||
*/
|
||||
ival = (long) fabs((double) ival);
|
||||
if (ival < 1) ival = 1;
|
||||
if (ival > 200000) ival = 200000;
|
||||
sprintf(motor_call->message, "%dSV%ld", axis, ival);
|
||||
rtnval = motor_end_trans_com(mr, drvtabptr);
|
||||
rtnval = (RTN_STATUS) motor_start_trans_com(mr, PIC630_cards);
|
||||
motor_call->type = PIC630_table[command];
|
||||
if (dval > 0.) /* jog pos */
|
||||
sprintf(motor_call->message, "%dMA%ld", axis, (long)(mr->dhlm / mr->mres));
|
||||
else /* jog neg */
|
||||
sprintf(motor_call->message, "%dMA%ld", axis, (long)(mr->dllm / mr->mres));
|
||||
break;
|
||||
|
||||
case SET_PGAIN:
|
||||
break;
|
||||
|
||||
case SET_IGAIN:
|
||||
break;
|
||||
|
||||
case SET_DGAIN:
|
||||
break;
|
||||
|
||||
case ENABLE_TORQUE:
|
||||
break;
|
||||
|
||||
case DISABL_TORQUE:
|
||||
break;
|
||||
|
||||
case SET_HIGH_LIMIT:
|
||||
case SET_LOW_LIMIT:
|
||||
trans->state = IDLE_STATE;
|
||||
break;
|
||||
|
||||
default:
|
||||
send = false;
|
||||
rtnval = ERROR;
|
||||
}
|
||||
|
||||
if (send == false)
|
||||
return(rtnval);
|
||||
else
|
||||
{
|
||||
rtnval = motor_end_trans_com(mr, drvtabptr);
|
||||
Debug(5, "PIC630_send_msg: motor_end_trans_com status=%d, exit\n", rtnval);
|
||||
return(rtnval);
|
||||
}
|
||||
}
|
||||
@@ -1,301 +0,0 @@
|
||||
/*
|
||||
FILENAME... devPIC662.cc
|
||||
USAGE... Motor record device level support for Physik Instrumente (PI)
|
||||
GmbH & Co. C-844 motor controller.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 12/17/03
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 03/08/06 jps - copied from devPI.cc
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "motordevCom.h"
|
||||
#include "epicsExport.h"
|
||||
#include "drvPIC662.h"
|
||||
|
||||
extern struct driver_table PIC662_access;
|
||||
|
||||
/* ----------------Create the dsets for devPIC662----------------- */
|
||||
static struct driver_table *drvtabptr;
|
||||
static long PIC662_init(int);
|
||||
static long PIC662_init_record(void *);
|
||||
static long PIC662_start_trans(struct motorRecord *);
|
||||
static RTN_STATUS PIC662_build_trans(motor_cmnd, double *, struct motorRecord *);
|
||||
static RTN_STATUS PIC662_end_trans(struct motorRecord *);
|
||||
|
||||
struct motor_dset devPIC662 =
|
||||
{
|
||||
{8, NULL, (DEVSUPFUN) PIC662_init, (DEVSUPFUN) PIC662_init_record, NULL},
|
||||
motor_update_values,
|
||||
PIC662_start_trans,
|
||||
PIC662_build_trans,
|
||||
PIC662_end_trans
|
||||
};
|
||||
|
||||
extern "C" {epicsExportAddress(dset,devPIC662);}
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
/* This table is used to define the command types */
|
||||
/* WARNING! this must match "motor_cmnd" in motor.h */
|
||||
|
||||
static msg_types PIC662_table[] = {
|
||||
MOTION, /* MOVE_ABS */
|
||||
MOTION, /* MOVE_REL */
|
||||
MOTION, /* HOME_FOR */
|
||||
MOTION, /* HOME_REV */
|
||||
IMMEDIATE, /* LOAD_POS */
|
||||
IMMEDIATE, /* SET_VEL_BASE */
|
||||
IMMEDIATE, /* SET_VELOCITY */
|
||||
IMMEDIATE, /* SET_ACCEL */
|
||||
IMMEDIATE, /* GO */
|
||||
IMMEDIATE, /* SET_ENC_RATIO */
|
||||
INFO, /* GET_INFO */
|
||||
MOVE_TERM, /* STOP_AXIS */
|
||||
VELOCITY, /* JOG */
|
||||
IMMEDIATE, /* SET_PGAIN */
|
||||
IMMEDIATE, /* SET_IGAIN */
|
||||
IMMEDIATE, /* SET_DGAIN */
|
||||
IMMEDIATE, /* ENABLE_TORQUE */
|
||||
IMMEDIATE, /* DISABL_TORQUE */
|
||||
IMMEDIATE, /* PRIMITIVE */
|
||||
IMMEDIATE, /* SET_HIGH_LIMIT */
|
||||
IMMEDIATE, /* SET_LOW_LIMIT */
|
||||
VELOCITY /* JOG_VELOCITY */
|
||||
};
|
||||
|
||||
|
||||
static struct board_stat **PIC662_cards;
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
|
||||
/* initialize device support for PIC662 stepper motor */
|
||||
static long PIC662_init(int after)
|
||||
{
|
||||
long rtnval;
|
||||
|
||||
if (!after)
|
||||
{
|
||||
drvtabptr = &PIC662_access;
|
||||
(drvtabptr->init)();
|
||||
}
|
||||
|
||||
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &PIC662_cards);
|
||||
return(rtnval);
|
||||
}
|
||||
|
||||
|
||||
/* initialize a record instance */
|
||||
static long PIC662_init_record(void *arg)
|
||||
{
|
||||
struct motorRecord *mr = (struct motorRecord *) arg;
|
||||
return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, PIC662_cards));
|
||||
}
|
||||
|
||||
|
||||
/* start building a transaction */
|
||||
static long PIC662_start_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_start_trans_com(mr, PIC662_cards);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* end building a transaction */
|
||||
static RTN_STATUS PIC662_end_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_end_trans_com(mr, drvtabptr);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* add a part to the transaction */
|
||||
static RTN_STATUS PIC662_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
struct controller *brdptr;
|
||||
struct PIC662controller *cntrl;
|
||||
char buff[110];
|
||||
int axis, card, maxdigits;
|
||||
unsigned int size;
|
||||
double dval, cntrl_units;
|
||||
RTN_STATUS rtnval;
|
||||
bool send;
|
||||
|
||||
send = true; /* Default to send motor command. */
|
||||
rtnval = OK;
|
||||
buff[0] = '\0';
|
||||
|
||||
/* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */
|
||||
dval = (parms == NULL) ? 0.0 : *parms;
|
||||
|
||||
motor_call = &(trans->motor_call);
|
||||
card = motor_call->card;
|
||||
axis = motor_call->signal + 1;
|
||||
brdptr = (*trans->tabptr->card_array)[card];
|
||||
if (brdptr == NULL)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
cntrl = (struct PIC662controller *) brdptr->DevicePrivate;
|
||||
|
||||
maxdigits = cntrl->res_decpts;
|
||||
cntrl_units = dval * cntrl->drive_resolution;
|
||||
|
||||
if (PIC662_table[command] > motor_call->type)
|
||||
motor_call->type = PIC662_table[command];
|
||||
|
||||
if (trans->state != BUILD_STATE)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
|
||||
strcat(motor_call->message, mr->init);
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
case MOVE_REL:
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
case JOG:
|
||||
if (strlen(mr->prem) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->prem);
|
||||
strcat(motor_call->message, ";");
|
||||
}
|
||||
if (strlen(mr->post) != 0)
|
||||
motor_call->postmsgptr = (char *) &mr->post;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
sprintf(buff, "DEV:CONT REM\nPOS %.*f", maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case MOVE_REL:
|
||||
sprintf(buff, "DEV:CONT REM\nPOS:REL %.*f", maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case LOAD_POS:
|
||||
send = false; /* Can't Load a Position */
|
||||
break;
|
||||
|
||||
case SET_VEL_BASE:
|
||||
|
||||
break;
|
||||
|
||||
case SET_VELOCITY:
|
||||
send = false; /* DC motor; not base velocity. */
|
||||
break;
|
||||
|
||||
case SET_ACCEL:
|
||||
send = false; /* DC motor; not base velocity. */
|
||||
break;
|
||||
|
||||
case GO:
|
||||
/* The PIC662 starts moving immediately on move commands, GO command
|
||||
* does nothing. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case PRIMITIVE:
|
||||
case GET_INFO:
|
||||
/* These commands are not actually done by sending a message, but
|
||||
rather they will indirectly cause the driver to read the status
|
||||
of all motors */
|
||||
break;
|
||||
|
||||
case STOP_AXIS:
|
||||
// Force device polling to stop.
|
||||
// There is no HALT command to the motor controller
|
||||
cntrl->stop_status = true;
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case JOG_VELOCITY:
|
||||
case JOG:
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case SET_PGAIN:
|
||||
send = false;
|
||||
break;
|
||||
case SET_IGAIN:
|
||||
send = false;
|
||||
break;
|
||||
case SET_DGAIN:
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case ENABLE_TORQUE:
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case DISABL_TORQUE:
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case SET_HIGH_LIMIT:
|
||||
case SET_LOW_LIMIT:
|
||||
case SET_ENC_RATIO:
|
||||
trans->state = IDLE_STATE; /* No command sent to the controller. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
send = false;
|
||||
rtnval = ERROR;
|
||||
}
|
||||
|
||||
size = strlen(buff);
|
||||
if (send == false)
|
||||
return(rtnval);
|
||||
else if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE)
|
||||
errlogMessage("PIC662_build_trans(): buffer overflow.\n");
|
||||
else
|
||||
strcat(motor_call->message, buff);
|
||||
return(rtnval);
|
||||
}
|
||||
@@ -1,306 +0,0 @@
|
||||
/*
|
||||
FILENAME... devPIC663.cc
|
||||
USAGE... Motor record device level support for Physik Instrumente (PI)
|
||||
GmbH & Co. C-663 motor controller.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copied from devPIC862.cc by Jonathan Thompson, Jan 2011
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* Jan 2011 - All references to 862 changed to 663
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "motordevCom.h"
|
||||
#include "drvPIC663.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern struct driver_table PIC663_access;
|
||||
|
||||
/* ----------------Create the dsets for devPIC663----------------- */
|
||||
static struct driver_table *drvtabptr;
|
||||
static long PIC663_init(int);
|
||||
static long PIC663_init_record(void *);
|
||||
static long PIC663_start_trans(struct motorRecord *);
|
||||
static RTN_STATUS PIC663_build_trans(motor_cmnd, double *, struct motorRecord *);
|
||||
static RTN_STATUS PIC663_end_trans(struct motorRecord *);
|
||||
|
||||
struct motor_dset devPIC663 =
|
||||
{
|
||||
{8, NULL, (DEVSUPFUN) PIC663_init, (DEVSUPFUN) PIC663_init_record, NULL},
|
||||
motor_update_values,
|
||||
PIC663_start_trans,
|
||||
PIC663_build_trans,
|
||||
PIC663_end_trans
|
||||
};
|
||||
|
||||
extern "C" {epicsExportAddress(dset,devPIC663);}
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
/* This table is used to define the command types */
|
||||
/* WARNING! this must match "motor_cmnd" in motor.h */
|
||||
|
||||
static msg_types PIC663_table[] = {
|
||||
MOTION, /* MOVE_ABS */
|
||||
MOTION, /* MOVE_REL */
|
||||
MOTION, /* HOME_FOR */
|
||||
MOTION, /* HOME_REV */
|
||||
IMMEDIATE, /* LOAD_POS */
|
||||
IMMEDIATE, /* SET_VEL_BASE */
|
||||
IMMEDIATE, /* SET_VELOCITY */
|
||||
IMMEDIATE, /* SET_ACCEL */
|
||||
IMMEDIATE, /* GO */
|
||||
IMMEDIATE, /* SET_ENC_RATIO */
|
||||
INFO, /* GET_INFO */
|
||||
MOVE_TERM, /* STOP_AXIS */
|
||||
VELOCITY, /* JOG */
|
||||
IMMEDIATE, /* SET_PGAIN */
|
||||
IMMEDIATE, /* SET_IGAIN */
|
||||
IMMEDIATE, /* SET_DGAIN */
|
||||
IMMEDIATE, /* ENABLE_TORQUE */
|
||||
IMMEDIATE, /* DISABL_TORQUE */
|
||||
IMMEDIATE, /* PRIMITIVE */
|
||||
IMMEDIATE, /* SET_HIGH_LIMIT */
|
||||
IMMEDIATE, /* SET_LOW_LIMIT */
|
||||
VELOCITY /* JOG_VELOCITY */
|
||||
};
|
||||
|
||||
|
||||
static struct board_stat **PIC663_cards;
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
|
||||
/* initialize device support for PIC663 servo motor */
|
||||
static long PIC663_init(int after)
|
||||
{
|
||||
long rtnval;
|
||||
|
||||
if (!after)
|
||||
{
|
||||
drvtabptr = &PIC663_access;
|
||||
(drvtabptr->init)();
|
||||
}
|
||||
|
||||
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &PIC663_cards);
|
||||
return(rtnval);
|
||||
}
|
||||
|
||||
|
||||
/* initialize a record instance */
|
||||
static long PIC663_init_record(void *arg)
|
||||
{
|
||||
struct motorRecord *mr = (struct motorRecord *) arg;
|
||||
return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, PIC663_cards));
|
||||
}
|
||||
|
||||
|
||||
/* start building a transaction */
|
||||
static long PIC663_start_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_start_trans_com(mr, PIC663_cards);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* end building a transaction */
|
||||
static RTN_STATUS PIC663_end_trans(struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
char *msgptr;
|
||||
int last;
|
||||
|
||||
/* Remove trailing cmnd separator (",") from message. */
|
||||
motor_call = &(trans->motor_call);
|
||||
msgptr = motor_call->message;
|
||||
last = strlen(msgptr) - 1;
|
||||
if (msgptr[last] == ',')
|
||||
msgptr[last] = (char) NULL;
|
||||
|
||||
motor_end_trans_com(mr, drvtabptr);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* add a part to the transaction */
|
||||
static RTN_STATUS PIC663_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
struct controller *brdptr;
|
||||
char buff[110];
|
||||
int card;
|
||||
unsigned int size;
|
||||
double dval;
|
||||
int cntrl_units;
|
||||
RTN_STATUS rtnval;
|
||||
bool send;
|
||||
|
||||
send = true; /* Default to send motor command. */
|
||||
rtnval = OK;
|
||||
buff[0] = '\0';
|
||||
|
||||
/* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */
|
||||
dval = (parms == NULL) ? 0.0 : *parms;
|
||||
|
||||
|
||||
motor_call = &(trans->motor_call);
|
||||
card = motor_call->card;
|
||||
brdptr = (*trans->tabptr->card_array)[card];
|
||||
if (brdptr == NULL)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
|
||||
cntrl_units = (int) dval;
|
||||
|
||||
if (PIC663_table[command] > motor_call->type)
|
||||
motor_call->type = PIC663_table[command];
|
||||
|
||||
if (trans->state != BUILD_STATE)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
|
||||
strcat(motor_call->message, mr->init);
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
case MOVE_REL:
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
case JOG:
|
||||
if (strlen(mr->prem) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->prem);
|
||||
strcat(motor_call->message, ",");
|
||||
}
|
||||
if (strlen(mr->post) != 0)
|
||||
motor_call->postmsgptr = (char *) &mr->post;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
sprintf(buff, "MA%d,", cntrl_units);
|
||||
break;
|
||||
|
||||
case MOVE_REL:
|
||||
sprintf(buff, "MR%d,", cntrl_units);
|
||||
break;
|
||||
|
||||
case HOME_FOR:
|
||||
sprintf(buff, "FE0");
|
||||
break;
|
||||
case HOME_REV:
|
||||
sprintf(buff, "FE1");
|
||||
break;
|
||||
|
||||
case LOAD_POS:
|
||||
if (cntrl_units == 0.0)
|
||||
sprintf(buff, "DH");
|
||||
else
|
||||
rtnval = ERROR;
|
||||
break;
|
||||
|
||||
case SET_VEL_BASE:
|
||||
send = false; /* DC motor; not base velocity. */
|
||||
break;
|
||||
|
||||
case JOG_VELOCITY:
|
||||
case SET_VELOCITY:
|
||||
sprintf(buff, "SV%d,", cntrl_units);
|
||||
break;
|
||||
|
||||
case SET_ACCEL:
|
||||
sprintf(buff, "SA%d,", cntrl_units);
|
||||
break;
|
||||
|
||||
case ENABLE_TORQUE:
|
||||
sprintf(buff, "MN");
|
||||
break;
|
||||
|
||||
case DISABL_TORQUE:
|
||||
sprintf(buff, "MF");
|
||||
break;
|
||||
|
||||
case GO:
|
||||
/* The PIC663 starts moving immediately on move commands, GO command
|
||||
* does nothing. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case PRIMITIVE:
|
||||
case GET_INFO:
|
||||
/* These commands are not actually done by sending a message, but
|
||||
rather they will indirectly cause the driver to read the status
|
||||
of all motors */
|
||||
break;
|
||||
|
||||
case STOP_AXIS:
|
||||
sprintf(buff, "ST");
|
||||
break;
|
||||
|
||||
case JOG:
|
||||
/*
|
||||
* C-663 does not have a jog command. Simulate with move absolute
|
||||
* to the appropriate software limit.
|
||||
*/
|
||||
sprintf(buff, "SV%d,", abs(cntrl_units));
|
||||
strcat(motor_call->message, buff);
|
||||
if (dval > 0.)
|
||||
sprintf(buff, "MA%d,", (int) (mr->dhlm / mr->mres));
|
||||
else
|
||||
sprintf(buff, "MA%d,", (int) (mr->dllm / mr->mres));
|
||||
break;
|
||||
|
||||
case SET_PGAIN:
|
||||
cntrl_units = (int) (32767 * dval);
|
||||
sprintf(buff, "DP%d", cntrl_units);
|
||||
break;
|
||||
case SET_IGAIN:
|
||||
cntrl_units = (int) (32767 * dval);
|
||||
sprintf(buff, "DI%d", cntrl_units);
|
||||
break;
|
||||
case SET_DGAIN:
|
||||
cntrl_units = (int) (32767 * dval);
|
||||
sprintf(buff, "DD%d", cntrl_units);
|
||||
break;
|
||||
|
||||
case SET_HIGH_LIMIT:
|
||||
case SET_LOW_LIMIT:
|
||||
case SET_ENC_RATIO:
|
||||
trans->state = IDLE_STATE; /* No command sent to the controller. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
send = false;
|
||||
rtnval = ERROR;
|
||||
}
|
||||
|
||||
size = strlen(buff);
|
||||
if (send == false)
|
||||
return(rtnval);
|
||||
else if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE)
|
||||
errlogMessage("PIC663_build_trans(): buffer overflow.\n");
|
||||
else
|
||||
{
|
||||
strcat(motor_call->message, buff);
|
||||
}
|
||||
return(rtnval);
|
||||
}
|
||||
@@ -1,300 +0,0 @@
|
||||
/*
|
||||
FILENAME... devPIC844.cc
|
||||
USAGE... Motor record device level support for Physik Instrumente (PI)
|
||||
GmbH & Co. C-844 motor controller.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 12/17/03
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 12/17/03 rls - copied from devIM483PL.cc
|
||||
* .02 01/22/03 rls - fix INIT field processing; support HOME and PID commands.
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "motordevCom.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern struct driver_table PIC844_access;
|
||||
|
||||
/* ----------------Create the dsets for devPIC844----------------- */
|
||||
static struct driver_table *drvtabptr;
|
||||
static long PIC844_init(int);
|
||||
static long PIC844_init_record(void *);
|
||||
static long PIC844_start_trans(struct motorRecord *);
|
||||
static RTN_STATUS PIC844_build_trans(motor_cmnd, double *, struct motorRecord *);
|
||||
static RTN_STATUS PIC844_end_trans(struct motorRecord *);
|
||||
|
||||
struct motor_dset devPIC844 =
|
||||
{
|
||||
{8, NULL, (DEVSUPFUN) PIC844_init, (DEVSUPFUN) PIC844_init_record, NULL},
|
||||
motor_update_values,
|
||||
PIC844_start_trans,
|
||||
PIC844_build_trans,
|
||||
PIC844_end_trans
|
||||
};
|
||||
|
||||
extern "C" {epicsExportAddress(dset,devPIC844);}
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
/* This table is used to define the command types */
|
||||
/* WARNING! this must match "motor_cmnd" in motor.h */
|
||||
|
||||
static msg_types PIC844_table[] = {
|
||||
MOTION, /* MOVE_ABS */
|
||||
MOTION, /* MOVE_REL */
|
||||
MOTION, /* HOME_FOR */
|
||||
MOTION, /* HOME_REV */
|
||||
IMMEDIATE, /* LOAD_POS */
|
||||
IMMEDIATE, /* SET_VEL_BASE */
|
||||
IMMEDIATE, /* SET_VELOCITY */
|
||||
IMMEDIATE, /* SET_ACCEL */
|
||||
IMMEDIATE, /* GO */
|
||||
IMMEDIATE, /* SET_ENC_RATIO */
|
||||
INFO, /* GET_INFO */
|
||||
MOVE_TERM, /* STOP_AXIS */
|
||||
VELOCITY, /* JOG */
|
||||
IMMEDIATE, /* SET_PGAIN */
|
||||
IMMEDIATE, /* SET_IGAIN */
|
||||
IMMEDIATE, /* SET_DGAIN */
|
||||
IMMEDIATE, /* ENABLE_TORQUE */
|
||||
IMMEDIATE, /* DISABL_TORQUE */
|
||||
IMMEDIATE, /* PRIMITIVE */
|
||||
IMMEDIATE, /* SET_HIGH_LIMIT */
|
||||
IMMEDIATE, /* SET_LOW_LIMIT */
|
||||
VELOCITY /* JOG_VELOCITY */
|
||||
};
|
||||
|
||||
|
||||
static struct board_stat **PIC844_cards;
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
|
||||
/* initialize device support for PIC844 stepper motor */
|
||||
static long PIC844_init(int after)
|
||||
{
|
||||
long rtnval;
|
||||
|
||||
if (!after)
|
||||
{
|
||||
drvtabptr = &PIC844_access;
|
||||
(drvtabptr->init)();
|
||||
}
|
||||
|
||||
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &PIC844_cards);
|
||||
return(rtnval);
|
||||
}
|
||||
|
||||
|
||||
/* initialize a record instance */
|
||||
static long PIC844_init_record(void *arg)
|
||||
{
|
||||
struct motorRecord *mr = (struct motorRecord *) arg;
|
||||
return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, PIC844_cards));
|
||||
}
|
||||
|
||||
|
||||
/* start building a transaction */
|
||||
static long PIC844_start_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_start_trans_com(mr, PIC844_cards);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* end building a transaction */
|
||||
static RTN_STATUS PIC844_end_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_end_trans_com(mr, drvtabptr);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* add a part to the transaction */
|
||||
static RTN_STATUS PIC844_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
struct controller *brdptr;
|
||||
char buff[110];
|
||||
int axis, card, maxdigits;
|
||||
unsigned int size;
|
||||
double dval, cntrl_units;
|
||||
RTN_STATUS rtnval;
|
||||
bool send;
|
||||
|
||||
send = true; /* Default to send motor command. */
|
||||
rtnval = OK;
|
||||
buff[0] = '\0';
|
||||
|
||||
/* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */
|
||||
dval = (parms == NULL) ? 0.0 : *parms;
|
||||
|
||||
motor_call = &(trans->motor_call);
|
||||
card = motor_call->card;
|
||||
axis = motor_call->signal + 1;
|
||||
brdptr = (*trans->tabptr->card_array)[card];
|
||||
if (brdptr == NULL)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
cntrl_units = dval;
|
||||
maxdigits = 2;
|
||||
|
||||
if (PIC844_table[command] > motor_call->type)
|
||||
motor_call->type = PIC844_table[command];
|
||||
|
||||
if (trans->state != BUILD_STATE)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
|
||||
strcat(motor_call->message, mr->init);
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
case MOVE_REL:
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
case JOG:
|
||||
if (strlen(mr->prem) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->prem);
|
||||
strcat(motor_call->message, ";");
|
||||
}
|
||||
if (strlen(mr->post) != 0)
|
||||
motor_call->postmsgptr = (char *) &mr->post;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
sprintf(buff, "TARG %.*f", maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case MOVE_REL:
|
||||
sprintf(buff, "TARG:RPOS %+.*f", maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case HOME_FOR:
|
||||
sprintf(buff, "TARG:FIND POS");
|
||||
break;
|
||||
case HOME_REV:
|
||||
sprintf(buff, "TARG:FIND NEG");
|
||||
break;
|
||||
|
||||
case LOAD_POS:
|
||||
sprintf(buff, "AXIS:POS %+.*f;TARG CURR", maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case SET_VEL_BASE:
|
||||
send = false; /* DC motor; not base velocity. */
|
||||
break;
|
||||
|
||||
case SET_VELOCITY:
|
||||
sprintf(buff, "MVEL %.*f;", maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case SET_ACCEL:
|
||||
sprintf(buff, "ACC %.*f;", maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case GO:
|
||||
/* The PIC844 starts moving immediately on move commands, GO command
|
||||
* does nothing. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case PRIMITIVE:
|
||||
case GET_INFO:
|
||||
/* These commands are not actually done by sending a message, but
|
||||
rather they will indirectly cause the driver to read the status
|
||||
of all motors */
|
||||
break;
|
||||
|
||||
case STOP_AXIS:
|
||||
sprintf(buff, "HALT");
|
||||
break;
|
||||
|
||||
case JOG_VELOCITY:
|
||||
case JOG:
|
||||
sprintf(buff, "TARG:VEL %.*f", maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case SET_PGAIN:
|
||||
cntrl_units *= 32767;
|
||||
sprintf(buff, "PID %.*f,,", maxdigits, cntrl_units);
|
||||
break;
|
||||
case SET_IGAIN:
|
||||
cntrl_units *= 32767;
|
||||
sprintf(buff, "PID ,%.*f,", maxdigits, cntrl_units);
|
||||
break;
|
||||
case SET_DGAIN:
|
||||
cntrl_units *= 32767;
|
||||
sprintf(buff, "PID ,,%.*f", maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case ENABLE_TORQUE:
|
||||
sprintf(buff, "AXIS:STAT ON");
|
||||
break;
|
||||
|
||||
case DISABL_TORQUE:
|
||||
sprintf(buff, "AXIS:STAT OFF");
|
||||
break;
|
||||
|
||||
case SET_HIGH_LIMIT:
|
||||
case SET_LOW_LIMIT:
|
||||
case SET_ENC_RATIO:
|
||||
trans->state = IDLE_STATE; /* No command sent to the controller. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
send = false;
|
||||
rtnval = ERROR;
|
||||
}
|
||||
|
||||
size = strlen(buff);
|
||||
if (send == false)
|
||||
return(rtnval);
|
||||
else if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE)
|
||||
errlogMessage("PIC844_build_trans(): buffer overflow.\n");
|
||||
else
|
||||
strcat(motor_call->message, buff);
|
||||
return(rtnval);
|
||||
}
|
||||
@@ -1,329 +0,0 @@
|
||||
/*
|
||||
FILENAME... devPIC848.cc
|
||||
USAGE... Motor record device level support for Physik Instrumente (PI)
|
||||
GmbH & Co. C-848 motor controller.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 12/17/03
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 12/17/03 rls - copied from devIM483PL.cc
|
||||
* .02 01/22/03 rls - fix INIT field processing; support HOME and PID commands.
|
||||
* .03 10/17/07 rls - Due LOAD_POS based on "reference" indicator.
|
||||
* - If torque is disabled, clear error conditions before
|
||||
* ENABLE_TORQUE command.
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "motordevCom.h"
|
||||
#include "drvPIC848.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern struct driver_table PIC848_access;
|
||||
|
||||
/* ----------------Create the dsets for devPIC848----------------- */
|
||||
static struct driver_table *drvtabptr;
|
||||
static long PIC848_init(int);
|
||||
static long PIC848_init_record(void *);
|
||||
static long PIC848_start_trans(struct motorRecord *);
|
||||
static RTN_STATUS PIC848_build_trans(motor_cmnd, double *, struct motorRecord *);
|
||||
static RTN_STATUS PIC848_end_trans(struct motorRecord *);
|
||||
|
||||
struct motor_dset devPIC848 =
|
||||
{
|
||||
{8, NULL, (DEVSUPFUN) PIC848_init, (DEVSUPFUN) PIC848_init_record, NULL},
|
||||
motor_update_values,
|
||||
PIC848_start_trans,
|
||||
PIC848_build_trans,
|
||||
PIC848_end_trans
|
||||
};
|
||||
|
||||
extern "C" {epicsExportAddress(dset,devPIC848);}
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
/* This table is used to define the command types */
|
||||
/* WARNING! this must match "motor_cmnd" in motor.h */
|
||||
|
||||
static msg_types PIC848_table[] = {
|
||||
MOTION, /* MOVE_ABS */
|
||||
MOTION, /* MOVE_REL */
|
||||
MOTION, /* HOME_FOR */
|
||||
MOTION, /* HOME_REV */
|
||||
IMMEDIATE, /* LOAD_POS */
|
||||
IMMEDIATE, /* SET_VEL_BASE */
|
||||
IMMEDIATE, /* SET_VELOCITY */
|
||||
IMMEDIATE, /* SET_ACCEL */
|
||||
IMMEDIATE, /* GO */
|
||||
IMMEDIATE, /* SET_ENC_RATIO */
|
||||
INFO, /* GET_INFO */
|
||||
MOVE_TERM, /* STOP_AXIS */
|
||||
VELOCITY, /* JOG */
|
||||
IMMEDIATE, /* SET_PGAIN */
|
||||
IMMEDIATE, /* SET_IGAIN */
|
||||
IMMEDIATE, /* SET_DGAIN */
|
||||
IMMEDIATE, /* ENABLE_TORQUE */
|
||||
IMMEDIATE, /* DISABL_TORQUE */
|
||||
IMMEDIATE, /* PRIMITIVE */
|
||||
IMMEDIATE, /* SET_HIGH_LIMIT */
|
||||
IMMEDIATE, /* SET_LOW_LIMIT */
|
||||
VELOCITY /* JOG_VELOCITY */
|
||||
};
|
||||
|
||||
|
||||
static struct board_stat **PIC848_cards;
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
|
||||
/* initialize device support for PIC848 stepper motor */
|
||||
static long PIC848_init(int after)
|
||||
{
|
||||
long rtnval;
|
||||
|
||||
if (!after)
|
||||
{
|
||||
drvtabptr = &PIC848_access;
|
||||
(drvtabptr->init)();
|
||||
}
|
||||
|
||||
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &PIC848_cards);
|
||||
return(rtnval);
|
||||
}
|
||||
|
||||
|
||||
/* initialize a record instance */
|
||||
static long PIC848_init_record(void *arg)
|
||||
{
|
||||
struct motorRecord *mr = (struct motorRecord *) arg;
|
||||
return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, PIC848_cards));
|
||||
}
|
||||
|
||||
|
||||
/* start building a transaction */
|
||||
static long PIC848_start_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_start_trans_com(mr, PIC848_cards);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* end building a transaction */
|
||||
static RTN_STATUS PIC848_end_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_end_trans_com(mr, drvtabptr);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* add a part to the transaction */
|
||||
static RTN_STATUS PIC848_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
struct controller *brdptr;
|
||||
struct PIC848controller *cntrl;
|
||||
char buff[110];
|
||||
int card, maxdigits;
|
||||
unsigned int size;
|
||||
double dval, cntrl_units, res;
|
||||
RTN_STATUS rtnval;
|
||||
bool send;
|
||||
msta_field msta;
|
||||
|
||||
send = true; /* Default to send motor command. */
|
||||
rtnval = OK;
|
||||
buff[0] = '\0';
|
||||
|
||||
/* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */
|
||||
dval = (parms == NULL) ? 0.0 : *parms;
|
||||
|
||||
msta.All = mr->msta;
|
||||
|
||||
rtnval = (RTN_STATUS) motor_start_trans_com(mr, PIC848_cards);
|
||||
|
||||
motor_call = &(trans->motor_call);
|
||||
card = motor_call->card;
|
||||
brdptr = (*trans->tabptr->card_array)[card];
|
||||
if (brdptr == NULL)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
cntrl = (struct PIC848controller *) brdptr->DevicePrivate;
|
||||
res = cntrl->drive_resolution[motor_call->signal];
|
||||
cntrl_units = dval;
|
||||
maxdigits = 5;
|
||||
|
||||
if (PIC848_table[command] > motor_call->type)
|
||||
motor_call->type = PIC848_table[command];
|
||||
|
||||
if (trans->state != BUILD_STATE)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
|
||||
strcat(motor_call->message, mr->init);
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
case MOVE_REL:
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
case JOG:
|
||||
if (strlen(mr->prem) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->prem);
|
||||
strcat(motor_call->message, ";");
|
||||
}
|
||||
if (strlen(mr->post) != 0)
|
||||
motor_call->postmsgptr = (char *) &mr->post;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
sprintf(buff, "MOV #%.*f", maxdigits, (cntrl_units * res));
|
||||
break;
|
||||
|
||||
case MOVE_REL:
|
||||
sprintf(buff, "MVR #%+.*f", maxdigits, (cntrl_units * res));
|
||||
break;
|
||||
|
||||
case HOME_FOR:
|
||||
sprintf(buff, "REF #");
|
||||
break;
|
||||
case HOME_REV:
|
||||
sprintf(buff, "REF #");
|
||||
break;
|
||||
|
||||
case LOAD_POS:
|
||||
if (cntrl->reference[motor_call->signal] == true)
|
||||
{
|
||||
if (cntrl_units == 0.0)
|
||||
sprintf(buff, "DFH #");
|
||||
else
|
||||
rtnval = ERROR;
|
||||
}
|
||||
else
|
||||
sprintf(buff, "POS #%+.*f", maxdigits, (cntrl_units * res));
|
||||
|
||||
break;
|
||||
|
||||
case SET_VEL_BASE:
|
||||
send = false; /* DC motor; not base velocity. */
|
||||
break;
|
||||
|
||||
case SET_VELOCITY:
|
||||
sprintf(buff, "VEL # %.*f", maxdigits, (cntrl_units * res));
|
||||
break;
|
||||
|
||||
case ENABLE_TORQUE:
|
||||
if (msta.Bits.EA_POSITION == 0) /* Test for torque disabled. */
|
||||
{
|
||||
/* Clear the axis status. */
|
||||
sprintf(buff, "CLR #");
|
||||
rtnval = motor_end_trans_com(mr, drvtabptr);
|
||||
rtnval = (RTN_STATUS) motor_start_trans_com(mr, PIC848_cards);
|
||||
motor_call->type = PIC848_table[command];
|
||||
}
|
||||
sprintf(buff, "SVO #1");
|
||||
break;
|
||||
|
||||
case DISABL_TORQUE:
|
||||
sprintf(buff, "SVO #0");
|
||||
break;
|
||||
|
||||
case SET_ACCEL:
|
||||
/* The PIC848 does not support acceleration commands. */
|
||||
case GO:
|
||||
/* The PIC848 starts moving immediately on move commands, GO command
|
||||
* does nothing. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case PRIMITIVE:
|
||||
case GET_INFO:
|
||||
/* These commands are not actually done by sending a message, but
|
||||
rather they will indirectly cause the driver to read the status
|
||||
of all motors */
|
||||
break;
|
||||
|
||||
case STOP_AXIS:
|
||||
sprintf(buff, "HLT #");
|
||||
break;
|
||||
|
||||
case JOG_VELOCITY:
|
||||
case JOG:
|
||||
sprintf(buff, "VEL #%.*f", maxdigits, (cntrl_units * res));
|
||||
break;
|
||||
|
||||
case SET_PGAIN:
|
||||
cntrl_units *= 32767;
|
||||
sprintf(buff, "SPA #1 %.*f", maxdigits, cntrl_units);
|
||||
break;
|
||||
case SET_IGAIN:
|
||||
cntrl_units *= 32767;
|
||||
sprintf(buff, "SPA #2 %.*f", maxdigits, cntrl_units);
|
||||
break;
|
||||
case SET_DGAIN:
|
||||
cntrl_units *= 32767;
|
||||
sprintf(buff, "SPA #3 %.*f", maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case SET_HIGH_LIMIT:
|
||||
case SET_LOW_LIMIT:
|
||||
case SET_ENC_RATIO:
|
||||
trans->state = IDLE_STATE; /* No command sent to the controller. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
send = false;
|
||||
rtnval = ERROR;
|
||||
}
|
||||
|
||||
size = strlen(buff);
|
||||
if (send == false)
|
||||
return(rtnval);
|
||||
else if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE)
|
||||
errlogMessage("PIC848_build_trans(): buffer overflow.\n");
|
||||
else
|
||||
{
|
||||
strcat(motor_call->message, buff);
|
||||
rtnval = motor_end_trans_com(mr, drvtabptr);
|
||||
}
|
||||
return(rtnval);
|
||||
}
|
||||
@@ -1,310 +0,0 @@
|
||||
/*
|
||||
FILENAME... devPIC862.cc
|
||||
USAGE... Motor record device level support for Physik Instrumente (PI)
|
||||
GmbH & Co. C-862 motor controller.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Current Author: Mohan Ramanathan
|
||||
* Date: 09/04/2006
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 09/05/2006 mr copied from devPIC848.cc
|
||||
* .01 09/25/2006 rls - strip trailing cmnd separator (",") from message.
|
||||
* - simulate jogging with absolute moves to soft limit.
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "motordevCom.h"
|
||||
#include "drvPIC862.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern struct driver_table PIC862_access;
|
||||
|
||||
/* ----------------Create the dsets for devPIC862----------------- */
|
||||
static struct driver_table *drvtabptr;
|
||||
static long PIC862_init(int);
|
||||
static long PIC862_init_record(void *);
|
||||
static long PIC862_start_trans(struct motorRecord *);
|
||||
static RTN_STATUS PIC862_build_trans(motor_cmnd, double *, struct motorRecord *);
|
||||
static RTN_STATUS PIC862_end_trans(struct motorRecord *);
|
||||
|
||||
struct motor_dset devPIC862 =
|
||||
{
|
||||
{8, NULL, (DEVSUPFUN) PIC862_init, (DEVSUPFUN) PIC862_init_record, NULL},
|
||||
motor_update_values,
|
||||
PIC862_start_trans,
|
||||
PIC862_build_trans,
|
||||
PIC862_end_trans
|
||||
};
|
||||
|
||||
extern "C" {epicsExportAddress(dset,devPIC862);}
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
/* This table is used to define the command types */
|
||||
/* WARNING! this must match "motor_cmnd" in motor.h */
|
||||
|
||||
static msg_types PIC862_table[] = {
|
||||
MOTION, /* MOVE_ABS */
|
||||
MOTION, /* MOVE_REL */
|
||||
MOTION, /* HOME_FOR */
|
||||
MOTION, /* HOME_REV */
|
||||
IMMEDIATE, /* LOAD_POS */
|
||||
IMMEDIATE, /* SET_VEL_BASE */
|
||||
IMMEDIATE, /* SET_VELOCITY */
|
||||
IMMEDIATE, /* SET_ACCEL */
|
||||
IMMEDIATE, /* GO */
|
||||
IMMEDIATE, /* SET_ENC_RATIO */
|
||||
INFO, /* GET_INFO */
|
||||
MOVE_TERM, /* STOP_AXIS */
|
||||
VELOCITY, /* JOG */
|
||||
IMMEDIATE, /* SET_PGAIN */
|
||||
IMMEDIATE, /* SET_IGAIN */
|
||||
IMMEDIATE, /* SET_DGAIN */
|
||||
IMMEDIATE, /* ENABLE_TORQUE */
|
||||
IMMEDIATE, /* DISABL_TORQUE */
|
||||
IMMEDIATE, /* PRIMITIVE */
|
||||
IMMEDIATE, /* SET_HIGH_LIMIT */
|
||||
IMMEDIATE, /* SET_LOW_LIMIT */
|
||||
VELOCITY /* JOG_VELOCITY */
|
||||
};
|
||||
|
||||
|
||||
static struct board_stat **PIC862_cards;
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
|
||||
/* initialize device support for PIC862 servo motor */
|
||||
static long PIC862_init(int after)
|
||||
{
|
||||
long rtnval;
|
||||
|
||||
if (!after)
|
||||
{
|
||||
drvtabptr = &PIC862_access;
|
||||
(drvtabptr->init)();
|
||||
}
|
||||
|
||||
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &PIC862_cards);
|
||||
return(rtnval);
|
||||
}
|
||||
|
||||
|
||||
/* initialize a record instance */
|
||||
static long PIC862_init_record(void *arg)
|
||||
{
|
||||
struct motorRecord *mr = (struct motorRecord *) arg;
|
||||
return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, PIC862_cards));
|
||||
}
|
||||
|
||||
|
||||
/* start building a transaction */
|
||||
static long PIC862_start_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_start_trans_com(mr, PIC862_cards);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* end building a transaction */
|
||||
static RTN_STATUS PIC862_end_trans(struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
char *msgptr;
|
||||
int last;
|
||||
|
||||
/* Remove trailing cmnd separator (",") from message. */
|
||||
motor_call = &(trans->motor_call);
|
||||
msgptr = motor_call->message;
|
||||
last = strlen(msgptr) - 1;
|
||||
if (msgptr[last] == ',')
|
||||
msgptr[last] = (char) NULL;
|
||||
|
||||
motor_end_trans_com(mr, drvtabptr);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* add a part to the transaction */
|
||||
static RTN_STATUS PIC862_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
struct controller *brdptr;
|
||||
char buff[110];
|
||||
int card;
|
||||
unsigned int size;
|
||||
double dval;
|
||||
int cntrl_units;
|
||||
RTN_STATUS rtnval;
|
||||
bool send;
|
||||
|
||||
send = true; /* Default to send motor command. */
|
||||
rtnval = OK;
|
||||
buff[0] = '\0';
|
||||
|
||||
/* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */
|
||||
dval = (parms == NULL) ? 0.0 : *parms;
|
||||
|
||||
|
||||
motor_call = &(trans->motor_call);
|
||||
card = motor_call->card;
|
||||
brdptr = (*trans->tabptr->card_array)[card];
|
||||
if (brdptr == NULL)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
|
||||
cntrl_units = (int) dval;
|
||||
|
||||
if (PIC862_table[command] > motor_call->type)
|
||||
motor_call->type = PIC862_table[command];
|
||||
|
||||
if (trans->state != BUILD_STATE)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
|
||||
strcat(motor_call->message, mr->init);
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
case MOVE_REL:
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
case JOG:
|
||||
if (strlen(mr->prem) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->prem);
|
||||
strcat(motor_call->message, ",");
|
||||
}
|
||||
if (strlen(mr->post) != 0)
|
||||
motor_call->postmsgptr = (char *) &mr->post;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
sprintf(buff, "MA%d,", cntrl_units);
|
||||
break;
|
||||
|
||||
case MOVE_REL:
|
||||
sprintf(buff, "MR%d,", cntrl_units);
|
||||
break;
|
||||
|
||||
case HOME_FOR:
|
||||
sprintf(buff, "FE0");
|
||||
break;
|
||||
case HOME_REV:
|
||||
sprintf(buff, "FE1");
|
||||
break;
|
||||
|
||||
case LOAD_POS:
|
||||
if (cntrl_units == 0.0)
|
||||
sprintf(buff, "DH");
|
||||
else
|
||||
rtnval = ERROR;
|
||||
break;
|
||||
|
||||
case SET_VEL_BASE:
|
||||
send = false; /* DC motor; not base velocity. */
|
||||
break;
|
||||
|
||||
case JOG_VELOCITY:
|
||||
case SET_VELOCITY:
|
||||
sprintf(buff, "SV%d,", cntrl_units);
|
||||
break;
|
||||
|
||||
case SET_ACCEL:
|
||||
sprintf(buff, "SA%d,", cntrl_units);
|
||||
break;
|
||||
|
||||
case ENABLE_TORQUE:
|
||||
sprintf(buff, "MN");
|
||||
break;
|
||||
|
||||
case DISABL_TORQUE:
|
||||
sprintf(buff, "MF");
|
||||
break;
|
||||
|
||||
case GO:
|
||||
/* The PIC862 starts moving immediately on move commands, GO command
|
||||
* does nothing. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case PRIMITIVE:
|
||||
case GET_INFO:
|
||||
/* These commands are not actually done by sending a message, but
|
||||
rather they will indirectly cause the driver to read the status
|
||||
of all motors */
|
||||
break;
|
||||
|
||||
case STOP_AXIS:
|
||||
sprintf(buff, "ST");
|
||||
break;
|
||||
|
||||
case JOG:
|
||||
/*
|
||||
* C-862 does not have a jog command. Simulate with move absolute
|
||||
* to the appropriate software limit.
|
||||
*/
|
||||
sprintf(buff, "SV%d,", abs(cntrl_units));
|
||||
strcat(motor_call->message, buff);
|
||||
if (dval > 0.)
|
||||
sprintf(buff, "MA%d,", (int) (mr->dhlm / mr->mres));
|
||||
else
|
||||
sprintf(buff, "MA%d,", (int) (mr->dllm / mr->mres));
|
||||
break;
|
||||
|
||||
case SET_PGAIN:
|
||||
cntrl_units = (int) (32767 * dval);
|
||||
sprintf(buff, "DP%d", cntrl_units);
|
||||
break;
|
||||
case SET_IGAIN:
|
||||
cntrl_units = (int) (32767 * dval);
|
||||
sprintf(buff, "DI%d", cntrl_units);
|
||||
break;
|
||||
case SET_DGAIN:
|
||||
cntrl_units = (int) (32767 * dval);
|
||||
sprintf(buff, "DD%d", cntrl_units);
|
||||
break;
|
||||
|
||||
case SET_HIGH_LIMIT:
|
||||
case SET_LOW_LIMIT:
|
||||
case SET_ENC_RATIO:
|
||||
trans->state = IDLE_STATE; /* No command sent to the controller. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
send = false;
|
||||
rtnval = ERROR;
|
||||
}
|
||||
|
||||
size = strlen(buff);
|
||||
if (send == false)
|
||||
return(rtnval);
|
||||
else if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE)
|
||||
errlogMessage("PIC862_build_trans(): buffer overflow.\n");
|
||||
else
|
||||
{
|
||||
strcat(motor_call->message, buff);
|
||||
}
|
||||
return(rtnval);
|
||||
}
|
||||
@@ -1,312 +0,0 @@
|
||||
/*
|
||||
FILENAME... devPIE516.cc
|
||||
USAGE... Motor record device level support for Physik Instrumente (PI)
|
||||
GmbH & Co. E-516 motor controller.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 12/17/03
|
||||
* Current Author: Joe Sullivan
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 01/29/06 jps - copied from devPIE710.cc
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "motordevCom.h"
|
||||
#include "drvPIE516.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern struct driver_table PIE516_access;
|
||||
|
||||
/* ----------------Create the dsets for devPIE516----------------- */
|
||||
static struct driver_table *drvtabptr;
|
||||
static long PIE516_init(int);
|
||||
static long PIE516_init_record(void *);
|
||||
static long PIE516_start_trans(struct motorRecord *);
|
||||
static RTN_STATUS PIE516_build_trans(motor_cmnd, double *, struct motorRecord *);
|
||||
static RTN_STATUS PIE516_end_trans(struct motorRecord *);
|
||||
|
||||
struct motor_dset devPIE516 =
|
||||
{
|
||||
{8, NULL, (DEVSUPFUN) PIE516_init, (DEVSUPFUN) PIE516_init_record, NULL},
|
||||
motor_update_values,
|
||||
PIE516_start_trans,
|
||||
PIE516_build_trans,
|
||||
PIE516_end_trans
|
||||
};
|
||||
|
||||
extern "C" {epicsExportAddress(dset,devPIE516);}
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
/* This table is used to define the command types */
|
||||
/* WARNING! this must match "motor_cmnd" in motor.h */
|
||||
|
||||
static msg_types PIE516_table[] = {
|
||||
MOTION, /* MOVE_ABS */
|
||||
MOTION, /* MOVE_REL */
|
||||
MOTION, /* HOME_FOR */
|
||||
MOTION, /* HOME_REV */
|
||||
IMMEDIATE, /* LOAD_POS */
|
||||
IMMEDIATE, /* SET_VEL_BASE */
|
||||
IMMEDIATE, /* SET_VELOCITY */
|
||||
IMMEDIATE, /* SET_ACCEL */
|
||||
IMMEDIATE, /* GO */
|
||||
IMMEDIATE, /* SET_ENC_RATIO */
|
||||
INFO, /* GET_INFO */
|
||||
MOVE_TERM, /* STOP_AXIS */
|
||||
VELOCITY, /* JOG */
|
||||
IMMEDIATE, /* SET_PGAIN */
|
||||
IMMEDIATE, /* SET_IGAIN */
|
||||
IMMEDIATE, /* SET_DGAIN */
|
||||
IMMEDIATE, /* ENABLE_TORQUE */
|
||||
IMMEDIATE, /* DISABL_TORQUE */
|
||||
IMMEDIATE, /* PRIMITIVE */
|
||||
IMMEDIATE, /* SET_HIGH_LIMIT */
|
||||
IMMEDIATE, /* SET_LOW_LIMIT */
|
||||
VELOCITY /* JOG_VELOCITY */
|
||||
};
|
||||
|
||||
|
||||
static struct board_stat **PIE516_cards;
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
|
||||
/* initialize device support for PIE516 stepper motor */
|
||||
static long PIE516_init(int after)
|
||||
{
|
||||
long rtnval;
|
||||
|
||||
if (!after)
|
||||
{
|
||||
drvtabptr = &PIE516_access;
|
||||
(drvtabptr->init)();
|
||||
}
|
||||
|
||||
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &PIE516_cards);
|
||||
return(rtnval);
|
||||
}
|
||||
|
||||
|
||||
/* initialize a record instance */
|
||||
static long PIE516_init_record(void *arg)
|
||||
{
|
||||
struct motorRecord *mr = (struct motorRecord *) arg;
|
||||
/* Disable change of direction testing in record support */
|
||||
/* This is a closed-loop device */
|
||||
mr->ntm = menuYesNoNO;
|
||||
return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, PIE516_cards));
|
||||
}
|
||||
|
||||
|
||||
/* start building a transaction */
|
||||
static long PIE516_start_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_start_trans_com(mr, PIE516_cards);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* end building a transaction */
|
||||
static RTN_STATUS PIE516_end_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_end_trans_com(mr, drvtabptr);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* add a part to the transaction */
|
||||
static RTN_STATUS PIE516_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
struct controller *brdptr;
|
||||
struct PIE516controller *cntrl;
|
||||
char buff[110];
|
||||
int card, maxdigits;
|
||||
unsigned int size;
|
||||
double dval, cntrl_units, res;
|
||||
RTN_STATUS rtnval;
|
||||
bool send;
|
||||
|
||||
send = true; /* Default to send motor command. */
|
||||
rtnval = OK;
|
||||
buff[0] = '\0';
|
||||
|
||||
/* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */
|
||||
dval = (parms == NULL) ? 0.0 : *parms;
|
||||
|
||||
rtnval = (RTN_STATUS) motor_start_trans_com(mr, PIE516_cards);
|
||||
|
||||
motor_call = &(trans->motor_call);
|
||||
card = motor_call->card;
|
||||
brdptr = (*trans->tabptr->card_array)[card];
|
||||
if (brdptr == NULL)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
cntrl = (struct PIE516controller *) brdptr->DevicePrivate;
|
||||
res = cntrl->drive_resolution[motor_call->signal];
|
||||
cntrl_units = dval;
|
||||
maxdigits = 3;
|
||||
|
||||
if (PIE516_table[command] > motor_call->type)
|
||||
motor_call->type = PIE516_table[command];
|
||||
|
||||
if (trans->state != BUILD_STATE)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
|
||||
strcat(motor_call->message, mr->init);
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
case MOVE_REL:
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
case JOG:
|
||||
if (strlen(mr->prem) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->prem);
|
||||
strcat(motor_call->message, EOL_E516);
|
||||
}
|
||||
if (strlen(mr->post) != 0)
|
||||
motor_call->postmsgptr = (char *) &mr->post;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
sprintf(buff, "MOV #%.*f", maxdigits, (cntrl_units * res));
|
||||
strcat(buff, EOL_E516);
|
||||
break;
|
||||
|
||||
case MOVE_REL:
|
||||
sprintf(buff, "MVR #%.*f", maxdigits, (cntrl_units * res));
|
||||
strcat(buff, EOL_E516);
|
||||
break;
|
||||
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
rtnval = ERROR;
|
||||
break;
|
||||
|
||||
case LOAD_POS:
|
||||
rtnval = ERROR;
|
||||
break;
|
||||
|
||||
case SET_VEL_BASE:
|
||||
send = false; /* DC motor; not base velocity. */
|
||||
break;
|
||||
|
||||
case SET_VELOCITY:
|
||||
sprintf(buff, "VEL #%.*f", maxdigits, (cntrl_units * res));
|
||||
strcat(buff, EOL_E516);
|
||||
break;
|
||||
|
||||
case ENABLE_TORQUE:
|
||||
strcpy(buff, "SVO #1");
|
||||
strcat(buff, EOL_E516);
|
||||
break;
|
||||
|
||||
case DISABL_TORQUE:
|
||||
strcpy(buff, "SVO #0");
|
||||
strcat(buff, EOL_E516);
|
||||
break;
|
||||
|
||||
case SET_ACCEL:
|
||||
/* The PIE516 does not support acceleration commands. */
|
||||
case GO:
|
||||
/* The PIE516 starts moving immediately on move commands, GO command
|
||||
* does nothing. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case PRIMITIVE:
|
||||
case GET_INFO:
|
||||
/* These commands are not actually done by sending a message, but
|
||||
rather they will indirectly cause the driver to read the status
|
||||
of all motors */
|
||||
break;
|
||||
|
||||
case STOP_AXIS:
|
||||
/* No stop command available - use move relative 0 */
|
||||
sprintf(buff, "STP #");
|
||||
strcat(buff, EOL_E516);
|
||||
break;
|
||||
|
||||
case JOG_VELOCITY:
|
||||
case JOG:
|
||||
sprintf(buff, "VEL #%.*f", maxdigits, cntrl_units);
|
||||
strcat(buff, EOL_E516);
|
||||
break;
|
||||
|
||||
case SET_PGAIN:
|
||||
send = false;
|
||||
break;
|
||||
case SET_IGAIN:
|
||||
send = false;
|
||||
break;
|
||||
case SET_DGAIN:
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case SET_HIGH_LIMIT:
|
||||
case SET_LOW_LIMIT:
|
||||
case SET_ENC_RATIO:
|
||||
trans->state = IDLE_STATE; /* No command sent to the controller. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
send = false;
|
||||
rtnval = ERROR;
|
||||
}
|
||||
|
||||
size = strlen(buff);
|
||||
if (send == false)
|
||||
return(rtnval);
|
||||
else if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE)
|
||||
errlogMessage("PIE516_build_trans(): buffer overflow.\n");
|
||||
else
|
||||
{
|
||||
strcat(motor_call->message, buff);
|
||||
rtnval = motor_end_trans_com(mr, drvtabptr);
|
||||
}
|
||||
return(rtnval);
|
||||
}
|
||||
@@ -1,317 +0,0 @@
|
||||
/*
|
||||
FILENAME... devPIE517.cc
|
||||
USAGE... Motor record device level support for Physik Instrumente (PI)
|
||||
GmbH & Co. E-516 motor controller.
|
||||
|
||||
Version: $Revision: 1.2 $
|
||||
Modified By: $Author: sluiter $
|
||||
Last Modified: $Date: 2008-03-14 20:21:37 $
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 12/17/03
|
||||
* Current Author: Joe Sullivan
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 08/10/16 Bruno Luvizotto (brunoluvizotto@gmail.com) - copied from devPIE516.cc
|
||||
* .02 08/10/16 Bruno Luvizotto (brunoluvizotto@gmail.com) - edited the files for the E517 controller
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "motordevCom.h"
|
||||
#include "drvPIE517.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern struct driver_table PIE517_access;
|
||||
|
||||
/* ----------------Create the dsets for devPIE517----------------- */
|
||||
static struct driver_table *drvtabptr;
|
||||
static long PIE517_init(int);
|
||||
static long PIE517_init_record(void *);
|
||||
static long PIE517_start_trans(struct motorRecord *);
|
||||
static RTN_STATUS PIE517_build_trans(motor_cmnd, double *, struct motorRecord *);
|
||||
static RTN_STATUS PIE517_end_trans(struct motorRecord *);
|
||||
|
||||
struct motor_dset devPIE517 =
|
||||
{
|
||||
{8, NULL, (DEVSUPFUN) PIE517_init, (DEVSUPFUN) PIE517_init_record, NULL},
|
||||
motor_update_values,
|
||||
PIE517_start_trans,
|
||||
PIE517_build_trans,
|
||||
PIE517_end_trans
|
||||
};
|
||||
|
||||
extern "C" {epicsExportAddress(dset,devPIE517);}
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
/* This table is used to define the command types */
|
||||
/* WARNING! this must match "motor_cmnd" in motor.h */
|
||||
|
||||
static msg_types PIE517_table[] = {
|
||||
MOTION, /* MOVE_ABS */
|
||||
MOTION, /* MOVE_REL */
|
||||
MOTION, /* HOME_FOR */
|
||||
MOTION, /* HOME_REV */
|
||||
IMMEDIATE, /* LOAD_POS */
|
||||
IMMEDIATE, /* SET_VEL_BASE */
|
||||
IMMEDIATE, /* SET_VELOCITY */
|
||||
IMMEDIATE, /* SET_ACCEL */
|
||||
IMMEDIATE, /* GO */
|
||||
IMMEDIATE, /* SET_ENC_RATIO */
|
||||
INFO, /* GET_INFO */
|
||||
MOVE_TERM, /* STOP_AXIS */
|
||||
VELOCITY, /* JOG */
|
||||
IMMEDIATE, /* SET_PGAIN */
|
||||
IMMEDIATE, /* SET_IGAIN */
|
||||
IMMEDIATE, /* SET_DGAIN */
|
||||
IMMEDIATE, /* ENABLE_TORQUE */
|
||||
IMMEDIATE, /* DISABL_TORQUE */
|
||||
IMMEDIATE, /* PRIMITIVE */
|
||||
IMMEDIATE, /* SET_HIGH_LIMIT */
|
||||
IMMEDIATE, /* SET_LOW_LIMIT */
|
||||
VELOCITY /* JOG_VELOCITY */
|
||||
};
|
||||
|
||||
|
||||
static struct board_stat **PIE517_cards;
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
|
||||
/* initialize device support for PIE517 stepper motor */
|
||||
static long PIE517_init(int after)
|
||||
{
|
||||
long rtnval;
|
||||
|
||||
if (!after)
|
||||
{
|
||||
drvtabptr = &PIE517_access;
|
||||
(drvtabptr->init)();
|
||||
}
|
||||
|
||||
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &PIE517_cards);
|
||||
return(rtnval);
|
||||
}
|
||||
|
||||
|
||||
/* initialize a record instance */
|
||||
static long PIE517_init_record(void *arg)
|
||||
{
|
||||
struct motorRecord *mr = (struct motorRecord *) arg;
|
||||
/* Disable change of direction testing in record support */
|
||||
/* This is a closed-loop device */
|
||||
mr->ntm = menuYesNoNO;
|
||||
return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, PIE517_cards));
|
||||
}
|
||||
|
||||
|
||||
/* start building a transaction */
|
||||
static long PIE517_start_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_start_trans_com(mr, PIE517_cards);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* end building a transaction */
|
||||
static RTN_STATUS PIE517_end_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_end_trans_com(mr, drvtabptr);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* add a part to the transaction */
|
||||
static RTN_STATUS PIE517_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
struct controller *brdptr;
|
||||
struct PIE517controller *cntrl;
|
||||
char buff[110];
|
||||
int card, maxdigits;
|
||||
unsigned int size;
|
||||
double dval, cntrl_units, res;
|
||||
RTN_STATUS rtnval;
|
||||
bool send;
|
||||
|
||||
send = true; /* Default to send motor command. */
|
||||
rtnval = OK;
|
||||
buff[0] = '\0';
|
||||
|
||||
/* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */
|
||||
dval = (parms == NULL) ? 0.0 : *parms;
|
||||
|
||||
rtnval = (RTN_STATUS) motor_start_trans_com(mr, PIE517_cards);
|
||||
|
||||
motor_call = &(trans->motor_call);
|
||||
card = motor_call->card;
|
||||
brdptr = (*trans->tabptr->card_array)[card];
|
||||
if (brdptr == NULL)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
cntrl = (struct PIE517controller *) brdptr->DevicePrivate;
|
||||
res = cntrl->drive_resolution[motor_call->signal];
|
||||
cntrl_units = dval;
|
||||
maxdigits = 3;
|
||||
|
||||
if (PIE517_table[command] > motor_call->type)
|
||||
motor_call->type = PIE517_table[command];
|
||||
|
||||
if (trans->state != BUILD_STATE)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
|
||||
strcat(motor_call->message, mr->init);
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
case MOVE_REL:
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
case JOG:
|
||||
if (strlen(mr->prem) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->prem);
|
||||
strcat(motor_call->message, EOL_E517);
|
||||
}
|
||||
if (strlen(mr->post) != 0)
|
||||
motor_call->postmsgptr = (char *) &mr->post;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
sprintf(buff, "MOV # %.*f", maxdigits, (cntrl_units * res));
|
||||
strcat(buff, EOL_E517);
|
||||
break;
|
||||
|
||||
case MOVE_REL:
|
||||
sprintf(buff, "MVR # %.*f", maxdigits, (cntrl_units * res));
|
||||
strcat(buff, EOL_E517);
|
||||
break;
|
||||
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
rtnval = ERROR;
|
||||
break;
|
||||
|
||||
case LOAD_POS:
|
||||
rtnval = ERROR;
|
||||
break;
|
||||
|
||||
case SET_VEL_BASE:
|
||||
send = false; /* DC motor; not base velocity. */
|
||||
break;
|
||||
|
||||
case SET_VELOCITY:
|
||||
sprintf(buff, "VEL # %.*f", maxdigits, (cntrl_units * res));
|
||||
strcat(buff, EOL_E517);
|
||||
break;
|
||||
|
||||
case ENABLE_TORQUE:
|
||||
strcpy(buff, "SVO #1");
|
||||
strcat(buff, EOL_E517);
|
||||
break;
|
||||
|
||||
case DISABL_TORQUE:
|
||||
strcpy(buff, "SVO #0");
|
||||
strcat(buff, EOL_E517);
|
||||
break;
|
||||
|
||||
case SET_ACCEL:
|
||||
/* The PIE517 does not support acceleration commands. */
|
||||
case GO:
|
||||
/* The PIE517 starts moving immediately on move commands, GO command
|
||||
* does nothing. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case PRIMITIVE:
|
||||
case GET_INFO:
|
||||
/* These commands are not actually done by sending a message, but
|
||||
rather they will indirectly cause the driver to read the status
|
||||
of all motors */
|
||||
break;
|
||||
|
||||
case STOP_AXIS:
|
||||
/* No stop command available - use move relative 0 */
|
||||
sprintf(buff, "STP #");
|
||||
strcat(buff, EOL_E517);
|
||||
break;
|
||||
|
||||
case JOG_VELOCITY:
|
||||
case JOG:
|
||||
sprintf(buff, "VEL # %.*f", maxdigits, cntrl_units);
|
||||
strcat(buff, EOL_E517);
|
||||
break;
|
||||
|
||||
case SET_PGAIN:
|
||||
send = false;
|
||||
break;
|
||||
case SET_IGAIN:
|
||||
send = false;
|
||||
break;
|
||||
case SET_DGAIN:
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case SET_HIGH_LIMIT:
|
||||
case SET_LOW_LIMIT:
|
||||
case SET_ENC_RATIO:
|
||||
trans->state = IDLE_STATE; /* No command sent to the controller. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
send = false;
|
||||
rtnval = ERROR;
|
||||
}
|
||||
|
||||
size = strlen(buff);
|
||||
if (send == false)
|
||||
return(rtnval);
|
||||
else if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE)
|
||||
errlogMessage("PIE517_build_trans(): buffer overflow.\n");
|
||||
else
|
||||
{
|
||||
strcat(motor_call->message, buff);
|
||||
rtnval = motor_end_trans_com(mr, drvtabptr);
|
||||
}
|
||||
return(rtnval);
|
||||
}
|
||||
@@ -1,307 +0,0 @@
|
||||
/*
|
||||
FILENAME... devPIE710.cc
|
||||
USAGE... Motor record device level support for Physik Instrumente (PI)
|
||||
GmbH & Co. E-710 motor controller.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 12/17/03
|
||||
* Current Author: Joe Sullivan
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 09/13/06 jps - copied from devPIC848.cc
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "motordevCom.h"
|
||||
#include "drvPIE710.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern struct driver_table PIE710_access;
|
||||
|
||||
/* ----------------Create the dsets for devPIE710----------------- */
|
||||
static struct driver_table *drvtabptr;
|
||||
static long PIE710_init(int);
|
||||
static long PIE710_init_record(void *);
|
||||
static long PIE710_start_trans(struct motorRecord *);
|
||||
static RTN_STATUS PIE710_build_trans(motor_cmnd, double *, struct motorRecord *);
|
||||
static RTN_STATUS PIE710_end_trans(struct motorRecord *);
|
||||
|
||||
struct motor_dset devPIE710 =
|
||||
{
|
||||
{8, NULL, (DEVSUPFUN) PIE710_init, (DEVSUPFUN) PIE710_init_record, NULL},
|
||||
motor_update_values,
|
||||
PIE710_start_trans,
|
||||
PIE710_build_trans,
|
||||
PIE710_end_trans
|
||||
};
|
||||
|
||||
extern "C" {epicsExportAddress(dset,devPIE710);}
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
/* This table is used to define the command types */
|
||||
/* WARNING! this must match "motor_cmnd" in motor.h */
|
||||
|
||||
static msg_types PIE710_table[] = {
|
||||
MOTION, /* MOVE_ABS */
|
||||
MOTION, /* MOVE_REL */
|
||||
MOTION, /* HOME_FOR */
|
||||
MOTION, /* HOME_REV */
|
||||
IMMEDIATE, /* LOAD_POS */
|
||||
IMMEDIATE, /* SET_VEL_BASE */
|
||||
IMMEDIATE, /* SET_VELOCITY */
|
||||
IMMEDIATE, /* SET_ACCEL */
|
||||
IMMEDIATE, /* GO */
|
||||
IMMEDIATE, /* SET_ENC_RATIO */
|
||||
INFO, /* GET_INFO */
|
||||
MOVE_TERM, /* STOP_AXIS */
|
||||
VELOCITY, /* JOG */
|
||||
IMMEDIATE, /* SET_PGAIN */
|
||||
IMMEDIATE, /* SET_IGAIN */
|
||||
IMMEDIATE, /* SET_DGAIN */
|
||||
IMMEDIATE, /* ENABLE_TORQUE */
|
||||
IMMEDIATE, /* DISABL_TORQUE */
|
||||
IMMEDIATE, /* PRIMITIVE */
|
||||
IMMEDIATE, /* SET_HIGH_LIMIT */
|
||||
IMMEDIATE, /* SET_LOW_LIMIT */
|
||||
VELOCITY /* JOG_VELOCITY */
|
||||
};
|
||||
|
||||
|
||||
static struct board_stat **PIE710_cards;
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
|
||||
/* initialize device support for PIE710 stepper motor */
|
||||
static long PIE710_init(int after)
|
||||
{
|
||||
long rtnval;
|
||||
|
||||
if (!after)
|
||||
{
|
||||
drvtabptr = &PIE710_access;
|
||||
(drvtabptr->init)();
|
||||
}
|
||||
|
||||
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &PIE710_cards);
|
||||
return(rtnval);
|
||||
}
|
||||
|
||||
|
||||
/* initialize a record instance */
|
||||
static long PIE710_init_record(void *arg)
|
||||
{
|
||||
struct motorRecord *mr = (struct motorRecord *) arg;
|
||||
/* Disable change of direction testing in record support */
|
||||
/* This is a closed-loop device */
|
||||
mr->ntm = menuYesNoNO;
|
||||
return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, PIE710_cards));
|
||||
}
|
||||
|
||||
|
||||
/* start building a transaction */
|
||||
static long PIE710_start_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_start_trans_com(mr, PIE710_cards);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* end building a transaction */
|
||||
static RTN_STATUS PIE710_end_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_end_trans_com(mr, drvtabptr);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* add a part to the transaction */
|
||||
static RTN_STATUS PIE710_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
struct controller *brdptr;
|
||||
struct PIE710controller *cntrl;
|
||||
char buff[110];
|
||||
int card, maxdigits;
|
||||
unsigned int size;
|
||||
double dval, cntrl_units, res;
|
||||
RTN_STATUS rtnval;
|
||||
bool send;
|
||||
|
||||
send = true; /* Default to send motor command. */
|
||||
rtnval = OK;
|
||||
buff[0] = '\0';
|
||||
|
||||
/* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */
|
||||
dval = (parms == NULL) ? 0.0 : *parms;
|
||||
|
||||
rtnval = (RTN_STATUS) motor_start_trans_com(mr, PIE710_cards);
|
||||
|
||||
motor_call = &(trans->motor_call);
|
||||
card = motor_call->card;
|
||||
brdptr = (*trans->tabptr->card_array)[card];
|
||||
if (brdptr == NULL)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
cntrl = (struct PIE710controller *) brdptr->DevicePrivate;
|
||||
res = cntrl->drive_resolution[motor_call->signal];
|
||||
cntrl_units = dval;
|
||||
maxdigits = 5;
|
||||
|
||||
if (PIE710_table[command] > motor_call->type)
|
||||
motor_call->type = PIE710_table[command];
|
||||
|
||||
if (trans->state != BUILD_STATE)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
|
||||
strcat(motor_call->message, mr->init);
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
case MOVE_REL:
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
case JOG:
|
||||
if (strlen(mr->prem) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->prem);
|
||||
strcat(motor_call->message, ",");
|
||||
}
|
||||
if (strlen(mr->post) != 0)
|
||||
motor_call->postmsgptr = (char *) &mr->post;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
sprintf(buff, "#MA%.*f,", maxdigits, (cntrl_units * res));
|
||||
break;
|
||||
|
||||
case MOVE_REL:
|
||||
sprintf(buff, "#MR%+.*f,", maxdigits, (cntrl_units * res));
|
||||
break;
|
||||
|
||||
case HOME_FOR:
|
||||
sprintf(buff, "#GH,");
|
||||
break;
|
||||
case HOME_REV:
|
||||
sprintf(buff, "#GH,");
|
||||
break;
|
||||
|
||||
case LOAD_POS:
|
||||
rtnval = ERROR;
|
||||
break;
|
||||
|
||||
case SET_VEL_BASE:
|
||||
send = false; /* DC motor; not base velocity. */
|
||||
break;
|
||||
|
||||
case SET_VELOCITY:
|
||||
sprintf(buff, "#SV%.*f,", maxdigits, (cntrl_units * res));
|
||||
break;
|
||||
|
||||
case ENABLE_TORQUE:
|
||||
strcpy(buff, "#SL1,");
|
||||
break;
|
||||
|
||||
case DISABL_TORQUE:
|
||||
strcpy(buff, "#SL0,");
|
||||
break;
|
||||
|
||||
case SET_ACCEL:
|
||||
/* The PIE710 does not support acceleration commands. */
|
||||
case GO:
|
||||
/* The PIE710 starts moving immediately on move commands, GO command
|
||||
* does nothing. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case PRIMITIVE:
|
||||
case GET_INFO:
|
||||
/* These commands are not actually done by sending a message, but
|
||||
rather they will indirectly cause the driver to read the status
|
||||
of all motors */
|
||||
break;
|
||||
|
||||
case STOP_AXIS:
|
||||
/* No stop command available - use move relative 0 */
|
||||
sprintf(buff, "#MR0,");
|
||||
break;
|
||||
|
||||
case JOG_VELOCITY:
|
||||
case JOG:
|
||||
sprintf(buff, "#SV%.*f,", maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case SET_PGAIN:
|
||||
sprintf(buff, "#SP%.*f", maxdigits, cntrl_units);
|
||||
break;
|
||||
case SET_IGAIN:
|
||||
send = false;
|
||||
break;
|
||||
case SET_DGAIN:
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case SET_HIGH_LIMIT:
|
||||
case SET_LOW_LIMIT:
|
||||
case SET_ENC_RATIO:
|
||||
trans->state = IDLE_STATE; /* No command sent to the controller. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
send = false;
|
||||
rtnval = ERROR;
|
||||
}
|
||||
|
||||
size = strlen(buff);
|
||||
if (send == false)
|
||||
return(rtnval);
|
||||
else if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE)
|
||||
errlogMessage("PIE710_build_trans(): buffer overflow.\n");
|
||||
else
|
||||
{
|
||||
strcat(motor_call->message, buff);
|
||||
rtnval = motor_end_trans_com(mr, drvtabptr);
|
||||
}
|
||||
return(rtnval);
|
||||
}
|
||||
@@ -1,315 +0,0 @@
|
||||
/*
|
||||
FILENAME... devPIE816.cc
|
||||
USAGE... Motor record device level support for Physik Instrumente (PI)
|
||||
GmbH & Co. E-816 motor controller.
|
||||
|
||||
Version: 1.1
|
||||
Modified By: sullivan
|
||||
Last Modified: 2007/03/30 20:01:05
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 12/17/03
|
||||
* Current Author: Joe Sullivan
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 01/29/06 jps - copied from devPIE710.cc
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "motordevCom.h"
|
||||
#include "drvPIE816.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern struct driver_table PIE816_access;
|
||||
|
||||
/* ----------------Create the dsets for devPIE816----------------- */
|
||||
static struct driver_table *drvtabptr;
|
||||
static long PIE816_init(int);
|
||||
static long PIE816_init_record(void *);
|
||||
static long PIE816_start_trans(struct motorRecord *);
|
||||
static RTN_STATUS PIE816_build_trans(motor_cmnd, double *, struct motorRecord *);
|
||||
static RTN_STATUS PIE816_end_trans(struct motorRecord *);
|
||||
|
||||
struct motor_dset devPIE816 =
|
||||
{
|
||||
{8, NULL, (DEVSUPFUN) PIE816_init, (DEVSUPFUN) PIE816_init_record, NULL},
|
||||
motor_update_values,
|
||||
PIE816_start_trans,
|
||||
PIE816_build_trans,
|
||||
PIE816_end_trans
|
||||
};
|
||||
|
||||
extern "C" {epicsExportAddress(dset,devPIE816);}
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
/* This table is used to define the command types */
|
||||
/* WARNING! this must match "motor_cmnd" in motor.h */
|
||||
|
||||
static msg_types PIE816_table[] = {
|
||||
MOTION, /* MOVE_ABS */
|
||||
MOTION, /* MOVE_REL */
|
||||
MOTION, /* HOME_FOR */
|
||||
MOTION, /* HOME_REV */
|
||||
IMMEDIATE, /* LOAD_POS */
|
||||
IMMEDIATE, /* SET_VEL_BASE */
|
||||
IMMEDIATE, /* SET_VELOCITY */
|
||||
IMMEDIATE, /* SET_ACCEL */
|
||||
IMMEDIATE, /* GO */
|
||||
IMMEDIATE, /* SET_ENC_RATIO */
|
||||
INFO, /* GET_INFO */
|
||||
MOVE_TERM, /* STOP_AXIS */
|
||||
VELOCITY, /* JOG */
|
||||
IMMEDIATE, /* SET_PGAIN */
|
||||
IMMEDIATE, /* SET_IGAIN */
|
||||
IMMEDIATE, /* SET_DGAIN */
|
||||
IMMEDIATE, /* ENABLE_TORQUE */
|
||||
IMMEDIATE, /* DISABL_TORQUE */
|
||||
IMMEDIATE, /* PRIMITIVE */
|
||||
IMMEDIATE, /* SET_HIGH_LIMIT */
|
||||
IMMEDIATE, /* SET_LOW_LIMIT */
|
||||
VELOCITY /* JOG_VELOCITY */
|
||||
};
|
||||
|
||||
|
||||
static struct board_stat **PIE816_cards;
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
|
||||
/* initialize device support for PIE816 stepper motor */
|
||||
static long PIE816_init(int after)
|
||||
{
|
||||
long rtnval;
|
||||
|
||||
if (!after)
|
||||
{
|
||||
drvtabptr = &PIE816_access;
|
||||
(drvtabptr->init)();
|
||||
}
|
||||
|
||||
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &PIE816_cards);
|
||||
return(rtnval);
|
||||
}
|
||||
|
||||
|
||||
/* initialize a record instance */
|
||||
static long PIE816_init_record(void *arg)
|
||||
{
|
||||
struct motorRecord *mr = (struct motorRecord *) arg;
|
||||
/* Disable change of direction testing in record support */
|
||||
/* This is a closed-loop device */
|
||||
mr->ntm = menuYesNoNO;
|
||||
return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, PIE816_cards));
|
||||
}
|
||||
|
||||
|
||||
/* start building a transaction */
|
||||
static long PIE816_start_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_start_trans_com(mr, PIE816_cards);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* end building a transaction */
|
||||
static RTN_STATUS PIE816_end_trans(struct motorRecord *mr)
|
||||
{
|
||||
motor_end_trans_com(mr, drvtabptr);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* add a part to the transaction */
|
||||
static RTN_STATUS PIE816_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
struct controller *brdptr;
|
||||
struct PIE816controller *cntrl;
|
||||
char buff[110];
|
||||
int card, maxdigits;
|
||||
unsigned int size;
|
||||
double dval, cntrl_units, res;
|
||||
RTN_STATUS rtnval;
|
||||
bool send;
|
||||
|
||||
send = true; /* Default to send motor command. */
|
||||
rtnval = OK;
|
||||
buff[0] = '\0';
|
||||
|
||||
/* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */
|
||||
dval = (parms == NULL) ? 0.0 : *parms;
|
||||
|
||||
rtnval = (RTN_STATUS) motor_start_trans_com(mr, PIE816_cards);
|
||||
|
||||
motor_call = &(trans->motor_call);
|
||||
card = motor_call->card;
|
||||
brdptr = (*trans->tabptr->card_array)[card];
|
||||
if (brdptr == NULL)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
cntrl = (struct PIE816controller *) brdptr->DevicePrivate;
|
||||
res = cntrl->drive_resolution[motor_call->signal];
|
||||
cntrl_units = dval;
|
||||
maxdigits = 3;
|
||||
|
||||
if (PIE816_table[command] > motor_call->type)
|
||||
motor_call->type = PIE816_table[command];
|
||||
|
||||
if (trans->state != BUILD_STATE)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
|
||||
strcat(motor_call->message, mr->init);
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
case MOVE_REL:
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
case JOG:
|
||||
if (strlen(mr->prem) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->prem);
|
||||
strcat(motor_call->message, EOL_E816);
|
||||
}
|
||||
if (strlen(mr->post) != 0)
|
||||
motor_call->postmsgptr = (char *) &mr->post;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
sprintf(buff, "MOV #%.*f", maxdigits, (cntrl_units * res));
|
||||
strcat(buff, EOL_E816);
|
||||
break;
|
||||
|
||||
case MOVE_REL:
|
||||
sprintf(buff, "MVR #%.*f", maxdigits, (cntrl_units * res));
|
||||
strcat(buff, EOL_E816);
|
||||
break;
|
||||
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
rtnval = ERROR;
|
||||
break;
|
||||
|
||||
case LOAD_POS:
|
||||
rtnval = ERROR;
|
||||
break;
|
||||
|
||||
case SET_VEL_BASE:
|
||||
send = false; /* DC motor; not base velocity. */
|
||||
break;
|
||||
|
||||
case SET_VELOCITY:
|
||||
sprintf(buff, "VEL #%.*f", maxdigits, (cntrl_units * res));
|
||||
strcat(buff, EOL_E816);
|
||||
break;
|
||||
|
||||
case ENABLE_TORQUE:
|
||||
strcpy(buff, "SVO #1");
|
||||
strcat(buff, EOL_E816);
|
||||
break;
|
||||
|
||||
case DISABL_TORQUE:
|
||||
strcpy(buff, "SVO #0");
|
||||
strcat(buff, EOL_E816);
|
||||
break;
|
||||
|
||||
case SET_ACCEL:
|
||||
/* The PIE816 does not support acceleration commands. */
|
||||
case GO:
|
||||
/* The PIE816 starts moving immediately on move commands, GO command
|
||||
* does nothing. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case PRIMITIVE:
|
||||
case GET_INFO:
|
||||
/* These commands are not actually done by sending a message, but
|
||||
rather they will indirectly cause the driver to read the status
|
||||
of all motors */
|
||||
break;
|
||||
|
||||
case STOP_AXIS:
|
||||
/* No stop command available - use move relative 0 */
|
||||
sprintf(buff, "MVR #0");
|
||||
strcat(buff, EOL_E816);
|
||||
break;
|
||||
|
||||
case JOG_VELOCITY:
|
||||
case JOG:
|
||||
sprintf(buff, "VEL #%.*f", maxdigits, cntrl_units);
|
||||
strcat(buff, EOL_E816);
|
||||
break;
|
||||
|
||||
case SET_PGAIN:
|
||||
send = false;
|
||||
break;
|
||||
case SET_IGAIN:
|
||||
send = false;
|
||||
break;
|
||||
case SET_DGAIN:
|
||||
send = false;
|
||||
break;
|
||||
|
||||
case SET_HIGH_LIMIT:
|
||||
case SET_LOW_LIMIT:
|
||||
case SET_ENC_RATIO:
|
||||
trans->state = IDLE_STATE; /* No command sent to the controller. */
|
||||
send = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
send = false;
|
||||
rtnval = ERROR;
|
||||
}
|
||||
|
||||
size = strlen(buff);
|
||||
if (send == false)
|
||||
return(rtnval);
|
||||
else if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE)
|
||||
errlogMessage("PIE816_build_trans(): buffer overflow.\n");
|
||||
else
|
||||
{
|
||||
strcat(motor_call->message, buff);
|
||||
rtnval = motor_end_trans_com(mr, drvtabptr);
|
||||
}
|
||||
return(rtnval);
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
# Physik Instrumente (PI) GmbH & Co. C-844 driver support.
|
||||
device(motor,VME_IO,devPIC844,"PIC844")
|
||||
driver(drvPIC844)
|
||||
registrar(PImotorRegister)
|
||||
variable(drvPIC844debug)
|
||||
|
||||
# PI C630 support.
|
||||
device(motor,VME_IO,devPIC630,"PI C630")
|
||||
driver(drvPIC630)
|
||||
registrar(PIC630Register)
|
||||
variable(drvPIC630debug)
|
||||
|
||||
# Physik Instrumente (PI) GmbH & Co. C-848 driver support.
|
||||
device(motor,VME_IO,devPIC848,"PIC848")
|
||||
driver(drvPIC848)
|
||||
registrar(PIC848motorRegister)
|
||||
variable(drvPIC848debug)
|
||||
|
||||
# Physik Instrumente (PI) GmbH & Co. E-662 driver support.
|
||||
device(motor,VME_IO,devPIC662,"PIC662")
|
||||
driver(drvPIC662)
|
||||
registrar(PIC662motorRegister)
|
||||
variable(drvPIC662debug)
|
||||
|
||||
# Physik Instrumente (PI) GmbH & Co. C-862 driver support.
|
||||
device(motor,VME_IO,devPIC862,"PIC862")
|
||||
driver(drvPIC862)
|
||||
registrar(PIC862motorRegister)
|
||||
variable(drvPIC862debug)
|
||||
|
||||
# Physik Instrumente (PI) GmbH & Co. C-663 driver support.
|
||||
device(motor,VME_IO,devPIC663,"PIC663")
|
||||
driver(drvPIC663)
|
||||
registrar(PIC663motorRegister)
|
||||
variable(drvPIC663debug)
|
||||
|
||||
# Physik Instrumente (PI) GmbH & Co. E-710 driver support.
|
||||
device(motor,VME_IO,devPIE710,"PIE710")
|
||||
driver(drvPIE710)
|
||||
registrar(PIE710motorRegister)
|
||||
variable(drvPIE710debug)
|
||||
|
||||
# Physik Instrumente (PI) GmbH & Co. E-516 driver support.
|
||||
device(motor,VME_IO,devPIE516,"PIE516")
|
||||
driver(drvPIE516)
|
||||
registrar(PIE516motorRegister)
|
||||
variable(drvPIE516debug)
|
||||
|
||||
# Physik Instrumente (PI) GmbH & Co. E-517 driver support.
|
||||
device(motor,VME_IO,devPIE517,"PIE517")
|
||||
driver(drvPIE517)
|
||||
registrar(PIE517motorRegister)
|
||||
variable(drvPIE517debug)
|
||||
|
||||
# Physik Instrumente (PI) GmbH & Co. E-816 driver support.
|
||||
device(motor,VME_IO,devPIE816,"PIE816")
|
||||
driver(drvPIE816)
|
||||
registrar(PIE816motorRegister)
|
||||
variable(drvPIE816debug)
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvPI.h
|
||||
USAGE... This file contains driver "include" information that is specific to
|
||||
Physik Instrumente (PI) GmbH & Co. motor controller driver support.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 12/17/03
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
*
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 12/17/03 rls - copied from drvIM483.h
|
||||
* .02 07/12/04 rls - Converted from MPF to asyn.
|
||||
*/
|
||||
|
||||
#ifndef INCdrvPIh
|
||||
#define INCdrvPIh 1
|
||||
|
||||
#include "motor.h"
|
||||
#include "motordrvCom.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
|
||||
#define COMM_TIMEOUT 2 /* Timeout in seconds. */
|
||||
|
||||
/* PIC844 specific data is stored in this structure. */
|
||||
struct PIC844controller
|
||||
{
|
||||
asynUser *pasynUser; /* For RS-232 */
|
||||
int asyn_address; /* Use for GPIB or other address with asyn */
|
||||
char asyn_port[80]; /* asyn port name */
|
||||
CommStatus status; /* Controller communication status. */
|
||||
};
|
||||
|
||||
/* Motion Condition register */
|
||||
|
||||
typedef union
|
||||
{
|
||||
unsigned short All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
unsigned int axis4ML :1; /* Axis#4 Minus Limit Switch */
|
||||
unsigned int axis3ML :1; /* Axis#3 Minus Limit Switch */
|
||||
unsigned int axis2ML :1; /* Axis#2 Minus Limit Switch */
|
||||
unsigned int axis1ML :1; /* Axis#1 Minus Limit Switch */
|
||||
unsigned int axis4PL :1; /* Axis#4 Plus Limit Switch */
|
||||
unsigned int axis3PL :1; /* Axis#3 Plus Limit Switch */
|
||||
unsigned int axis2PL :1; /* Axis#2 Plus Limit Switch */
|
||||
unsigned int axis1PL :1; /* Axis#1 Plus Limit Switch */
|
||||
unsigned int axis4ME :1; /* Axis#4 Motion-Error */
|
||||
unsigned int axis3ME :1; /* Axis#3 Motion-Error */
|
||||
unsigned int axis2ME :1; /* Axis#2 Motion-Error */
|
||||
unsigned int axis1ME :1; /* Axis#1 Motion-Error */
|
||||
unsigned int axis4IM :1; /* Axis#4 in motion */
|
||||
unsigned int axis3IM :1; /* Axis#3 in motion */
|
||||
unsigned int axis2IM :1; /* Axis#2 in motion */
|
||||
unsigned int axis1IM :1; /* Axis#1 in motion */
|
||||
#else
|
||||
unsigned int axis1IM :1; /* Axis#1 in motion */
|
||||
unsigned int axis2IM :1; /* Axis#2 in motion */
|
||||
unsigned int axis3IM :1; /* Axis#3 in motion */
|
||||
unsigned int axis4IM :1; /* Axis#4 in motion */
|
||||
unsigned int axis1ME :1; /* Axis#1 Motion-Error */
|
||||
unsigned int axis2ME :1; /* Axis#2 Motion-Error */
|
||||
unsigned int axis3ME :1; /* Axis#3 Motion-Error */
|
||||
unsigned int axis4ME :1; /* Axis#4 Motion-Error */
|
||||
unsigned int axis1PL :1; /* Axis#1 Plus Limit Switch */
|
||||
unsigned int axis2PL :1; /* Axis#2 Plus Limit Switch */
|
||||
unsigned int axis3PL :1; /* Axis#3 Plus Limit Switch */
|
||||
unsigned int axis4PL :1; /* Axis#4 Plus Limit Switch */
|
||||
unsigned int axis1ML :1; /* Axis#1 Minus Limit Switch */
|
||||
unsigned int axis2ML :1; /* Axis#2 Minus Limit Switch */
|
||||
unsigned int axis3ML :1; /* Axis#3 Minus Limit Switch */
|
||||
unsigned int axis4ML :1; /* Axis#4 Minus Limit Switch */
|
||||
#endif
|
||||
} Bits;
|
||||
} C844_Cond_Reg;
|
||||
|
||||
/* Function prototypes. */
|
||||
extern RTN_STATUS PIC844Setup(int, int);
|
||||
extern RTN_STATUS PIC844Config(int, const char *, int);
|
||||
|
||||
#endif /* INCdrvPIh */
|
||||
|
||||
@@ -1,574 +0,0 @@
|
||||
/* File: drvPIC630.cc */
|
||||
|
||||
/* Device Driver Support routines for motor */
|
||||
/*
|
||||
* Original Author: Kurt Goetze
|
||||
* Date: 02-07-2005
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 02-07-2005 kag initialized from drvMicos.c
|
||||
*/
|
||||
|
||||
/* The PI C-630 controller is a 3-axis controller/driver. Up to 3 controllers
|
||||
* can be daisy-chained on one serial port (in this code this is considered a "card").
|
||||
* More than 1 "card" can be configured, but each will need its own serial port.
|
||||
* This means that up to 9 axes are controllable per serial port, addressed 1-9.
|
||||
* Each axis has a current setting, which is handled by PIC630_config and motor_init.
|
||||
*
|
||||
* The Controllers MUST BE ON at bootup or this code will error out.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <epicsThread.h>
|
||||
#include <drvSup.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include "motor.h"
|
||||
#include "drvPIC630.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define WAIT 1
|
||||
#define BUFF_SIZE 100 /* Maximum length of string to/from PIC630 */
|
||||
|
||||
/*----------------debugging-----------------*/
|
||||
volatile int drvPIC630debug = 0;
|
||||
extern "C" {epicsExportAddress(int, drvPIC630debug);}
|
||||
static inline void Debug(int level, const char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
if (level < drvPIC630debug) {
|
||||
va_list pVar;
|
||||
va_start(pVar, format);
|
||||
vprintf(format, pVar);
|
||||
va_end(pVar);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Debugging notes:
|
||||
* drvPIC630debug == 0 No debugging information is printed
|
||||
* drvPIC630debug >= 1 Warning information is printed
|
||||
* drvPIC630debug >= 2 Time-stamped messages are printed for each string
|
||||
* sent to and received from the controller
|
||||
* drvPIC630debug >= 3 Additional debugging messages
|
||||
*/
|
||||
|
||||
volatile int PIC630_num_cards = 0;
|
||||
volatile int PIC630_num_axis = 0;
|
||||
volatile int PIC630_current[9]; /* current settings per axis */
|
||||
|
||||
/* Local data required for every driver; see "motordrvComCode.h" */
|
||||
#include "motordrvComCode.h"
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
static int recv_mess(int, char *, int);
|
||||
static RTN_STATUS send_mess(int, char const *, char *);
|
||||
static void start_status(int);
|
||||
static int set_status(int, int);
|
||||
static long report(int);
|
||||
static long init();
|
||||
static int motor_init();
|
||||
static void query_done(int, int, struct mess_node *);
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
|
||||
struct driver_table PIC630_access =
|
||||
{
|
||||
motor_init,
|
||||
motor_send,
|
||||
motor_free,
|
||||
motor_card_info,
|
||||
motor_axis_info,
|
||||
&mess_queue,
|
||||
&queue_lock,
|
||||
&free_list,
|
||||
&freelist_lock,
|
||||
&motor_sem,
|
||||
&motor_state,
|
||||
&total_cards,
|
||||
&any_motor_in_motion,
|
||||
send_mess,
|
||||
recv_mess,
|
||||
set_status,
|
||||
query_done,
|
||||
start_status,
|
||||
&initialized,
|
||||
NULL
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
long number;
|
||||
long (*report) (int);
|
||||
long (*init) (void);
|
||||
} drvPIC630 = {2, report, init};
|
||||
|
||||
extern "C" {epicsExportAddress(drvet, drvPIC630);}
|
||||
|
||||
static struct thread_args targs = {SCAN_RATE, &PIC630_access};
|
||||
|
||||
/*********************************************************
|
||||
* Print out driver status report
|
||||
*********************************************************/
|
||||
static long report(int level)
|
||||
{
|
||||
int card;
|
||||
|
||||
if (PIC630_num_cards <=0)
|
||||
printf(" No PIC630 controllers configured.\n");
|
||||
else
|
||||
{
|
||||
for (card = 0; card < PIC630_num_cards; card++)
|
||||
{
|
||||
struct controller *brdptr = motor_state[card];
|
||||
if (brdptr == NULL)
|
||||
printf(" PIC630 controller %d connection failed.\n", card);
|
||||
else
|
||||
{
|
||||
struct PIC630Controller *cntrl;
|
||||
cntrl = (struct PIC630Controller *) brdptr->DevicePrivate;
|
||||
printf(" PIC630 controller #%d, port=%s, id: %s \n", card, cntrl->asyn_port, brdptr->ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
static long init()
|
||||
{
|
||||
/*
|
||||
* We cannot call motor_init() here, because that function can do GPIB I/O,
|
||||
* and hence requires that the drvGPIB have already been initialized.
|
||||
* That cannot be guaranteed, so we need to call motor_init from device
|
||||
* support
|
||||
*/
|
||||
/* Check for setup */
|
||||
if (PIC630_num_cards <= 0)
|
||||
{
|
||||
Debug(1, "init(): PIC630 driver disabled. PIC630Setup() missing from startup script.\n");
|
||||
}
|
||||
return ((long) 0);
|
||||
}
|
||||
|
||||
static void query_done(int card, int axis, struct mess_node *nodeptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static void start_status(int card)
|
||||
{
|
||||
/* The PIC630 cannot query status or positions of all axes with a
|
||||
* single command. This needs to be done on an axis-by-axis basis,
|
||||
* so this function does nothing
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
* Query position and status for an axis
|
||||
* set_status()
|
||||
************************************************************/
|
||||
|
||||
static int set_status(int card, int signal)
|
||||
{
|
||||
struct PIC630Controller *cntrl;
|
||||
struct mess_node *nodeptr;
|
||||
register struct mess_info *motor_info;
|
||||
char command[BUFF_SIZE];
|
||||
char response[BUFF_SIZE];
|
||||
char cStatus;
|
||||
int rtn_state;
|
||||
long motorData;
|
||||
char buff[BUFF_SIZE];
|
||||
bool plusdir, ls_active = false;
|
||||
msta_field status;
|
||||
|
||||
cntrl = (struct PIC630Controller *) motor_state[card]->DevicePrivate;
|
||||
motor_info = &(motor_state[card]->motor_info[signal]);
|
||||
nodeptr = motor_info->motor_motion;
|
||||
status.All = motor_info->status.All;
|
||||
|
||||
signal++;
|
||||
/* Request the status of this motor */
|
||||
sprintf(command, "%dTS", signal);
|
||||
send_mess(card, command, 0);
|
||||
recv_mess(card, response, WAIT);
|
||||
|
||||
/* The response string is of the form "nTS:N" where N is an int (0-255)
|
||||
bit0 (0x01) = moving
|
||||
bit1 (0x02) = reference signal flag
|
||||
bit2 (0x04) = pos. limit (0 = limit tripped)
|
||||
bit3 (0x08) = neg. limit (0 = limit tripped)
|
||||
bit4 (0x10) = command error
|
||||
bit5 (0x20) = profile error
|
||||
bit6 (0x40) = not used
|
||||
bit7 (0x80) = Estop (0 = Estop) */
|
||||
|
||||
cStatus = (char) atoi(&response[4]);
|
||||
|
||||
/* check to see if motor is moving */
|
||||
status.Bits.RA_DONE = (cStatus & 0x01) ? 0 : 1;
|
||||
|
||||
/* Request the position of this motor, find out which direction we're going */
|
||||
/* The response string is of the form "1TP:1000" */
|
||||
|
||||
sprintf(command, "%dTP", signal);
|
||||
send_mess(card, command, 0);
|
||||
recv_mess(card, response, WAIT);
|
||||
|
||||
motorData = atoi(&response[4]);
|
||||
|
||||
if (motorData == motor_info->position)
|
||||
{
|
||||
if (nodeptr != 0) /* Increment counter only if motor is moving. */
|
||||
motor_info->no_motion_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
status.Bits.RA_DIRECTION = (motorData >= motor_info->position) ? 1 : 0;
|
||||
motor_info->position = motorData;
|
||||
motor_info->no_motion_count = 0;
|
||||
}
|
||||
|
||||
plusdir = (status.Bits.RA_DIRECTION) ? true : false;
|
||||
|
||||
/* check limits, set indicators */
|
||||
if (!(cStatus & 0x04)) /* if +lim */
|
||||
{
|
||||
status.Bits.RA_PLUS_LS = 1;
|
||||
if (plusdir == true)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_PLUS_LS = 0;
|
||||
|
||||
if (!(cStatus & 0x08)) /* if -lim */
|
||||
{
|
||||
status.Bits.RA_MINUS_LS = 1;
|
||||
if (plusdir == false)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_MINUS_LS = 0;
|
||||
|
||||
/* encoder status */
|
||||
status.Bits.EA_SLIP = 0;
|
||||
status.Bits.EA_SLIP_STALL = 0;
|
||||
status.Bits.EA_HOME = 0;
|
||||
|
||||
/* Parse motor velocity? */
|
||||
/* NEEDS WORK */
|
||||
|
||||
motor_info->velocity = 0;
|
||||
|
||||
if (!status.Bits.RA_DIRECTION)
|
||||
motor_info->velocity *= -1;
|
||||
|
||||
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
|
||||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
|
||||
|
||||
/* Test for post-move string. */
|
||||
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 &&
|
||||
nodeptr->postmsgptr != 0)
|
||||
{
|
||||
strcpy(buff, nodeptr->postmsgptr);
|
||||
send_mess(card, buff, NULL);
|
||||
/* The PIC630 will send back a response for a 'set' command */
|
||||
recv_mess(card, buff, WAIT);
|
||||
nodeptr->postmsgptr = NULL;
|
||||
}
|
||||
|
||||
motor_info->status.All = status.All;
|
||||
return (rtn_state);
|
||||
}
|
||||
|
||||
/*****************************************************/
|
||||
/* send a message to the PIC630 board */
|
||||
/* send_mess() */
|
||||
/*****************************************************/
|
||||
static RTN_STATUS send_mess(int card, const char *com, char *name)
|
||||
{
|
||||
char buff[BUFF_SIZE];
|
||||
char inp_buff[BUFF_SIZE];
|
||||
int status = 0;
|
||||
size_t nwrite;
|
||||
struct PIC630Controller *cntrl;
|
||||
|
||||
/* Check that card exists */
|
||||
if (!motor_state[card])
|
||||
{
|
||||
errlogPrintf("send_mess - invalid card #%d\n", card);
|
||||
return (ERROR);
|
||||
}
|
||||
|
||||
/* If the string is NULL just return */
|
||||
if (strlen(com) == 0) return(OK);
|
||||
cntrl = (struct PIC630Controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
strcpy(buff, com);
|
||||
Debug(2, "send_mess: sending message to card %d, message=%s\n", card, buff);
|
||||
pasynOctetSyncIO->write(cntrl->pasynUser, buff, strlen(buff), COMM_TIMEOUT, &nwrite);
|
||||
|
||||
/* This thing always echos everything sent to it. Read this response. */
|
||||
status = recv_mess(card, inp_buff, WAIT);
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Read a response string from the PIC630 board */
|
||||
/* recv_mess() */
|
||||
/*****************************************************/
|
||||
static int recv_mess(int card, char *com, int flag)
|
||||
{
|
||||
double timeout;
|
||||
size_t nread = 0;
|
||||
int eomReason;
|
||||
int flush;
|
||||
struct PIC630Controller *cntrl;
|
||||
asynStatus status;
|
||||
|
||||
/* Check that card exists */
|
||||
if (!motor_state[card])
|
||||
{
|
||||
errlogPrintf("recv_mess - invalid card #%d\n", card);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
cntrl = (struct PIC630Controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
Debug(3, "recv_mess entry: card %d, flag=%d\n", card, flag);
|
||||
if (flag == FLUSH)
|
||||
{
|
||||
flush = 1;
|
||||
timeout = 0.;
|
||||
}
|
||||
else
|
||||
{
|
||||
flush = 0;
|
||||
timeout = COMM_TIMEOUT;
|
||||
}
|
||||
if (flush) status = pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, MAX_MSG_SIZE,
|
||||
timeout, &nread, &eomReason);
|
||||
|
||||
if (nread < 1) com[0] = '\0';
|
||||
|
||||
if (nread > 0) {
|
||||
Debug(2, "recv_mess: card %d, message = \"%s\"\n", card, com);
|
||||
}
|
||||
if (nread == 0) {
|
||||
if (flag != FLUSH) {
|
||||
Debug(1, "recv_mess: card %d ERROR: no response\n", card);
|
||||
} else {
|
||||
Debug(3, "recv_mess: card %d flush returned no characters\n", card);
|
||||
}
|
||||
}
|
||||
return (nread);
|
||||
}
|
||||
|
||||
/*****************************************************/
|
||||
/* Setup system configuration */
|
||||
/* PIC630Setup() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIC630Setup(int num_cards, /* maximum number of "controllers" in system */
|
||||
int num_channels, /* max number of drivers */
|
||||
int scan_rate) /* polling rate - 1/60 sec units */
|
||||
{
|
||||
int itera;
|
||||
|
||||
if (num_cards < 1 || num_cards > PIC630_NUM_CARDS)
|
||||
PIC630_num_cards = PIC630_NUM_CARDS;
|
||||
else
|
||||
PIC630_num_cards = num_cards;
|
||||
|
||||
if (num_channels < 1 || num_channels > PIC630_NUM_AXIS)
|
||||
PIC630_num_axis = PIC630_NUM_AXIS;
|
||||
else
|
||||
PIC630_num_axis = num_channels;
|
||||
|
||||
/* Set motor polling task rate */
|
||||
if (scan_rate >= 1 && scan_rate <= 60)
|
||||
targs.motor_scan_rate = scan_rate;
|
||||
else
|
||||
targs.motor_scan_rate = SCAN_RATE;
|
||||
|
||||
/*
|
||||
* Allocate space for motor_state structures. Note this must be done
|
||||
* before PIC630Config 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 since this is just
|
||||
* an array of pointers.
|
||||
*/
|
||||
motor_state = (struct controller **) malloc(PIC630_num_cards *
|
||||
sizeof(struct controller *));
|
||||
|
||||
for (itera = 0; itera < PIC630_num_cards; itera++)
|
||||
motor_state[itera] = (struct controller *) NULL;
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*****************************************************/
|
||||
/* Configure a controller */
|
||||
/* PIC630Config() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIC630Config(int card, /* "controller" being configured */
|
||||
const char *name, /* port name for asyn */
|
||||
int cur0, int cur1, int cur2, int cur3, int cur4, /* see below */
|
||||
int cur5, int cur6, int cur7, int cur8)
|
||||
{
|
||||
struct PIC630Controller *cntrl;
|
||||
|
||||
if (card < 0 || card >= PIC630_num_cards)
|
||||
return (ERROR);
|
||||
|
||||
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
||||
motor_state[card]->DevicePrivate = malloc(sizeof(struct PIC630Controller));
|
||||
cntrl = (struct PIC630Controller *) motor_state[card]->DevicePrivate;
|
||||
strcpy(cntrl->asyn_port, name);
|
||||
|
||||
/* This is a current setting for each axis that will be sent during motor_init.
|
||||
Valid settings are: 0=OFF, 1=100mA, 2=200mA, ... 8=800mA. */
|
||||
PIC630_current[0] = cur0;
|
||||
PIC630_current[1] = cur1;
|
||||
PIC630_current[2] = cur2;
|
||||
PIC630_current[3] = cur3;
|
||||
PIC630_current[4] = cur4;
|
||||
PIC630_current[5] = cur5;
|
||||
PIC630_current[6] = cur6;
|
||||
PIC630_current[7] = cur7;
|
||||
PIC630_current[8] = cur8;
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*****************************************************/
|
||||
/* initialize all software and hardware */
|
||||
/* This is called from the initialization routine in */
|
||||
/* device support. */
|
||||
/* motor_init() */
|
||||
/*****************************************************/
|
||||
static int motor_init()
|
||||
{
|
||||
struct controller *brdptr;
|
||||
struct PIC630Controller *cntrl;
|
||||
int card_index, motor_index;
|
||||
char cmd[BUFF_SIZE];
|
||||
char buff[BUFF_SIZE];
|
||||
int total_axis = 0;
|
||||
int status = 0;
|
||||
int i;
|
||||
asynStatus success_rtn;
|
||||
static const char output_terminator[] = "\n";
|
||||
static const char input_terminator[] = "\n";
|
||||
|
||||
initialized = true; /* Indicate that driver is initialized. */
|
||||
|
||||
/* Check for setup */
|
||||
if (PIC630_num_cards <= 0)
|
||||
{
|
||||
Debug(1, "motor_init: *PIC630 driver disabled*\n");
|
||||
Debug(1, "PIC630Setup() is missing from startup script.\n");
|
||||
return (ERROR);
|
||||
}
|
||||
for (card_index = 0; card_index < PIC630_num_cards; card_index++)
|
||||
{
|
||||
if (!motor_state[card_index])
|
||||
continue;
|
||||
brdptr = motor_state[card_index];
|
||||
brdptr->ident[0] = (char) NULL; /* No controller identification message. */
|
||||
/* device echos? then set to true. else false */
|
||||
brdptr->cmnd_response = false;
|
||||
total_cards = card_index + 1;
|
||||
cntrl = (struct PIC630Controller *) brdptr->DevicePrivate;
|
||||
|
||||
/* Initialize communications channel */
|
||||
|
||||
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));
|
||||
|
||||
/* Each "controller chain" can have max 9 axes. */
|
||||
total_axis = PIC630_num_axis;
|
||||
brdptr->total_axis = total_axis;
|
||||
|
||||
/* flush any junk at input port - should not be any data available */
|
||||
pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
|
||||
/* Send a message to each PIC630 motor. See if controller responds */
|
||||
for (motor_index = 0; motor_index < total_axis; motor_index++)
|
||||
{
|
||||
do
|
||||
{
|
||||
sprintf(cmd, "%dTS", (motor_index + 1));
|
||||
send_mess(card_index, cmd, 0);
|
||||
status = recv_mess(card_index, buff, WAIT);
|
||||
retry++;
|
||||
/* Return value is length of response string */
|
||||
} while(status == 0 && retry < 3);
|
||||
if (status == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (success_rtn == asynSuccess && status > 0)
|
||||
{
|
||||
brdptr->localaddr = (char *) NULL;
|
||||
brdptr->motor_in_motion = 0;
|
||||
/* how did this get here? brdptr->cmnd_response = true; */
|
||||
|
||||
start_status(card_index);
|
||||
for (motor_index = 0; motor_index < total_axis; motor_index++)
|
||||
{
|
||||
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
|
||||
brdptr->motor_info[motor_index].motor_motion = NULL;
|
||||
/* Wish I could turn off echo, can't :( */
|
||||
/* Set motor current */
|
||||
sprintf(buff,"%dDC%d", (motor_index + 1),PIC630_current[motor_index]);
|
||||
for (i=0; i<=8; i++)
|
||||
Debug(1, "PIC630_current[%d] = %d\n",i,PIC630_current[i]);
|
||||
send_mess(card_index, buff, 0);
|
||||
|
||||
/* Stop motor */
|
||||
sprintf(buff,"%dAB", (motor_index + 1));
|
||||
send_mess(card_index, buff, 0);
|
||||
strcpy(brdptr->ident, "PIC630");
|
||||
|
||||
motor_info->status.All = 0;
|
||||
motor_info->no_motion_count = 0;
|
||||
motor_info->encoder_position = 0;
|
||||
motor_info->position = 0;
|
||||
set_status(card_index, motor_index); /* Read status of each motor */
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
motor_state[card_index] = (struct controller *) NULL;
|
||||
}
|
||||
any_motor_in_motion = 0;
|
||||
|
||||
mess_queue.head = (struct mess_node *) NULL;
|
||||
mess_queue.tail = (struct mess_node *) NULL;
|
||||
|
||||
free_list.head = (struct mess_node *) NULL;
|
||||
free_list.tail = (struct mess_node *) NULL;
|
||||
|
||||
Debug(3, "motor_init: spawning motor task\n");
|
||||
|
||||
epicsThreadCreate((char *) "PIC630_motor", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/* File: drvPIC630.h */
|
||||
|
||||
|
||||
/* Device Driver Support definitions for motor */
|
||||
/*
|
||||
* Original Author: Kurt Goetze
|
||||
* Current Author: Kurt Goetze
|
||||
* Date: 02/07/2005
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 02/07/2005 kag initialized from drvMicos.h
|
||||
* .01 03/30/2005 kag port to 3.14 / asyn
|
||||
*/
|
||||
|
||||
#ifndef INCdrvPIC630h
|
||||
#define INCdrvPIC630h 1
|
||||
|
||||
#include "motordrvCom.h"
|
||||
#include "asynDriver.h"
|
||||
|
||||
/* PIC630 default profile. */
|
||||
|
||||
#define PIC630_NUM_CARDS 8 /* Maximum number of controller chains */
|
||||
#define PIC630_NUM_AXIS 9 /* Maximum number of axes per chain */
|
||||
|
||||
#define COMM_TIMEOUT 2 /* Timeout in seconds. */
|
||||
|
||||
struct PIC630Controller
|
||||
{
|
||||
asynUser *pasynUser; /* asynUser structure */
|
||||
char asyn_port[80]; /* asyn port name */
|
||||
};
|
||||
|
||||
#endif /* INCdrvPIC630h */
|
||||
@@ -1,597 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvPIC662.cc
|
||||
USAGE... Motor record driver level support for Physik Instrumente (PI)
|
||||
GmbH & Co. C-844 motor controller.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Joe Sullivan
|
||||
* Date: 03/08/06
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 03/08/06 jps - copied from drvPIC884.cc
|
||||
*/
|
||||
|
||||
/*
|
||||
DESIGN LIMITATIONS...
|
||||
1 - Like all controllers, the PIC662 must be powered-on when EPICS is first
|
||||
booted up.
|
||||
2 - The PIC662 cannot be power cycled while EPICS is up and running. The
|
||||
consequences are permanent communication lose with the PIC662 until
|
||||
EPICS is rebooted.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <epicsThread.h>
|
||||
#include <drvSup.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include "motor.h"
|
||||
#include "drvPIC662.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define GET_IDENT "*IDN?"
|
||||
#define GET_STATUS "*ESR?" // Status Register
|
||||
#define GET_POS "POS?" // Status Register
|
||||
|
||||
#define PIC662_NUM_CARDS 8
|
||||
#define MAX_AXES 1
|
||||
#define BUFF_SIZE 100 /* Maximum length of string to/from PIC662 */
|
||||
|
||||
/*----------------debugging-----------------*/
|
||||
volatile int drvPIC662debug = 0;
|
||||
extern "C" {epicsExportAddress(int, drvPIC662debug);}
|
||||
static inline void Debug(int level, const char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
if (level < drvPIC662debug) {
|
||||
va_list pVar;
|
||||
va_start(pVar, format);
|
||||
vprintf(format, pVar);
|
||||
va_end(pVar);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- Local data. --- */
|
||||
int PIC662_num_cards = 0;
|
||||
static char *PIC662_axis[4] = {"1", "2", "3", "4"};
|
||||
|
||||
/* Local data required for every driver; see "motordrvComCode.h" */
|
||||
#include "motordrvComCode.h"
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
static int recv_mess(int, char *, int);
|
||||
static RTN_STATUS send_mess(int, char const *, char *);
|
||||
static int set_status(int, int);
|
||||
static long report(int);
|
||||
static long init();
|
||||
static int motor_init();
|
||||
static void query_done(int, int, struct mess_node *);
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
|
||||
struct driver_table PIC662_access =
|
||||
{
|
||||
motor_init,
|
||||
motor_send,
|
||||
motor_free,
|
||||
motor_card_info,
|
||||
motor_axis_info,
|
||||
&mess_queue,
|
||||
&queue_lock,
|
||||
&free_list,
|
||||
&freelist_lock,
|
||||
&motor_sem,
|
||||
&motor_state,
|
||||
&total_cards,
|
||||
&any_motor_in_motion,
|
||||
send_mess,
|
||||
recv_mess,
|
||||
set_status,
|
||||
query_done,
|
||||
NULL,
|
||||
&initialized,
|
||||
PIC662_axis
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
long number;
|
||||
long (*report) (int);
|
||||
long (*init) (void);
|
||||
} drvPIC662 = {2, report, init};
|
||||
|
||||
extern "C" {epicsExportAddress(drvet, drvPIC662);}
|
||||
|
||||
static struct thread_args targs = {SCAN_RATE, &PIC662_access, 0.0};
|
||||
|
||||
/*********************************************************
|
||||
* Print out driver status report
|
||||
*********************************************************/
|
||||
static long report(int level)
|
||||
{
|
||||
int card;
|
||||
|
||||
if (PIC662_num_cards <=0)
|
||||
printf(" No PIC662 controllers configured.\n");
|
||||
else
|
||||
{
|
||||
for (card = 0; card < PIC662_num_cards; card++)
|
||||
{
|
||||
struct controller *brdptr = motor_state[card];
|
||||
|
||||
if (brdptr == NULL)
|
||||
printf(" PIC662 controller %d connection failed.\n", card);
|
||||
else
|
||||
{
|
||||
struct PIC662controller *cntrl;
|
||||
|
||||
cntrl = (struct PIC662controller *) brdptr->DevicePrivate;
|
||||
printf(" PIC662 controller #%d, port=%s, id: %s \n", card,
|
||||
cntrl->asyn_port, brdptr->ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
static long init()
|
||||
{
|
||||
/*
|
||||
* We cannot call motor_init() here, because that function can do GPIB I/O,
|
||||
* and hence requires that the drvGPIB have already been initialized.
|
||||
* That cannot be guaranteed, so we need to call motor_init from device
|
||||
* support
|
||||
*/
|
||||
/* Check for setup */
|
||||
if (PIC662_num_cards <= 0)
|
||||
{
|
||||
Debug(1, "init(): PIC662 driver disabled. PIC662Setup() missing from startup script.\n");
|
||||
}
|
||||
return((long) 0);
|
||||
}
|
||||
|
||||
|
||||
static void query_done(int card, int axis, struct mess_node *nodeptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* FUNCTION NAME: set_status *
|
||||
* *
|
||||
* LOGIC: *
|
||||
* Initialize. *
|
||||
* Send "Moving Status" query. *
|
||||
* Read response. *
|
||||
* IF normal response to query. *
|
||||
* Set communication status to NORMAL. *
|
||||
* ELSE *
|
||||
* IF communication status is NORMAL. *
|
||||
* Set communication status to RETRY. *
|
||||
* NORMAL EXIT. *
|
||||
* ELSE *
|
||||
* Set communication status error. *
|
||||
* ERROR EXIT. *
|
||||
* ENDIF *
|
||||
* ENDIF *
|
||||
* *
|
||||
* IF "Moving Status" indicates any motion (i.e. status != 0). *
|
||||
* Clear "Done Moving" status bit. *
|
||||
* ELSE *
|
||||
* Set "Done Moving" status bit. *
|
||||
* ENDIF *
|
||||
* *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
static int set_status(int card, int signal)
|
||||
{
|
||||
struct PIC662controller *cntrl;
|
||||
struct mess_node *nodeptr;
|
||||
register struct mess_info *motor_info;
|
||||
/* Message parsing variables */
|
||||
char buff[BUFF_SIZE];
|
||||
E662_ESR_REG mstat;
|
||||
int rtn_state;
|
||||
int comm_status;
|
||||
long motorData;
|
||||
bool plusdir, ls_active = false, plusLS, minusLS;
|
||||
bool eventflgs;
|
||||
msta_field status;
|
||||
|
||||
cntrl = (struct PIC662controller *) motor_state[card]->DevicePrivate;
|
||||
motor_info = &(motor_state[card]->motor_info[signal]);
|
||||
nodeptr = motor_info->motor_motion;
|
||||
status.All = motor_info->status.All;
|
||||
|
||||
send_mess(card, GET_STATUS, (char*) NULL);
|
||||
comm_status = recv_mess(card, buff, 1);
|
||||
if (comm_status == 0)
|
||||
{
|
||||
if (cntrl->status == NORMAL)
|
||||
{
|
||||
cntrl->status = RETRY;
|
||||
rtn_state = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cntrl->status = COMM_ERR;
|
||||
status.Bits.CNTRL_COMM_ERR = 1;
|
||||
status.Bits.RA_PROBLEM = 1;
|
||||
rtn_state = 1;
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cntrl->status = NORMAL;
|
||||
status.Bits.CNTRL_COMM_ERR = 0;
|
||||
status.Bits.EA_POSITION = 0;
|
||||
|
||||
mstat.All = atoi(&buff[0]);
|
||||
|
||||
eventflgs = (mstat.Bits.OpComplete ||
|
||||
mstat.Bits.DevError ||
|
||||
mstat.Bits.ExeError) ? true : false;
|
||||
|
||||
status.Bits.RA_DONE = (eventflgs || cntrl->stop_status)? 1 : 0;
|
||||
|
||||
cntrl->stop_status = false;
|
||||
|
||||
/*
|
||||
* Parse motor position
|
||||
* Position string format: 1TP5.012,2TP1.123,3TP-100.567,...
|
||||
* Skip to substring for this motor, convert to double
|
||||
*/
|
||||
|
||||
send_mess(card, GET_POS, (char*) NULL);
|
||||
recv_mess(card, buff, 1);
|
||||
|
||||
motorData = NINT (atof(buff) / cntrl->drive_resolution);
|
||||
|
||||
if (motorData == motor_info->position)
|
||||
{
|
||||
if (nodeptr != 0) /* Increment counter only if motor is moving. */
|
||||
if (motor_info->no_motion_count++ > 1)
|
||||
status.Bits.RA_DONE = 1; // No done indicator - stop when at position
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
status.Bits.RA_DIRECTION = (motorData >= motor_info->position) ? 1 : 0;
|
||||
motor_info->position = motorData;
|
||||
motor_info->no_motion_count = 0;
|
||||
}
|
||||
|
||||
// motor_info->encoder_position = (epicsInt32) motorData;
|
||||
status.Bits.RA_PROBLEM = 0;
|
||||
|
||||
plusdir = (status.Bits.RA_DIRECTION) ? true : false;
|
||||
|
||||
// No hardware limit switch feedback
|
||||
plusLS = false;
|
||||
minusLS = false;
|
||||
|
||||
/* Set limit switch error indicators. */
|
||||
if (plusLS == true)
|
||||
{
|
||||
status.Bits.RA_PLUS_LS = 1;
|
||||
if (plusdir == true)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_PLUS_LS = 0;
|
||||
|
||||
if (minusLS == true)
|
||||
{
|
||||
status.Bits.RA_MINUS_LS = 1;
|
||||
if (plusdir == false)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_MINUS_LS = 0;
|
||||
|
||||
/* encoder status */
|
||||
status.Bits.EA_SLIP = 0;
|
||||
status.Bits.EA_SLIP_STALL = 0;
|
||||
status.Bits.EA_HOME = 0;
|
||||
|
||||
|
||||
/* Parse motor velocity? */
|
||||
/* NEEDS WORK */
|
||||
|
||||
motor_info->velocity = 0;
|
||||
|
||||
if (!status.Bits.RA_DIRECTION)
|
||||
motor_info->velocity *= -1;
|
||||
|
||||
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
|
||||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
|
||||
|
||||
/* Test for post-move string. */
|
||||
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 &&
|
||||
nodeptr->postmsgptr != 0)
|
||||
{
|
||||
strcpy(buff, nodeptr->postmsgptr);
|
||||
send_mess(card, buff, (char*) NULL);
|
||||
nodeptr->postmsgptr = NULL;
|
||||
}
|
||||
|
||||
exit:
|
||||
motor_info->status.All = status.All;
|
||||
return(rtn_state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* send a message to the PIC662 board */
|
||||
/* send_mess() */
|
||||
/*****************************************************/
|
||||
static RTN_STATUS send_mess(int card, char const *com, char *name)
|
||||
{
|
||||
char local_buff[MAX_MSG_SIZE];
|
||||
struct PIC662controller *cntrl;
|
||||
int comsize, namesize;
|
||||
size_t nwrite;
|
||||
|
||||
comsize = (com == NULL) ? 0 : strlen(com);
|
||||
namesize = (name == NULL) ? 0 : strlen(name);
|
||||
|
||||
if ((comsize + namesize) > MAX_MSG_SIZE)
|
||||
{
|
||||
errlogMessage("drvPIC662.cc:send_mess(); message size violation.\n");
|
||||
return(ERROR);
|
||||
}
|
||||
else if (comsize == 0) /* Normal exit on empty input message. */
|
||||
return(OK);
|
||||
|
||||
if (!motor_state[card])
|
||||
{
|
||||
errlogPrintf("drvPIC662.cc:send_mess() - invalid card #%d\n", card);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
local_buff[0] = (char) NULL; /* Terminate local buffer. */
|
||||
|
||||
/* Make a local copy of the string. */
|
||||
strcat(local_buff, com);
|
||||
|
||||
Debug(2, "send_mess(): message = %s\n", local_buff);
|
||||
|
||||
cntrl = (struct PIC662controller *) motor_state[card]->DevicePrivate;
|
||||
pasynOctetSyncIO->write(cntrl->pasynUser, local_buff, strlen(local_buff),
|
||||
COMM_TIMEOUT, &nwrite);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* receive a message from the PIC662 board */
|
||||
/* recv_mess() */
|
||||
/*****************************************************/
|
||||
static int recv_mess(int card, char *com, int flag)
|
||||
{
|
||||
struct PIC662controller *cntrl;
|
||||
size_t nread = 0;
|
||||
asynStatus status = asynError;
|
||||
int eomReason;
|
||||
|
||||
/* Check that card exists */
|
||||
if (!motor_state[card])
|
||||
return(ERROR);
|
||||
|
||||
cntrl = (struct PIC662controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
if (flag == FLUSH)
|
||||
pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
else
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
|
||||
COMM_TIMEOUT, &nread, &eomReason);
|
||||
|
||||
if ((status != asynSuccess) || (nread <= 0))
|
||||
{
|
||||
com[0] = '\0';
|
||||
nread = 0;
|
||||
}
|
||||
|
||||
Debug(2, "recv_mess(): message = \"%s\"\n", com);
|
||||
return(nread);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Setup system configuration */
|
||||
/* PIC662Setup() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIC662Setup(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 > PIC662_NUM_CARDS)
|
||||
PIC662_num_cards = PIC662_NUM_CARDS;
|
||||
else
|
||||
PIC662_num_cards = num_cards;
|
||||
|
||||
/* Set motor polling task rate */
|
||||
if (scan_rate >= 1 && scan_rate <= 60)
|
||||
targs.motor_scan_rate = scan_rate;
|
||||
else
|
||||
targs.motor_scan_rate = SCAN_RATE;
|
||||
|
||||
/*
|
||||
* Allocate space for motor_state structures. Note this must be done
|
||||
* before PIC662Config 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(PIC662_num_cards *
|
||||
sizeof(struct controller *));
|
||||
|
||||
for (itera = 0; itera < PIC662_num_cards; itera++)
|
||||
motor_state[itera] = (struct controller *) NULL;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Configure a controller */
|
||||
/* PIC662Config() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIC662Config(int card, /* card being configured */
|
||||
const char *name) /* asyn port name */
|
||||
{
|
||||
struct PIC662controller *cntrl;
|
||||
|
||||
if (card < 0 || card >= PIC662_num_cards)
|
||||
return (ERROR);
|
||||
|
||||
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
||||
motor_state[card]->DevicePrivate = malloc(sizeof(struct PIC662controller));
|
||||
cntrl = (struct PIC662controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
strcpy(cntrl->asyn_port, name);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* initialize all software and hardware */
|
||||
/* This is called from the initialization routine in */
|
||||
/* device support. */
|
||||
/* motor_init() */
|
||||
/*****************************************************/
|
||||
static int motor_init()
|
||||
{
|
||||
struct controller *brdptr;
|
||||
struct PIC662controller *cntrl;
|
||||
int card_index;
|
||||
char buff[BUFF_SIZE];
|
||||
int status;
|
||||
asynStatus success_rtn;
|
||||
static const char output_terminator[] = "\n";
|
||||
static const char input_terminator[] = "\n";
|
||||
|
||||
initialized = true; /* Indicate that driver is initialized. */
|
||||
|
||||
/* Check for setup */
|
||||
if (PIC662_num_cards <= 0)
|
||||
return(ERROR);
|
||||
|
||||
for (card_index = 0; card_index < PIC662_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 PIC662controller *) brdptr->DevicePrivate;
|
||||
|
||||
/* Initialize communications channel */
|
||||
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port, 0,
|
||||
&cntrl->pasynUser, NULL);
|
||||
status = 0;
|
||||
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));
|
||||
|
||||
/* 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++;
|
||||
} while (status == 0 && retry < 3);
|
||||
}
|
||||
|
||||
if (success_rtn == asynSuccess && status > 0)
|
||||
{
|
||||
strcpy(brdptr->ident, &buff[0]);
|
||||
brdptr->localaddr = (char *) NULL;
|
||||
brdptr->motor_in_motion = 0;
|
||||
brdptr->total_axis = 1; /* Single axis controller */
|
||||
|
||||
/* Fixed resolution */
|
||||
cntrl->res_decpts = 3;
|
||||
cntrl->drive_resolution = 1.0/pow(10.0,cntrl->res_decpts);
|
||||
|
||||
|
||||
/* Set Controller to REMOTE mode */
|
||||
send_mess(card_index, REMOTE_MODE, (char*) NULL);
|
||||
|
||||
{
|
||||
struct mess_info *motor_info = &brdptr->motor_info[0];
|
||||
|
||||
motor_info->status.All = 0;
|
||||
motor_info->no_motion_count = 0;
|
||||
motor_info->encoder_position = 0;
|
||||
motor_info->position = 0;
|
||||
brdptr->motor_info[0].motor_motion = NULL;
|
||||
/* PIC662 has DC motor support only */
|
||||
motor_info->encoder_present = NO;
|
||||
motor_info->status.Bits.EA_PRESENT = 0;
|
||||
motor_info->pid_present = NO;
|
||||
motor_info->status.Bits.GAIN_SUPPORT = 0;
|
||||
|
||||
set_status(card_index, 0); /* Read status of each motor */
|
||||
}
|
||||
}
|
||||
else
|
||||
motor_state[card_index] = (struct controller *) NULL;
|
||||
}
|
||||
|
||||
any_motor_in_motion = 0;
|
||||
|
||||
mess_queue.head = (struct mess_node *) NULL;
|
||||
mess_queue.tail = (struct mess_node *) NULL;
|
||||
|
||||
free_list.head = (struct mess_node *) NULL;
|
||||
free_list.tail = (struct mess_node *) NULL;
|
||||
|
||||
epicsThreadCreate((char *) "PIC662_motor", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvPIC662.h
|
||||
USAGE... This file contains driver "include" information that is specific to
|
||||
Physik Instrumente (PI) GmbH & Co. motor controller driver support.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Joe Sullivan
|
||||
* Date: 12/17/03
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
*
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 03/08/06 jps - copied from drvPI.h
|
||||
*/
|
||||
|
||||
#ifndef INCdrvPIh
|
||||
#define INCdrvPIh 1
|
||||
|
||||
#include "motor.h"
|
||||
#include "motordrvCom.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
|
||||
#define COMM_TIMEOUT 2 /* Timeout in seconds. */
|
||||
|
||||
// E662 Command: switch to remote control mode
|
||||
// This is done before each positioning move because
|
||||
// the controller defaults to 'Local' mode on power up.
|
||||
// Status can be read while in 'Local' mode.
|
||||
#define REMOTE_MODE "DEV:CONT REM"
|
||||
|
||||
/* PIC662 specific data is stored in this structure. */
|
||||
struct PIC662controller
|
||||
{
|
||||
asynUser *pasynUser; /* For RS-232 */
|
||||
int asyn_address; /* Use for GPIB or other address with asyn */
|
||||
char asyn_port[80]; /* asyn port name */
|
||||
CommStatus status; /* Controller communication status. */
|
||||
|
||||
bool stop_status; /* Signal to set_status() - stop polling */
|
||||
double drive_resolution;
|
||||
int res_decpts; /* Max decimal points */
|
||||
};
|
||||
|
||||
/* Standard Event Status register */
|
||||
|
||||
|
||||
typedef union
|
||||
{
|
||||
epicsUInt8 All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
unsigned int PowerOn :1; // (Bit 7) Power On
|
||||
unsigned int UserReq :1; // User Request
|
||||
unsigned int CmdError :1; // Command Error
|
||||
unsigned int ExeError :1; // Execution Error
|
||||
unsigned int DevError :1; // Device Dependant Error
|
||||
unsigned int QueryError :1; // Query Error
|
||||
unsigned int ReqControl :1; // Request Control
|
||||
unsigned int OpComplete :1; // (Bit 0) Operation Complete
|
||||
#else
|
||||
unsigned int OpComplete :1; // (Bit 0) Operation Complete
|
||||
unsigned int ReqControl :1; // Request Control
|
||||
unsigned int QueryError :1; // Query Error
|
||||
unsigned int DevError :1; // Device Dependant Error
|
||||
unsigned int ExeError :1; // Execution Error
|
||||
unsigned int CmdError :1; // Command Error
|
||||
unsigned int UserReq :1; // User Request
|
||||
unsigned int PowerOn :1; // (Bit 7) Power On
|
||||
#endif
|
||||
} Bits;
|
||||
} E662_ESR_REG;
|
||||
|
||||
|
||||
/* Function prototypes. */
|
||||
extern RTN_STATUS PIC662Setup(int, int);
|
||||
extern RTN_STATUS PIC662Config(int, const char *);
|
||||
|
||||
#endif /* INCdrvPIh */
|
||||
|
||||
@@ -1,574 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvPIC663.cc
|
||||
USAGE... Motor record driver level support for Physik Instrumente (PI)
|
||||
GmbH & Co. C-663 motor controller.
|
||||
*/
|
||||
/*
|
||||
* Copied from devPIC862.cc by Jonathan Thompson, Jan 2011
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* Jan 2011 - All references to 862 changed to 663
|
||||
* - Handling of status request results changed to cope with 663 output
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
DESIGN LIMITATIONS...
|
||||
1 - Like all controllers, the PIC663 must be powered-on when EPICS is first
|
||||
booted up.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <epicsThread.h>
|
||||
#include <drvSup.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "drvPIC663.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define GET_IDENT 0x01
|
||||
|
||||
#define PIC663_NUM_CARDS 8
|
||||
#define MAX_AXES 1
|
||||
#define BUFF_SIZE 100 /* Maximum length of string to/from PIC663 */
|
||||
|
||||
/*----------------debugging-----------------*/
|
||||
volatile int drvPIC663debug = 0;
|
||||
extern "C" {epicsExportAddress(int, drvPIC663debug);}
|
||||
static inline void Debug(int level, const char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
if (level < drvPIC663debug) {
|
||||
va_list pVar;
|
||||
va_start(pVar, format);
|
||||
vprintf(format, pVar);
|
||||
va_end(pVar);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- Local data. --- */
|
||||
int PIC663_num_cards = 0;
|
||||
|
||||
/* Local data required for every driver; see "motordrvComCode.h" */
|
||||
#include "motordrvComCode.h"
|
||||
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
static int recv_mess(int, char *, int);
|
||||
static RTN_STATUS send_mess(int, char const *, char *);
|
||||
static int set_status(int, int);
|
||||
static long report(int);
|
||||
static long init();
|
||||
static int motor_init();
|
||||
static void query_done(int, int, struct mess_node *);
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
|
||||
struct driver_table PIC663_access =
|
||||
{
|
||||
motor_init,
|
||||
motor_send,
|
||||
motor_free,
|
||||
motor_card_info,
|
||||
motor_axis_info,
|
||||
&mess_queue,
|
||||
&queue_lock,
|
||||
&free_list,
|
||||
&freelist_lock,
|
||||
&motor_sem,
|
||||
&motor_state,
|
||||
&total_cards,
|
||||
&any_motor_in_motion,
|
||||
send_mess,
|
||||
recv_mess,
|
||||
set_status,
|
||||
query_done,
|
||||
NULL,
|
||||
&initialized,
|
||||
NULL
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
long number;
|
||||
long (*report) (int);
|
||||
long (*init) (void);
|
||||
} drvPIC663 = {2, report, init};
|
||||
|
||||
extern "C" {epicsExportAddress(drvet, drvPIC663);}
|
||||
|
||||
static struct thread_args targs = {SCAN_RATE, &PIC663_access, 0.017};
|
||||
|
||||
/*********************************************************
|
||||
* Print out driver status report
|
||||
*********************************************************/
|
||||
static long report(int level)
|
||||
{
|
||||
int card;
|
||||
|
||||
if (PIC663_num_cards <=0)
|
||||
printf(" No PIC663 controllers configured.\n");
|
||||
else
|
||||
{
|
||||
for (card = 0; card < PIC663_num_cards; card++)
|
||||
{
|
||||
struct controller *brdptr = motor_state[card];
|
||||
|
||||
if (brdptr == NULL)
|
||||
printf(" PIC663 controller %d connection failed.\n", card);
|
||||
else
|
||||
{
|
||||
struct PIC663controller *cntrl;
|
||||
|
||||
cntrl = (struct PIC663controller *) brdptr->DevicePrivate;
|
||||
printf(" PIC663 controller #%d, port=%s, id: %s \n", card,
|
||||
cntrl->asyn_port, brdptr->ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
static long init()
|
||||
{
|
||||
/*
|
||||
* We cannot call motor_init() here, because that function can do GPIB I/O,
|
||||
* and hence requires that the drvGPIB have already been initialized.
|
||||
* That cannot be guaranteed, so we need to call motor_init from device
|
||||
* support
|
||||
*/
|
||||
/* Check for setup */
|
||||
if (PIC663_num_cards <= 0)
|
||||
{
|
||||
Debug(1, "init(): PIC663 driver disabled. PIC663Setup() missing from startup script.\n");
|
||||
}
|
||||
return((long) 0);
|
||||
}
|
||||
|
||||
|
||||
static void query_done(int card, int axis, struct mess_node *nodeptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* FUNCTION NAME: set_status *
|
||||
* *
|
||||
* LOGIC: *
|
||||
* Initialize. *
|
||||
* Send "Moving Status" query. *
|
||||
* Read response. *
|
||||
* IF normal response to query. *
|
||||
* Set communication status to NORMAL. *
|
||||
* ELSE *
|
||||
* IF communication status is NORMAL. *
|
||||
* Set communication status to RETRY. *
|
||||
* NORMAL EXIT. *
|
||||
* ELSE *
|
||||
* Set communication status error. *
|
||||
* ERROR EXIT. *
|
||||
* ENDIF *
|
||||
* ENDIF *
|
||||
* *
|
||||
* IF "Moving Status" indicates any motion (i.e. status != 0). *
|
||||
* Clear "Done Moving" status bit. *
|
||||
* ELSE *
|
||||
* Set "Done Moving" status bit. *
|
||||
* ENDIF *
|
||||
* *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
static int set_status(int card, int signal)
|
||||
{
|
||||
struct PIC663controller *cntrl;
|
||||
struct mess_node *nodeptr;
|
||||
struct mess_info *motor_info;
|
||||
struct motorRecord *mr;
|
||||
/* Message parsing variables */
|
||||
char buff[BUFF_SIZE];
|
||||
C663_Status_Reg1 mstat1;
|
||||
C663_Status_Reg2 mstat2;
|
||||
C663_Status_Reg3 mstat3;
|
||||
epicsUInt16 dev_sts1, dev_sts2, dev_sts3;
|
||||
|
||||
int rtn_state, convert_cnt, charcnt;
|
||||
epicsInt32 motorData;
|
||||
bool plusdir, ls_active = false, plusLS, minusLS, LSactiveH;
|
||||
msta_field status;
|
||||
|
||||
cntrl = (struct PIC663controller *) motor_state[card]->DevicePrivate;
|
||||
motor_info = &(motor_state[card]->motor_info[signal]);
|
||||
nodeptr = motor_info->motor_motion;
|
||||
if (nodeptr != NULL)
|
||||
mr = (struct motorRecord *) nodeptr->mrecord;
|
||||
else
|
||||
mr = NULL;
|
||||
status.All = motor_info->status.All;
|
||||
|
||||
if (cntrl->status != NORMAL)
|
||||
charcnt = recv_mess(card, buff, FLUSH);
|
||||
|
||||
send_mess(card, "TS", (char*) NULL); /* Tell Status */
|
||||
charcnt = recv_mess(card, buff, 1);
|
||||
if (charcnt > 9)
|
||||
convert_cnt = sscanf(buff, "S:%2hx %2hx %2hx\n",
|
||||
&dev_sts1,&dev_sts2,&dev_sts3);
|
||||
|
||||
if (charcnt > 9 && convert_cnt == 3)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
mstat1.All = dev_sts1;
|
||||
mstat2.All = dev_sts2;
|
||||
mstat3.All = dev_sts3;
|
||||
|
||||
status.Bits.RA_DONE = (mstat1.Bits.on_target) ? 1 : 0;
|
||||
status.Bits.EA_POSITION = (mstat1.Bits.drv_cur_act) ? 0 : 1;
|
||||
status.Bits.RA_DIRECTION = 0;
|
||||
|
||||
plusLS = mstat2.Bits.hi_limit ? 0 : 1;
|
||||
minusLS = mstat2.Bits.lo_limit ? 0 : 1;
|
||||
|
||||
/* Parse motor position */
|
||||
send_mess(card, "TP", (char*) NULL); /* Tell Position */
|
||||
recv_mess(card, buff, 1);
|
||||
motorData = NINT(atof(&buff[2]));
|
||||
|
||||
if (motorData == motor_info->position)
|
||||
{
|
||||
if (nodeptr != 0) /* Increment counter only if motor is moving. */
|
||||
motor_info->no_motion_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
motor_info->position = motor_info->encoder_position = motorData;
|
||||
motor_info->no_motion_count = 0;
|
||||
}
|
||||
|
||||
plusdir = (status.Bits.RA_DIRECTION) ? true : false;
|
||||
|
||||
/* Set limit switch error indicators. */
|
||||
if (plusLS == true)
|
||||
{
|
||||
status.Bits.RA_PLUS_LS = 1;
|
||||
if (plusdir == true)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_PLUS_LS = 0;
|
||||
|
||||
if (minusLS == true)
|
||||
{
|
||||
status.Bits.RA_MINUS_LS = 1;
|
||||
if (plusdir == false)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_MINUS_LS = 0;
|
||||
|
||||
/* encoder status */
|
||||
status.Bits.EA_SLIP = 0;
|
||||
status.Bits.EA_SLIP_STALL = 0;
|
||||
status.Bits.EA_HOME = 0;
|
||||
|
||||
status.Bits.RA_PROBLEM = 0;
|
||||
|
||||
if (!status.Bits.RA_DIRECTION)
|
||||
motor_info->velocity *= -1;
|
||||
|
||||
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
|
||||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
|
||||
|
||||
/* Test for post-move string. */
|
||||
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 &&
|
||||
nodeptr->postmsgptr != 0)
|
||||
{
|
||||
strcpy(buff, nodeptr->postmsgptr);
|
||||
send_mess(card, buff, (char*) NULL);
|
||||
nodeptr->postmsgptr = NULL;
|
||||
}
|
||||
|
||||
exit:
|
||||
motor_info->status.All = status.All;
|
||||
return(rtn_state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* send a message to the PIC663 board */
|
||||
/* send_mess() */
|
||||
/*****************************************************/
|
||||
static RTN_STATUS send_mess(int card, char const *com, char *name)
|
||||
{
|
||||
char local_buff[MAX_MSG_SIZE];
|
||||
struct PIC663controller *cntrl;
|
||||
int comsize, namesize;
|
||||
size_t nwrite;
|
||||
|
||||
comsize = (com == NULL) ? 0 : strlen(com);
|
||||
namesize = (name == NULL) ? 0 : strlen(name);
|
||||
|
||||
if ((comsize + namesize) > MAX_MSG_SIZE)
|
||||
{
|
||||
errlogMessage("drvPIC663.cc:send_mess(); message size violation.\n");
|
||||
return(ERROR);
|
||||
}
|
||||
else if (comsize == 0) /* Normal exit on empty input message. */
|
||||
return(OK);
|
||||
|
||||
if (!motor_state[card])
|
||||
{
|
||||
errlogPrintf("drvPIC663.cc:send_mess() - invalid card #%d\n", card);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
local_buff[0] = (char) NULL; /* Terminate local buffer. */
|
||||
|
||||
/* this device deos not have axis info and so name is ignored! */
|
||||
|
||||
strcat(local_buff, com); /* Make a local copy of the string. */
|
||||
Debug(2, "send_mess(): message = %s\n", local_buff);
|
||||
|
||||
cntrl = (struct PIC663controller *) motor_state[card]->DevicePrivate;
|
||||
pasynOctetSyncIO->write(cntrl->pasynUser, local_buff, strlen(local_buff),
|
||||
COMM_TIMEOUT, &nwrite);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* receive a message from the PIC663 board */
|
||||
/* recv_mess() */
|
||||
/*****************************************************/
|
||||
static int recv_mess(int card, char *com, int flag)
|
||||
{
|
||||
struct PIC663controller *cntrl;
|
||||
size_t nread = 0;
|
||||
asynStatus status = asynError;
|
||||
int eomReason;
|
||||
|
||||
/* Check that card exists */
|
||||
if (!motor_state[card])
|
||||
return(ERROR);
|
||||
|
||||
cntrl = (struct PIC663controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
if (flag == FLUSH)
|
||||
pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
else
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
|
||||
COMM_TIMEOUT, &nread, &eomReason);
|
||||
|
||||
if ((status != asynSuccess) || (nread <= 0))
|
||||
{
|
||||
com[0] = '\0';
|
||||
nread = 0;
|
||||
}
|
||||
else
|
||||
com[nread - 1] = '\0'; /* Strip traling CR. */
|
||||
|
||||
Debug(2, "recv_mess(): message = \"%s\"\n", com);
|
||||
return(nread);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Setup system configuration */
|
||||
/* PIC663Setup() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIC663Setup(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 > PIC663_NUM_CARDS)
|
||||
PIC663_num_cards = PIC663_NUM_CARDS;
|
||||
else
|
||||
PIC663_num_cards = num_cards;
|
||||
|
||||
/* Set motor polling task rate */
|
||||
if (scan_rate >= 1 && scan_rate <= 60)
|
||||
targs.motor_scan_rate = scan_rate;
|
||||
else
|
||||
targs.motor_scan_rate = SCAN_RATE;
|
||||
|
||||
/*
|
||||
* Allocate space for motor_state structures. Note this must be done
|
||||
* before PIC663Config 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(PIC663_num_cards *
|
||||
sizeof(struct controller *));
|
||||
|
||||
for (itera = 0; itera < PIC663_num_cards; itera++)
|
||||
motor_state[itera] = (struct controller *) NULL;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Configure a controller */
|
||||
/* PIC663Config() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIC663Config(int card, /* card being configured */
|
||||
const char *name, /* asyn port name */
|
||||
int addr) /* asyn address ( device address for daisy chaining */
|
||||
{
|
||||
struct PIC663controller *cntrl;
|
||||
|
||||
if (card < 0 || card >= PIC663_num_cards)
|
||||
return(ERROR);
|
||||
|
||||
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
||||
motor_state[card]->DevicePrivate = malloc(sizeof(struct PIC663controller));
|
||||
cntrl = (struct PIC663controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
strcpy(cntrl->asyn_port, name);
|
||||
cntrl->asyn_address = addr;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* initialize all software and hardware */
|
||||
/* This is called from the initialization routine in */
|
||||
/* device support. */
|
||||
/* motor_init() */
|
||||
/*****************************************************/
|
||||
static int motor_init()
|
||||
{
|
||||
struct controller *brdptr;
|
||||
struct PIC663controller *cntrl;
|
||||
int card_index, motor_index;
|
||||
char buff[BUFF_SIZE];
|
||||
int status;
|
||||
asynStatus success_rtn;
|
||||
static const char output_terminator[] = "\r";
|
||||
static const char input_terminator[] = "\n\03";
|
||||
|
||||
initialized = true; /* Indicate that driver is initialized. */
|
||||
|
||||
/* Check for setup */
|
||||
if (PIC663_num_cards <= 0)
|
||||
return(ERROR);
|
||||
|
||||
for (card_index = 0; card_index < PIC663_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 PIC663controller *) brdptr->DevicePrivate;
|
||||
|
||||
/* Initialize communications channel */
|
||||
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));
|
||||
|
||||
/* 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);
|
||||
|
||||
/* To start communicating with the device requires to enable the device
|
||||
To do this send "0x01" and a singel letter address (0-F)
|
||||
To make sure we talk ask the status with "TB" command for the address
|
||||
It replies "B:000x" where x is 0-F
|
||||
The command "VE" provides a complete Identification string if we need.
|
||||
*/
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
sprintf(buff,"\001%1XVE", cntrl->asyn_address);
|
||||
send_mess(card_index, buff, (char*) NULL);
|
||||
status = recv_mess(card_index, buff, 1);
|
||||
retry++;
|
||||
} while (status == 0 && retry < 3);
|
||||
}
|
||||
|
||||
if (success_rtn == asynSuccess && status > 0)
|
||||
{
|
||||
strcpy(brdptr->ident, &buff[0]);
|
||||
brdptr->localaddr = (char *) NULL;
|
||||
brdptr->motor_in_motion = 0;
|
||||
|
||||
/* number of axes is always one.*/
|
||||
brdptr->total_axis = 1;
|
||||
motor_index = 0;
|
||||
|
||||
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;
|
||||
/* PIC663 has DC motor support only */
|
||||
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;
|
||||
|
||||
mess_queue.head = (struct mess_node *) NULL;
|
||||
mess_queue.tail = (struct mess_node *) NULL;
|
||||
|
||||
free_list.head = (struct mess_node *) NULL;
|
||||
free_list.tail = (struct mess_node *) NULL;
|
||||
|
||||
epicsThreadCreate((char *) "PIC663_motor", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
/* File: drvPIC663.h */
|
||||
|
||||
|
||||
/* Device Driver Support definitions for motor */
|
||||
/*
|
||||
* Copied from devPIC862.cc by Jonathan Thompson, Jan 2011
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* Jan 2011 - All references to 862 changed to 663
|
||||
* Status register definitions changed to match 663
|
||||
*/
|
||||
|
||||
#ifndef INCdrvPIC663h
|
||||
#define INCdrvPIC663h 1
|
||||
|
||||
#include "motordrvCom.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
|
||||
#define COMM_TIMEOUT 2.0 /* Timeout in seconds. */
|
||||
|
||||
struct PIC663controller
|
||||
{
|
||||
asynUser *pasynUser; /* asynUser structure */
|
||||
int asyn_address; /* Use for GPIB or other address with asyn */
|
||||
CommStatus status; /* Controller communication status. */
|
||||
char asyn_port[80]; /* asyn port name */
|
||||
};
|
||||
|
||||
|
||||
/* Operation status */
|
||||
typedef union
|
||||
{
|
||||
epicsUInt16 All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
unsigned int na8 :8; /* NA8. */
|
||||
unsigned int drv_cur_act :1; /* 7 - Drive current active. */
|
||||
unsigned int brake_on :1; /* 6 - Brake on. */
|
||||
unsigned int brake_off :1; /* 5 - Brake off. */
|
||||
unsigned int macro_act :1; /* 4 - Macro running. */
|
||||
unsigned int joy_on :1; /* 3 - Joystick on. */
|
||||
unsigned int ref_drv_act :1; /* 2 - Reference drive active. */
|
||||
unsigned int on_target :1; /* 1 - On target. */
|
||||
unsigned int ready :1; /* 0 - Ready. */
|
||||
#else
|
||||
unsigned int ready :1; /* 0 - Ready. */
|
||||
unsigned int on_target :1; /* 1 - On target. */
|
||||
unsigned int ref_drv_act :1; /* 2 - Reference drive active. */
|
||||
unsigned int joy_on :1; /* 3 - Joystick on. */
|
||||
unsigned int macro_act :1; /* 4 - Macro running. */
|
||||
unsigned int brake_off :1; /* 5 - Brake off. */
|
||||
unsigned int brake_on :1; /* 6 - Brake on. */
|
||||
unsigned int drv_cur_act :1; /* 7 - Drive current active. */
|
||||
unsigned int na8 :8; /* NA8. */
|
||||
#endif
|
||||
} Bits;
|
||||
} C663_Status_Reg1;
|
||||
|
||||
/* Hardware flags */
|
||||
typedef union
|
||||
{
|
||||
epicsUInt16 All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
unsigned int na8 :8; /* NA8. */
|
||||
unsigned int in_4 :1; /* 7 - Digital input 4. */
|
||||
unsigned int in_3 :1; /* 6 - Digital input 3. */
|
||||
unsigned int in_2 :1; /* 3 - Digital input 2. */
|
||||
unsigned int in_1 :1; /* 4 - Digital input 1. */
|
||||
unsigned int unused :1; /* 3 - No function. */
|
||||
unsigned int hi_limit :1; /* 2 - Positive limit. */
|
||||
unsigned int ref_signal :1; /* 1 - Reference signal. */
|
||||
unsigned int lo_limit :1; /* 0 - Negative limit. */
|
||||
#else
|
||||
unsigned int lo_limit :1; /* 0 - Negative limit. */
|
||||
unsigned int ref_signal :1; /* 1 - Reference signal. */
|
||||
unsigned int hi_limit :1; /* 2 - Positive limit. */
|
||||
unsigned int unused :1; /* 3 - No function. */
|
||||
unsigned int in_1 :1; /* 4 - Digital input 1. */
|
||||
unsigned int in_2 :1; /* 3 - Digital input 2. */
|
||||
unsigned int in_3 :1; /* 6 - Digital input 3. */
|
||||
unsigned int in_4 :1; /* 7 - Digital input 4. */
|
||||
unsigned int na8 :8; /* NA8. */
|
||||
#endif
|
||||
} Bits;
|
||||
} C663_Status_Reg2;
|
||||
|
||||
/* Error reporting */
|
||||
typedef union
|
||||
{
|
||||
epicsUInt16 All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
unsigned int na8 :8; /* NA8. */
|
||||
unsigned int error :8; /* Error code. */
|
||||
#else
|
||||
unsigned int error :8; /* Error code. */
|
||||
unsigned int na8 :8; /* NA8. */
|
||||
#endif
|
||||
} Bits;
|
||||
} C663_Status_Reg3;
|
||||
|
||||
#define C663_Status_Reg3_NO_ERROR 0x00
|
||||
#define C663_Status_Reg3_RS232_TIMEOUT 0x01
|
||||
#define C663_Status_Reg3_RS232_OVERFLOW 0x02
|
||||
#define C663_Status_Reg3_MACRO_STORAGE_FULL 0x03
|
||||
#define C663_Status_Reg3_MACRO_OUT_OF_RANGE 0x04
|
||||
#define C663_Status_Reg3_WRONG_MACRO_CMD 0x05
|
||||
#define C663_Status_Reg3_COMMAND_ERROR 0x06
|
||||
|
||||
|
||||
/* Function prototypes. */
|
||||
extern RTN_STATUS PIC663Setup(int, int);
|
||||
extern RTN_STATUS PIC663Config(int, const char *, int);
|
||||
|
||||
#endif /* INCdrvPIC663h */
|
||||
@@ -1,648 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvPIC844.cc
|
||||
USAGE... Motor record driver level support for Physik Instrumente (PI)
|
||||
GmbH & Co. C-844 motor controller.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 12/17/03
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 12/17/03 rls - copied from drvIM483PL.cc
|
||||
* .02 02/03/04 rls - Eliminate erroneous "Motor motion timeout ERROR".
|
||||
* .03 07/12/04 rls - Converted from MPF to asyn.
|
||||
* .04 09/09/04 rls - Retry on initial comm. (PIC844 comm. locks up when IOC
|
||||
* is power cycled).
|
||||
* .05 09/21/04 rls - support for 32axes/controller.
|
||||
* .06 12/16/04 rls - asyn R4.0 support.
|
||||
* - make debug variables always available.
|
||||
* - MS Visual C compatibility; make all epicsExportAddress
|
||||
* extern "C" linkage.
|
||||
* .07 08/31/04 rls - Bug fix for no "break"'s in axis #4 switch/case stmts.
|
||||
* in set_status().
|
||||
*/
|
||||
|
||||
/*
|
||||
DESIGN LIMITATIONS...
|
||||
1 - Like all controllers, the PIC844 must be powered-on when EPICS is first
|
||||
booted up.
|
||||
2 - The PIC844 cannot be power cycled while EPICS is up and running. The
|
||||
consequences are permanent communication lose with the PIC844 until
|
||||
EPICS is rebooted.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <epicsThread.h>
|
||||
#include <drvSup.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include "motor.h"
|
||||
#include "drvPI.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define GET_IDENT "*IDN?"
|
||||
|
||||
#define PIC844_NUM_CARDS 8
|
||||
#define MAX_AXES 8
|
||||
#define BUFF_SIZE 100 /* Maximum length of string to/from PIC844 */
|
||||
|
||||
/*----------------debugging-----------------*/
|
||||
volatile int drvPIC844debug = 0;
|
||||
extern "C" {epicsExportAddress(int, drvPIC844debug);}
|
||||
static inline void Debug(int level, const char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
if (level < drvPIC844debug) {
|
||||
va_list pVar;
|
||||
va_start(pVar, format);
|
||||
vprintf(format, pVar);
|
||||
va_end(pVar);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- Local data. --- */
|
||||
int PIC844_num_cards = 0;
|
||||
static char *PIC844_axis[4] = {"1", "2", "3", "4"};
|
||||
|
||||
/* Local data required for every driver; see "motordrvComCode.h" */
|
||||
#include "motordrvComCode.h"
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
static int recv_mess(int, char *, int);
|
||||
static RTN_STATUS send_mess(int, char const *, char *);
|
||||
static int set_status(int, int);
|
||||
static long report(int);
|
||||
static long init();
|
||||
static int motor_init();
|
||||
static void query_done(int, int, struct mess_node *);
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
|
||||
struct driver_table PIC844_access =
|
||||
{
|
||||
motor_init,
|
||||
motor_send,
|
||||
motor_free,
|
||||
motor_card_info,
|
||||
motor_axis_info,
|
||||
&mess_queue,
|
||||
&queue_lock,
|
||||
&free_list,
|
||||
&freelist_lock,
|
||||
&motor_sem,
|
||||
&motor_state,
|
||||
&total_cards,
|
||||
&any_motor_in_motion,
|
||||
send_mess,
|
||||
recv_mess,
|
||||
set_status,
|
||||
query_done,
|
||||
NULL,
|
||||
&initialized,
|
||||
PIC844_axis
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
long number;
|
||||
long (*report) (int);
|
||||
long (*init) (void);
|
||||
} drvPIC844 = {2, report, init};
|
||||
|
||||
extern "C" {epicsExportAddress(drvet, drvPIC844);}
|
||||
|
||||
static struct thread_args targs = {SCAN_RATE, &PIC844_access, 0.0};
|
||||
|
||||
/*********************************************************
|
||||
* Print out driver status report
|
||||
*********************************************************/
|
||||
static long report(int level)
|
||||
{
|
||||
int card;
|
||||
|
||||
if (PIC844_num_cards <=0)
|
||||
printf(" No PIC844 controllers configured.\n");
|
||||
else
|
||||
{
|
||||
for (card = 0; card < PIC844_num_cards; card++)
|
||||
{
|
||||
struct controller *brdptr = motor_state[card];
|
||||
|
||||
if (brdptr == NULL)
|
||||
printf(" PIC844 controller %d connection failed.\n", card);
|
||||
else
|
||||
{
|
||||
struct PIC844controller *cntrl;
|
||||
|
||||
cntrl = (struct PIC844controller *) brdptr->DevicePrivate;
|
||||
printf(" PIC844 controller #%d, port=%s, id: %s \n", card,
|
||||
cntrl->asyn_port, brdptr->ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
static long init()
|
||||
{
|
||||
/*
|
||||
* We cannot call motor_init() here, because that function can do GPIB I/O,
|
||||
* and hence requires that the drvGPIB have already been initialized.
|
||||
* That cannot be guaranteed, so we need to call motor_init from device
|
||||
* support
|
||||
*/
|
||||
/* Check for setup */
|
||||
if (PIC844_num_cards <= 0)
|
||||
{
|
||||
Debug(1, "init(): PIC844 driver disabled. PIC844Setup() missing from startup script.\n");
|
||||
}
|
||||
return((long) 0);
|
||||
}
|
||||
|
||||
|
||||
static void query_done(int card, int axis, struct mess_node *nodeptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* FUNCTION NAME: set_status *
|
||||
* *
|
||||
* LOGIC: *
|
||||
* Initialize. *
|
||||
* Send "Moving Status" query. *
|
||||
* Read response. *
|
||||
* IF normal response to query. *
|
||||
* Set communication status to NORMAL. *
|
||||
* ELSE *
|
||||
* IF communication status is NORMAL. *
|
||||
* Set communication status to RETRY. *
|
||||
* NORMAL EXIT. *
|
||||
* ELSE *
|
||||
* Set communication status error. *
|
||||
* ERROR EXIT. *
|
||||
* ENDIF *
|
||||
* ENDIF *
|
||||
* *
|
||||
* IF "Moving Status" indicates any motion (i.e. status != 0). *
|
||||
* Clear "Done Moving" status bit. *
|
||||
* ELSE *
|
||||
* Set "Done Moving" status bit. *
|
||||
* ENDIF *
|
||||
* *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
static int set_status(int card, int signal)
|
||||
{
|
||||
struct PIC844controller *cntrl;
|
||||
struct mess_node *nodeptr;
|
||||
register struct mess_info *motor_info;
|
||||
/* Message parsing variables */
|
||||
char buff[BUFF_SIZE];
|
||||
C844_Cond_Reg mstat;
|
||||
int rtn_state;
|
||||
double motorData;
|
||||
bool plusdir, ls_active = false, inmotion, plusLS, minusLS;
|
||||
msta_field status;
|
||||
|
||||
cntrl = (struct PIC844controller *) motor_state[card]->DevicePrivate;
|
||||
motor_info = &(motor_state[card]->motor_info[signal]);
|
||||
nodeptr = motor_info->motor_motion;
|
||||
status.All = motor_info->status.All;
|
||||
|
||||
send_mess(card, "AXIS:STAT?", PIC844_axis[signal]);
|
||||
recv_mess(card, buff, 1);
|
||||
|
||||
if (strcmp(buff, "ON") == 0)
|
||||
status.Bits.EA_POSITION = 1;
|
||||
else if (strcmp(buff, "OFF") == 0)
|
||||
status.Bits.EA_POSITION = 0;
|
||||
else
|
||||
{
|
||||
if (cntrl->status == NORMAL)
|
||||
{
|
||||
cntrl->status = RETRY;
|
||||
rtn_state = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cntrl->status = COMM_ERR;
|
||||
status.Bits.CNTRL_COMM_ERR = 1;
|
||||
status.Bits.RA_PROBLEM = 1;
|
||||
rtn_state = 1;
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cntrl->status = NORMAL;
|
||||
status.Bits.CNTRL_COMM_ERR = 0;
|
||||
|
||||
send_mess(card, "MOT:COND?", (char*) NULL);
|
||||
recv_mess(card, buff, 1);
|
||||
|
||||
mstat.All = atoi(&buff[0]);
|
||||
switch(signal)
|
||||
{
|
||||
case 0:
|
||||
inmotion = mstat.Bits.axis1IM;
|
||||
break;
|
||||
case 1:
|
||||
inmotion = mstat.Bits.axis2IM;
|
||||
break;
|
||||
case 2:
|
||||
inmotion = mstat.Bits.axis3IM;
|
||||
break;
|
||||
case 3:
|
||||
inmotion = mstat.Bits.axis4IM;
|
||||
break;
|
||||
default:
|
||||
rtn_state = 1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status.Bits.RA_DONE = (inmotion == YES) ? 0 : 1;
|
||||
|
||||
/*
|
||||
* Parse motor position
|
||||
* Position string format: 1TP5.012,2TP1.123,3TP-100.567,...
|
||||
* Skip to substring for this motor, convert to double
|
||||
*/
|
||||
|
||||
send_mess(card, "CURR:TPOS?", (char*) NULL);
|
||||
recv_mess(card, buff, 1);
|
||||
|
||||
motorData = atof(buff);
|
||||
|
||||
if (motorData == motor_info->position)
|
||||
{
|
||||
if (nodeptr != 0) /* Increment counter only if motor is moving. */
|
||||
motor_info->no_motion_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
epicsInt32 newposition;
|
||||
|
||||
newposition = NINT(motorData);
|
||||
status.Bits.RA_DIRECTION = (newposition >= motor_info->position) ? 1 : 0;
|
||||
motor_info->position = newposition;
|
||||
motor_info->no_motion_count = 0;
|
||||
}
|
||||
|
||||
plusdir = (status.Bits.RA_DIRECTION) ? true : false;
|
||||
|
||||
switch(signal)
|
||||
{
|
||||
case 0:
|
||||
plusLS = mstat.Bits.axis1PL;
|
||||
minusLS = mstat.Bits.axis1ML;
|
||||
break;
|
||||
case 1:
|
||||
plusLS = mstat.Bits.axis2PL;
|
||||
minusLS = mstat.Bits.axis2ML;
|
||||
break;
|
||||
case 2:
|
||||
plusLS = mstat.Bits.axis3PL;
|
||||
minusLS = mstat.Bits.axis3ML;
|
||||
break;
|
||||
case 3:
|
||||
plusLS = mstat.Bits.axis4PL;
|
||||
minusLS = mstat.Bits.axis4ML;
|
||||
break;
|
||||
default:
|
||||
rtn_state = 1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Set limit switch error indicators. */
|
||||
if (plusLS == true)
|
||||
{
|
||||
status.Bits.RA_PLUS_LS = 1;
|
||||
if (plusdir == true)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_PLUS_LS = 0;
|
||||
|
||||
if (minusLS == true)
|
||||
{
|
||||
status.Bits.RA_MINUS_LS = 1;
|
||||
if (plusdir == false)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_MINUS_LS = 0;
|
||||
|
||||
/* encoder status */
|
||||
status.Bits.EA_SLIP = 0;
|
||||
status.Bits.EA_SLIP_STALL = 0;
|
||||
status.Bits.EA_HOME = 0;
|
||||
|
||||
send_mess(card, "AXIS:POS?", (char*) NULL);
|
||||
recv_mess(card, buff, 1);
|
||||
motorData = atof(buff);
|
||||
motor_info->encoder_position = (epicsInt32) motorData;
|
||||
|
||||
status.Bits.RA_PROBLEM = 0;
|
||||
|
||||
/* Parse motor velocity? */
|
||||
/* NEEDS WORK */
|
||||
|
||||
motor_info->velocity = 0;
|
||||
|
||||
if (!status.Bits.RA_DIRECTION)
|
||||
motor_info->velocity *= -1;
|
||||
|
||||
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
|
||||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
|
||||
|
||||
/* Test for post-move string. */
|
||||
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 &&
|
||||
nodeptr->postmsgptr != 0)
|
||||
{
|
||||
strcpy(buff, nodeptr->postmsgptr);
|
||||
send_mess(card, buff, (char*) NULL);
|
||||
nodeptr->postmsgptr = NULL;
|
||||
}
|
||||
|
||||
exit:
|
||||
motor_info->status.All = status.All;
|
||||
return(rtn_state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* send a message to the PIC844 board */
|
||||
/* send_mess() */
|
||||
/*****************************************************/
|
||||
static RTN_STATUS send_mess(int card, char const *com, char *name)
|
||||
{
|
||||
char local_buff[MAX_MSG_SIZE];
|
||||
struct PIC844controller *cntrl;
|
||||
int comsize, namesize;
|
||||
size_t nwrite;
|
||||
|
||||
comsize = (com == NULL) ? 0 : strlen(com);
|
||||
namesize = (name == NULL) ? 0 : strlen(name);
|
||||
|
||||
if ((comsize + namesize) > MAX_MSG_SIZE)
|
||||
{
|
||||
errlogMessage("drvPIC844.cc:send_mess(); message size violation.\n");
|
||||
return(ERROR);
|
||||
}
|
||||
else if (comsize == 0) /* Normal exit on empty input message. */
|
||||
return(OK);
|
||||
|
||||
if (!motor_state[card])
|
||||
{
|
||||
errlogPrintf("drvPIC844.cc:send_mess() - invalid card #%d\n", card);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
local_buff[0] = (char) NULL; /* Terminate local buffer. */
|
||||
|
||||
if (name != NULL)
|
||||
{
|
||||
strcpy(local_buff, "AXIS ");
|
||||
strcat(local_buff, name); /* put in axis. */
|
||||
strcat(local_buff, ";"); /* put in comman seperator. */
|
||||
}
|
||||
|
||||
/* Make a local copy of the string. */
|
||||
strcat(local_buff, com);
|
||||
|
||||
Debug(2, "send_mess(): message = %s\n", local_buff);
|
||||
|
||||
cntrl = (struct PIC844controller *) motor_state[card]->DevicePrivate;
|
||||
pasynOctetSyncIO->write(cntrl->pasynUser, local_buff, strlen(local_buff),
|
||||
COMM_TIMEOUT, &nwrite);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* receive a message from the PIC844 board */
|
||||
/* recv_mess() */
|
||||
/*****************************************************/
|
||||
static int recv_mess(int card, char *com, int flag)
|
||||
{
|
||||
struct PIC844controller *cntrl;
|
||||
size_t nread = 0;
|
||||
asynStatus status = asynError;
|
||||
int eomReason;
|
||||
|
||||
/* Check that card exists */
|
||||
if (!motor_state[card])
|
||||
return(ERROR);
|
||||
|
||||
cntrl = (struct PIC844controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
if (flag == FLUSH)
|
||||
pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
else
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
|
||||
COMM_TIMEOUT, &nread, &eomReason);
|
||||
|
||||
if ((status != asynSuccess) || (nread <= 0))
|
||||
{
|
||||
com[0] = '\0';
|
||||
nread = 0;
|
||||
}
|
||||
|
||||
Debug(2, "recv_mess(): message = \"%s\"\n", com);
|
||||
return(nread);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Setup system configuration */
|
||||
/* PIC844Setup() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIC844Setup(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 > PIC844_NUM_CARDS)
|
||||
PIC844_num_cards = PIC844_NUM_CARDS;
|
||||
else
|
||||
PIC844_num_cards = num_cards;
|
||||
|
||||
/* Set motor polling task rate */
|
||||
if (scan_rate >= 1 && scan_rate <= 60)
|
||||
targs.motor_scan_rate = scan_rate;
|
||||
else
|
||||
targs.motor_scan_rate = SCAN_RATE;
|
||||
|
||||
/*
|
||||
* Allocate space for motor_state structures. Note this must be done
|
||||
* before PIC844Config 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(PIC844_num_cards *
|
||||
sizeof(struct controller *));
|
||||
|
||||
for (itera = 0; itera < PIC844_num_cards; itera++)
|
||||
motor_state[itera] = (struct controller *) NULL;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Configure a controller */
|
||||
/* PIC844Config() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIC844Config(int card, /* card being configured */
|
||||
const char *name, /* asyn port name */
|
||||
int addr) /* asyn address (GPIB) */
|
||||
{
|
||||
struct PIC844controller *cntrl;
|
||||
|
||||
if (card < 0 || card >= PIC844_num_cards)
|
||||
return (ERROR);
|
||||
|
||||
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
||||
motor_state[card]->DevicePrivate = malloc(sizeof(struct PIC844controller));
|
||||
cntrl = (struct PIC844controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
strcpy(cntrl->asyn_port, name);
|
||||
cntrl->asyn_address = addr;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* initialize all software and hardware */
|
||||
/* This is called from the initialization routine in */
|
||||
/* device support. */
|
||||
/* motor_init() */
|
||||
/*****************************************************/
|
||||
static int motor_init()
|
||||
{
|
||||
struct controller *brdptr;
|
||||
struct PIC844controller *cntrl;
|
||||
int card_index, motor_index;
|
||||
char buff[BUFF_SIZE];
|
||||
int total_axis;
|
||||
int status;
|
||||
asynStatus success_rtn;
|
||||
static const char output_terminator[] = "\n";
|
||||
static const char input_terminator[] = "\n";
|
||||
|
||||
initialized = true; /* Indicate that driver is initialized. */
|
||||
|
||||
/* Check for setup */
|
||||
if (PIC844_num_cards <= 0)
|
||||
return(ERROR);
|
||||
|
||||
for (card_index = 0; card_index < PIC844_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 PIC844controller *) brdptr->DevicePrivate;
|
||||
|
||||
/* Initialize communications channel */
|
||||
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));
|
||||
|
||||
/* 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++;
|
||||
} while (status == 0 && retry < 3);
|
||||
}
|
||||
|
||||
if (success_rtn == asynSuccess && status > 0)
|
||||
{
|
||||
strcpy(brdptr->ident, &buff[0]);
|
||||
brdptr->localaddr = (char *) NULL;
|
||||
brdptr->motor_in_motion = 0;
|
||||
brdptr->total_axis = total_axis = 4;
|
||||
|
||||
for (motor_index = 0; motor_index < total_axis; motor_index++)
|
||||
{
|
||||
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
|
||||
|
||||
motor_info->status.All = 0;
|
||||
motor_info->no_motion_count = 0;
|
||||
motor_info->encoder_position = 0;
|
||||
motor_info->position = 0;
|
||||
brdptr->motor_info[motor_index].motor_motion = NULL;
|
||||
/* PIC844 has DC motor support only */
|
||||
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;
|
||||
|
||||
mess_queue.head = (struct mess_node *) NULL;
|
||||
mess_queue.tail = (struct mess_node *) NULL;
|
||||
|
||||
free_list.head = (struct mess_node *) NULL;
|
||||
free_list.tail = (struct mess_node *) NULL;
|
||||
|
||||
epicsThreadCreate((char *) "PIC844_motor", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
@@ -1,619 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvPIC848.cc
|
||||
USAGE... Motor record driver level support for Physik Instrumente (PI)
|
||||
GmbH & Co. C-848 motor controller.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 10/18/05
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 10/18/05 rls - copied from drvPIC844.cc
|
||||
* .02 10/17/07 rls - Added "Motor motion timeout" error check.
|
||||
* - Set "reference" home switch indicator.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESIGN LIMITATIONS...
|
||||
1 - Like all controllers, the PIC848 must be powered-on when EPICS is first
|
||||
booted up.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <epicsThread.h>
|
||||
#include <drvSup.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "drvPIC848.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define GET_IDENT "*IDN?"
|
||||
|
||||
#define PIC848_NUM_CARDS 8
|
||||
#define MAX_AXES 4
|
||||
#define BUFF_SIZE 100 /* Maximum length of string to/from PIC848 */
|
||||
|
||||
/*----------------debugging-----------------*/
|
||||
volatile int drvPIC848debug = 0;
|
||||
extern "C" {epicsExportAddress(int, drvPIC848debug);}
|
||||
static inline void Debug(int level, const char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
if (level < drvPIC848debug) {
|
||||
va_list pVar;
|
||||
va_start(pVar, format);
|
||||
vprintf(format, pVar);
|
||||
va_end(pVar);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- Local data. --- */
|
||||
int PIC848_num_cards = 0;
|
||||
static char *PIC848_axis[4] = {"A", "B", "C", "D"};
|
||||
static volatile int motionTO = 10;
|
||||
|
||||
/* Local data required for every driver; see "motordrvComCode.h" */
|
||||
#include "motordrvComCode.h"
|
||||
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
static int recv_mess(int, char *, int);
|
||||
static RTN_STATUS send_mess(int, char const *, char *);
|
||||
static int set_status(int, int);
|
||||
static long report(int);
|
||||
static long init();
|
||||
static int motor_init();
|
||||
static void query_done(int, int, struct mess_node *);
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
|
||||
struct driver_table PIC848_access =
|
||||
{
|
||||
motor_init,
|
||||
motor_send,
|
||||
motor_free,
|
||||
motor_card_info,
|
||||
motor_axis_info,
|
||||
&mess_queue,
|
||||
&queue_lock,
|
||||
&free_list,
|
||||
&freelist_lock,
|
||||
&motor_sem,
|
||||
&motor_state,
|
||||
&total_cards,
|
||||
&any_motor_in_motion,
|
||||
send_mess,
|
||||
recv_mess,
|
||||
set_status,
|
||||
query_done,
|
||||
NULL,
|
||||
&initialized,
|
||||
PIC848_axis
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
long number;
|
||||
long (*report) (int);
|
||||
long (*init) (void);
|
||||
} drvPIC848 = {2, report, init};
|
||||
|
||||
extern "C" {epicsExportAddress(drvet, drvPIC848);}
|
||||
|
||||
static struct thread_args targs = {SCAN_RATE, &PIC848_access, 0.0};
|
||||
|
||||
/*********************************************************
|
||||
* Print out driver status report
|
||||
*********************************************************/
|
||||
static long report(int level)
|
||||
{
|
||||
int card;
|
||||
|
||||
if (PIC848_num_cards <=0)
|
||||
printf(" No PIC848 controllers configured.\n");
|
||||
else
|
||||
{
|
||||
for (card = 0; card < PIC848_num_cards; card++)
|
||||
{
|
||||
struct controller *brdptr = motor_state[card];
|
||||
|
||||
if (brdptr == NULL)
|
||||
printf(" PIC848 controller %d connection failed.\n", card);
|
||||
else
|
||||
{
|
||||
struct PIC848controller *cntrl;
|
||||
|
||||
cntrl = (struct PIC848controller *) brdptr->DevicePrivate;
|
||||
printf(" PIC848 controller #%d, port=%s, id: %s \n", card,
|
||||
cntrl->asyn_port, brdptr->ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
static long init()
|
||||
{
|
||||
/*
|
||||
* We cannot call motor_init() here, because that function can do GPIB I/O,
|
||||
* and hence requires that the drvGPIB have already been initialized.
|
||||
* That cannot be guaranteed, so we need to call motor_init from device
|
||||
* support
|
||||
*/
|
||||
/* Check for setup */
|
||||
if (PIC848_num_cards <= 0)
|
||||
{
|
||||
Debug(1, "init(): PIC848 driver disabled. PIC848Setup() missing from startup script.\n");
|
||||
}
|
||||
return((long) 0);
|
||||
}
|
||||
|
||||
|
||||
static void query_done(int card, int axis, struct mess_node *nodeptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* FUNCTION NAME: set_status *
|
||||
* *
|
||||
* LOGIC: *
|
||||
* Initialize. *
|
||||
* Send "Moving Status" query. *
|
||||
* Read response. *
|
||||
* IF normal response to query. *
|
||||
* Set communication status to NORMAL. *
|
||||
* ELSE *
|
||||
* IF communication status is NORMAL. *
|
||||
* Set communication status to RETRY. *
|
||||
* NORMAL EXIT. *
|
||||
* ELSE *
|
||||
* Set communication status error. *
|
||||
* ERROR EXIT. *
|
||||
* ENDIF *
|
||||
* ENDIF *
|
||||
* *
|
||||
* IF "Moving Status" indicates any motion (i.e. status != 0). *
|
||||
* Clear "Done Moving" status bit. *
|
||||
* ELSE *
|
||||
* Set "Done Moving" status bit. *
|
||||
* ENDIF *
|
||||
* *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
static int set_status(int card, int signal)
|
||||
{
|
||||
struct PIC848controller *cntrl;
|
||||
struct mess_node *nodeptr;
|
||||
struct mess_info *motor_info;
|
||||
struct motorRecord *mr;
|
||||
/* Message parsing variables */
|
||||
char buff[BUFF_SIZE], axisID;
|
||||
C848_Status_Reg mstat;
|
||||
int rtn_state, convert_cnt, charcnt, tempInt;
|
||||
epicsInt32 motorData;
|
||||
bool plusdir, ls_active = false, plusLS, minusLS;
|
||||
msta_field status;
|
||||
|
||||
cntrl = (struct PIC848controller *) motor_state[card]->DevicePrivate;
|
||||
motor_info = &(motor_state[card]->motor_info[signal]);
|
||||
nodeptr = motor_info->motor_motion;
|
||||
if (nodeptr != NULL)
|
||||
mr = (struct motorRecord *) nodeptr->mrecord;
|
||||
else
|
||||
mr = NULL;
|
||||
status.All = motor_info->status.All;
|
||||
|
||||
if (cntrl->status != NORMAL)
|
||||
charcnt = recv_mess(card, buff, FLUSH);
|
||||
|
||||
send_mess(card, "STA? #", PIC848_axis[signal]);
|
||||
charcnt = recv_mess(card, buff, 1);
|
||||
if (charcnt > 2)
|
||||
convert_cnt = sscanf(buff, "%c=%d\n", &axisID, &tempInt);
|
||||
|
||||
if (charcnt > 2 && convert_cnt == 2)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
mstat.All = tempInt;
|
||||
status.Bits.RA_DONE = (mstat.Bits.Done) ? 1 : 0;
|
||||
status.Bits.EA_POSITION = (mstat.Bits.torque) ? 1 : 0;
|
||||
plusLS = mstat.Bits.plus_ls;
|
||||
minusLS = mstat.Bits.minus_ls;
|
||||
|
||||
send_mess(card, "POS? #", PIC848_axis[signal]);
|
||||
recv_mess(card, buff, 1);
|
||||
|
||||
motorData = NINT(atof(&buff[2]) / cntrl->drive_resolution[signal]);
|
||||
|
||||
if (motorData == motor_info->position)
|
||||
{
|
||||
if (nodeptr != 0) /* Increment counter only if motor is moving. */
|
||||
motor_info->no_motion_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
status.Bits.RA_DIRECTION = (motorData >= motor_info->position) ? 1 : 0;
|
||||
motor_info->position = motor_info->encoder_position = motorData;
|
||||
motor_info->no_motion_count = 0;
|
||||
}
|
||||
|
||||
if (motor_info->no_motion_count > motionTO)
|
||||
{
|
||||
status.Bits.RA_PROBLEM = 1;
|
||||
send_mess(card, "HLT #", PIC848_axis[signal]);
|
||||
motor_info->no_motion_count = 0;
|
||||
errlogSevPrintf(errlogMinor, "Motor motion timeout ERROR on card: %d, signal: %d\n",
|
||||
card, signal);
|
||||
}
|
||||
else
|
||||
status.Bits.RA_PROBLEM = 0;
|
||||
|
||||
plusdir = (status.Bits.RA_DIRECTION) ? true : false;
|
||||
|
||||
/* Set limit switch error indicators. */
|
||||
if (plusLS == true)
|
||||
{
|
||||
status.Bits.RA_PLUS_LS = 1;
|
||||
if (plusdir == true)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_PLUS_LS = 0;
|
||||
|
||||
if (minusLS == true)
|
||||
{
|
||||
status.Bits.RA_MINUS_LS = 1;
|
||||
if (plusdir == false)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_MINUS_LS = 0;
|
||||
|
||||
/* encoder status */
|
||||
status.Bits.EA_SLIP = 0;
|
||||
status.Bits.EA_SLIP_STALL = 0;
|
||||
status.Bits.EA_HOME = 0;
|
||||
|
||||
/* Parse motor velocity? */
|
||||
/* NEEDS WORK */
|
||||
|
||||
motor_info->velocity = 0;
|
||||
|
||||
if (!status.Bits.RA_DIRECTION)
|
||||
motor_info->velocity *= -1;
|
||||
|
||||
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
|
||||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
|
||||
|
||||
/* Test for post-move string. */
|
||||
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 &&
|
||||
nodeptr->postmsgptr != 0)
|
||||
{
|
||||
strcpy(buff, nodeptr->postmsgptr);
|
||||
send_mess(card, buff, (char*) NULL);
|
||||
nodeptr->postmsgptr = NULL;
|
||||
}
|
||||
|
||||
exit:
|
||||
motor_info->status.All = status.All;
|
||||
return(rtn_state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* send a message to the PIC848 board */
|
||||
/* send_mess() */
|
||||
/*****************************************************/
|
||||
static RTN_STATUS send_mess(int card, char const *com, char *name)
|
||||
{
|
||||
char local_buff[MAX_MSG_SIZE];
|
||||
struct PIC848controller *cntrl;
|
||||
int comsize, namesize;
|
||||
size_t nwrite;
|
||||
|
||||
comsize = (com == NULL) ? 0 : strlen(com);
|
||||
namesize = (name == NULL) ? 0 : strlen(name);
|
||||
|
||||
if ((comsize + namesize) > MAX_MSG_SIZE)
|
||||
{
|
||||
errlogMessage("drvPIC848.cc:send_mess(); message size violation.\n");
|
||||
return(ERROR);
|
||||
}
|
||||
else if (comsize == 0) /* Normal exit on empty input message. */
|
||||
return(OK);
|
||||
|
||||
if (!motor_state[card])
|
||||
{
|
||||
errlogPrintf("drvPIC848.cc:send_mess() - invalid card #%d\n", card);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
local_buff[0] = (char) NULL; /* Terminate local buffer. */
|
||||
|
||||
if (name == NULL)
|
||||
strcat(local_buff, com); /* Make a local copy of the string. */
|
||||
else
|
||||
{
|
||||
strcpy(local_buff, com);
|
||||
local_buff[5] = *name; /* put in axis. */
|
||||
}
|
||||
|
||||
Debug(2, "send_mess(): message = %s\n", local_buff);
|
||||
|
||||
cntrl = (struct PIC848controller *) motor_state[card]->DevicePrivate;
|
||||
pasynOctetSyncIO->write(cntrl->pasynUser, local_buff, strlen(local_buff),
|
||||
COMM_TIMEOUT, &nwrite);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* receive a message from the PIC848 board */
|
||||
/* recv_mess() */
|
||||
/*****************************************************/
|
||||
static int recv_mess(int card, char *com, int flag)
|
||||
{
|
||||
struct PIC848controller *cntrl;
|
||||
size_t nread = 0;
|
||||
asynStatus status = asynError;
|
||||
int eomReason;
|
||||
|
||||
/* Check that card exists */
|
||||
if (!motor_state[card])
|
||||
return(ERROR);
|
||||
|
||||
cntrl = (struct PIC848controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
if (flag == FLUSH)
|
||||
pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
else
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
|
||||
COMM_TIMEOUT, &nread, &eomReason);
|
||||
|
||||
if ((status != asynSuccess) || (nread <= 0))
|
||||
{
|
||||
com[0] = '\0';
|
||||
nread = 0;
|
||||
}
|
||||
|
||||
Debug(2, "recv_mess(): message = \"%s\"\n", com);
|
||||
return(nread);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Setup system configuration */
|
||||
/* PIC848Setup() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIC848Setup(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 > PIC848_NUM_CARDS)
|
||||
PIC848_num_cards = PIC848_NUM_CARDS;
|
||||
else
|
||||
PIC848_num_cards = num_cards;
|
||||
|
||||
/* Set motor polling task rate */
|
||||
if (scan_rate >= 1 && scan_rate <= 60)
|
||||
targs.motor_scan_rate = scan_rate;
|
||||
else
|
||||
targs.motor_scan_rate = SCAN_RATE;
|
||||
|
||||
/*
|
||||
* Allocate space for motor_state structures. Note this must be done
|
||||
* before PIC848Config 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(PIC848_num_cards *
|
||||
sizeof(struct controller *));
|
||||
|
||||
for (itera = 0; itera < PIC848_num_cards; itera++)
|
||||
motor_state[itera] = (struct controller *) NULL;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Configure a controller */
|
||||
/* PIC848Config() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIC848Config(int card, /* card being configured */
|
||||
const char *name, /* asyn port name */
|
||||
int addr) /* asyn address (GPIB) */
|
||||
{
|
||||
struct PIC848controller *cntrl;
|
||||
|
||||
if (card < 0 || card >= PIC848_num_cards)
|
||||
return(ERROR);
|
||||
|
||||
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
||||
motor_state[card]->DevicePrivate = malloc(sizeof(struct PIC848controller));
|
||||
cntrl = (struct PIC848controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
strcpy(cntrl->asyn_port, name);
|
||||
cntrl->asyn_address = addr;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* initialize all software and hardware */
|
||||
/* This is called from the initialization routine in */
|
||||
/* device support. */
|
||||
/* motor_init() */
|
||||
/*****************************************************/
|
||||
static int motor_init()
|
||||
{
|
||||
struct controller *brdptr;
|
||||
struct PIC848controller *cntrl;
|
||||
int card_index, motor_index;
|
||||
char buff[BUFF_SIZE];
|
||||
int total_axis;
|
||||
int status;
|
||||
asynStatus success_rtn;
|
||||
static const char output_terminator[] = "\n";
|
||||
static const char input_terminator[] = "\n";
|
||||
|
||||
initialized = true; /* Indicate that driver is initialized. */
|
||||
|
||||
/* Check for setup */
|
||||
if (PIC848_num_cards <= 0)
|
||||
return(ERROR);
|
||||
|
||||
for (card_index = 0; card_index < PIC848_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 PIC848controller *) brdptr->DevicePrivate;
|
||||
|
||||
/* Initialize communications channel */
|
||||
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));
|
||||
|
||||
/* 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++;
|
||||
} while (status == 0 && retry < 3);
|
||||
}
|
||||
|
||||
if (success_rtn == asynSuccess && status > 0)
|
||||
{
|
||||
strcpy(brdptr->ident, &buff[0]);
|
||||
brdptr->localaddr = (char *) NULL;
|
||||
brdptr->motor_in_motion = 0;
|
||||
|
||||
/* Determine # of axes. Request stage name. See if it responds */
|
||||
for (total_axis = 0; total_axis < MAX_AXES; total_axis++)
|
||||
{
|
||||
send_mess(card_index, "CST? #", PIC848_axis[total_axis]);
|
||||
status = recv_mess(card_index, buff, 1);
|
||||
if (strcmp(&buff[2],"NOSTAGE") == 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];
|
||||
|
||||
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;
|
||||
/* PIC848 has DC motor support only */
|
||||
motor_info->encoder_present = YES;
|
||||
motor_info->status.Bits.EA_PRESENT = 1;
|
||||
motor_info->pid_present = YES;
|
||||
motor_info->status.Bits.GAIN_SUPPORT = 1;
|
||||
|
||||
cntrl->drive_resolution[motor_index] = POS_RES;
|
||||
|
||||
/* Determine if stage has a reference (home) switch. */
|
||||
send_mess(card_index, "REF? #", PIC848_axis[motor_index]);
|
||||
status = recv_mess(card_index, buff, 1);
|
||||
if (strcmp(&buff[2],"0") == 0)
|
||||
cntrl->reference[motor_index] = false;
|
||||
else
|
||||
cntrl->reference[motor_index] = true;
|
||||
|
||||
set_status(card_index, motor_index); /* Read status of each motor */
|
||||
}
|
||||
}
|
||||
else
|
||||
motor_state[card_index] = (struct controller *) NULL;
|
||||
}
|
||||
|
||||
any_motor_in_motion = 0;
|
||||
|
||||
mess_queue.head = (struct mess_node *) NULL;
|
||||
mess_queue.tail = (struct mess_node *) NULL;
|
||||
|
||||
free_list.head = (struct mess_node *) NULL;
|
||||
free_list.tail = (struct mess_node *) NULL;
|
||||
|
||||
epicsThreadCreate((char *) "PIC848_motor", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/* File: drvPIC848.h */
|
||||
|
||||
|
||||
/* Device Driver Support definitions for motor */
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Current Author: Ron Sluiter
|
||||
* Date: 09/20/2005
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 09/20/2005 rls copied from drvPIC630.h
|
||||
* .01 10/17/2007 rls - Added "reference" home switch indicator.
|
||||
- increased position resolution scaler.
|
||||
*/
|
||||
|
||||
#ifndef INCdrvPIC848h
|
||||
#define INCdrvPIC848h 1
|
||||
|
||||
#include "motordrvCom.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
|
||||
#define COMM_TIMEOUT 2 /* Timeout in seconds. */
|
||||
#define POS_RES 0.000001 /* Position resolution. */
|
||||
|
||||
struct PIC848controller
|
||||
{
|
||||
bool reference[4]; /* reference sensor; if true, axis position can
|
||||
* only be set to zero; if false, axis position
|
||||
* must be set before axis can be moved. */
|
||||
asynUser *pasynUser; /* asynUser structure */
|
||||
int asyn_address; /* Use for GPIB or other address with asyn */
|
||||
CommStatus status; /* Controller communication status. */
|
||||
double drive_resolution[4];
|
||||
char asyn_port[80]; /* asyn port name */
|
||||
};
|
||||
|
||||
|
||||
typedef union
|
||||
{
|
||||
epicsUInt16 All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
unsigned int na15 :1;
|
||||
unsigned int na14 :1;
|
||||
unsigned int axisID :2; /*12-13 - Axis ID; 0/A, 1/B, 2/C, 3/D */
|
||||
unsigned int na11 :1;
|
||||
unsigned int in_motion :1; /*10 - Axis in motion flag. */
|
||||
unsigned int axis_on :1; /* 9 - Axis on; always on (1). */
|
||||
unsigned int torque :1; /* 8 - Servo-control status. */
|
||||
unsigned int cmnd_err :1; /* 7 - Command error flag. */
|
||||
unsigned int minus_ls :1; /* 6 - Negative limit switch flag. */
|
||||
unsigned int plus_ls :1; /* 5 - Positive limit switch flag. */
|
||||
unsigned int max_pos_err :1; /* 4 - Maximum position error is exceeded. */
|
||||
unsigned int index :1; /* 3 - Index pulse received flag. */
|
||||
unsigned int breakpt :1; /* 2 - Breakpoint reached flag. */
|
||||
unsigned int wrap_around :1; /* 1 - Position wrap-around flag. */
|
||||
unsigned int Done :1; /* 0 - Axis trajectory complete. */
|
||||
#else
|
||||
unsigned int Done :1; /* 0 - Axis trajectory complete. */
|
||||
unsigned int wrap_around :1; /* 1 - Position wrap-around flag. */
|
||||
unsigned int breakpt :1; /* 2 - Breakpoint reached flag. */
|
||||
unsigned int index :1; /* 3 - Index pulse received flag. */
|
||||
unsigned int max_pos_err :1; /* 4 - Maximum position error is exceeded. */
|
||||
unsigned int plus_ls :1; /* 5 - Positive limit switch flag. */
|
||||
unsigned int minus_ls :1; /* 6 - Negative limit switch flag. */
|
||||
unsigned int cmnd_err :1; /* 7 - Command error flag. */
|
||||
unsigned int torque :1; /* 8 - Servo-control status. */
|
||||
unsigned int axis_on :1; /* 9 - Axis on; always on (1). */
|
||||
unsigned int in_motion :1; /*10 - Axis in motion flag. */
|
||||
unsigned int na11 :1;
|
||||
unsigned int axisID :2; /*12-13 - Axis ID; 0/A, 1/B, 2/C, 3/D */
|
||||
unsigned int na14 :1;
|
||||
unsigned int na15 :1;
|
||||
#endif
|
||||
} Bits;
|
||||
} C848_Status_Reg;
|
||||
|
||||
|
||||
/* Function prototypes. */
|
||||
extern RTN_STATUS PIC848Setup(int, int);
|
||||
extern RTN_STATUS PIC848Config(int, const char *, int);
|
||||
|
||||
#endif /* INCdrvPIC848h */
|
||||
@@ -1,600 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvPIC862.cc
|
||||
USAGE... Motor record driver level support for Physik Instrumente (PI)
|
||||
GmbH & Co. C-862 motor controller.
|
||||
*/
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Current Author: Mohan Ramanathan
|
||||
* Date: 09/04/2006
|
||||
*
|
||||
* NOTES
|
||||
* -----
|
||||
* - This driver works with both the C-862 and C-863.
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 09/05/2006 mr copied from drvPIC848.cc
|
||||
* .01 09/25/2006 rls Set LS error indicator based on LS active high/low
|
||||
* configuration indicator and the state of the LS.
|
||||
* .02 09/28/2006 rls C-862 drops transmitted characters on move command;
|
||||
* need "status update delay".
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
DESIGN LIMITATIONS...
|
||||
1 - Like all controllers, the PIC862 must be powered-on when EPICS is first
|
||||
booted up.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <epicsThread.h>
|
||||
#include <drvSup.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "drvPIC862.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define GET_IDENT 0x01
|
||||
|
||||
#define PIC862_NUM_CARDS 8
|
||||
#define MAX_AXES 1
|
||||
#define BUFF_SIZE 100 /* Maximum length of string to/from PIC862 */
|
||||
|
||||
/*----------------debugging-----------------*/
|
||||
volatile int drvPIC862debug = 0;
|
||||
extern "C" {epicsExportAddress(int, drvPIC862debug);}
|
||||
static inline void Debug(int level, const char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
if (level < drvPIC862debug) {
|
||||
va_list pVar;
|
||||
va_start(pVar, format);
|
||||
vprintf(format, pVar);
|
||||
va_end(pVar);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- Local data. --- */
|
||||
int PIC862_num_cards = 0;
|
||||
|
||||
/* Local data required for every driver; see "motordrvComCode.h" */
|
||||
#include "motordrvComCode.h"
|
||||
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
static int recv_mess(int, char *, int);
|
||||
static RTN_STATUS send_mess(int, char const *, char *);
|
||||
static int set_status(int, int);
|
||||
static long report(int);
|
||||
static long init();
|
||||
static int motor_init();
|
||||
static void query_done(int, int, struct mess_node *);
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
|
||||
struct driver_table PIC862_access =
|
||||
{
|
||||
motor_init,
|
||||
motor_send,
|
||||
motor_free,
|
||||
motor_card_info,
|
||||
motor_axis_info,
|
||||
&mess_queue,
|
||||
&queue_lock,
|
||||
&free_list,
|
||||
&freelist_lock,
|
||||
&motor_sem,
|
||||
&motor_state,
|
||||
&total_cards,
|
||||
&any_motor_in_motion,
|
||||
send_mess,
|
||||
recv_mess,
|
||||
set_status,
|
||||
query_done,
|
||||
NULL,
|
||||
&initialized,
|
||||
NULL
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
long number;
|
||||
long (*report) (int);
|
||||
long (*init) (void);
|
||||
} drvPIC862 = {2, report, init};
|
||||
|
||||
extern "C" {epicsExportAddress(drvet, drvPIC862);}
|
||||
|
||||
static struct thread_args targs = {SCAN_RATE, &PIC862_access, 0.017};
|
||||
|
||||
/*********************************************************
|
||||
* Print out driver status report
|
||||
*********************************************************/
|
||||
static long report(int level)
|
||||
{
|
||||
int card;
|
||||
|
||||
if (PIC862_num_cards <=0)
|
||||
printf(" No PIC862 controllers configured.\n");
|
||||
else
|
||||
{
|
||||
for (card = 0; card < PIC862_num_cards; card++)
|
||||
{
|
||||
struct controller *brdptr = motor_state[card];
|
||||
|
||||
if (brdptr == NULL)
|
||||
printf(" PIC862 controller %d connection failed.\n", card);
|
||||
else
|
||||
{
|
||||
struct PIC862controller *cntrl;
|
||||
|
||||
cntrl = (struct PIC862controller *) brdptr->DevicePrivate;
|
||||
printf(" PIC862 controller #%d, port=%s, id: %s \n", card,
|
||||
cntrl->asyn_port, brdptr->ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
static long init()
|
||||
{
|
||||
/*
|
||||
* We cannot call motor_init() here, because that function can do GPIB I/O,
|
||||
* and hence requires that the drvGPIB have already been initialized.
|
||||
* That cannot be guaranteed, so we need to call motor_init from device
|
||||
* support
|
||||
*/
|
||||
/* Check for setup */
|
||||
if (PIC862_num_cards <= 0)
|
||||
{
|
||||
Debug(1, "init(): PIC862 driver disabled. PIC862Setup() missing from startup script.\n");
|
||||
}
|
||||
return((long) 0);
|
||||
}
|
||||
|
||||
|
||||
static void query_done(int card, int axis, struct mess_node *nodeptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* FUNCTION NAME: set_status *
|
||||
* *
|
||||
* LOGIC: *
|
||||
* Initialize. *
|
||||
* Send "Moving Status" query. *
|
||||
* Read response. *
|
||||
* IF normal response to query. *
|
||||
* Set communication status to NORMAL. *
|
||||
* ELSE *
|
||||
* IF communication status is NORMAL. *
|
||||
* Set communication status to RETRY. *
|
||||
* NORMAL EXIT. *
|
||||
* ELSE *
|
||||
* Set communication status error. *
|
||||
* ERROR EXIT. *
|
||||
* ENDIF *
|
||||
* ENDIF *
|
||||
* *
|
||||
* IF "Moving Status" indicates any motion (i.e. status != 0). *
|
||||
* Clear "Done Moving" status bit. *
|
||||
* ELSE *
|
||||
* Set "Done Moving" status bit. *
|
||||
* ENDIF *
|
||||
* *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
static int set_status(int card, int signal)
|
||||
{
|
||||
struct PIC862controller *cntrl;
|
||||
struct mess_node *nodeptr;
|
||||
struct mess_info *motor_info;
|
||||
struct motorRecord *mr;
|
||||
/* Message parsing variables */
|
||||
char buff[BUFF_SIZE];
|
||||
C862_Status_Reg1 mstat1;
|
||||
C862_Status_Reg2 mstat2;
|
||||
C862_Status_Reg3 mstat3;
|
||||
C862_Status_Reg4 mstat4;
|
||||
C862_Status_Reg5 mstat5;
|
||||
epicsUInt16 dev_sts1, dev_sts2, dev_sts3, dev_sts4, dev_sts5, dev_sts6;
|
||||
|
||||
int rtn_state, convert_cnt, charcnt;
|
||||
epicsInt32 motorData;
|
||||
bool plusdir, ls_active = false, plusLS, minusLS, LSactiveH;
|
||||
msta_field status;
|
||||
|
||||
cntrl = (struct PIC862controller *) motor_state[card]->DevicePrivate;
|
||||
motor_info = &(motor_state[card]->motor_info[signal]);
|
||||
nodeptr = motor_info->motor_motion;
|
||||
if (nodeptr != NULL)
|
||||
mr = (struct motorRecord *) nodeptr->mrecord;
|
||||
else
|
||||
mr = NULL;
|
||||
status.All = motor_info->status.All;
|
||||
|
||||
if (cntrl->status != NORMAL)
|
||||
charcnt = recv_mess(card, buff, FLUSH);
|
||||
|
||||
send_mess(card, "TS", (char*) NULL); /* Tell Status */
|
||||
charcnt = recv_mess(card, buff, 1);
|
||||
if (charcnt > 18)
|
||||
convert_cnt = sscanf(buff, "S:%2hx %2hx %2hx %2hx %2hx %2hx\n",
|
||||
&dev_sts1,&dev_sts2,&dev_sts3,&dev_sts4,&dev_sts5,&dev_sts6);
|
||||
|
||||
if (charcnt > 18 && convert_cnt == 6)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
mstat1.All = dev_sts1;
|
||||
mstat2.All = dev_sts2;
|
||||
mstat3.All = dev_sts3;
|
||||
mstat4.All = dev_sts4;
|
||||
mstat5.All = dev_sts5;
|
||||
|
||||
status.Bits.RA_DONE = (mstat1.Bits.trty_done) ? 1 : 0;
|
||||
status.Bits.EA_POSITION = (mstat1.Bits.motor_off) ? 0 : 1;
|
||||
status.Bits.RA_DIRECTION = (mstat3.Bits.mvdir_pol) ? 1 : 0;
|
||||
|
||||
/* Set +/- LS indicator based on limit switch active high/low
|
||||
configuration and the state of the limits switch. */
|
||||
|
||||
LSactiveH = (mstat4.Bits.lmt_high) ? true : false;
|
||||
if (LSactiveH == true)
|
||||
{
|
||||
plusLS = mstat5.Bits.plus_ls;
|
||||
minusLS = mstat5.Bits.minus_ls;
|
||||
}
|
||||
else
|
||||
{
|
||||
plusLS = !mstat5.Bits.plus_ls;
|
||||
minusLS = !mstat5.Bits.minus_ls;
|
||||
}
|
||||
|
||||
|
||||
/* Parse motor position */
|
||||
send_mess(card, "TP", (char*) NULL); /* Tell Position */
|
||||
recv_mess(card, buff, 1);
|
||||
motorData = NINT(atof(&buff[2]));
|
||||
|
||||
if (motorData == motor_info->position)
|
||||
{
|
||||
if (nodeptr != 0) /* Increment counter only if motor is moving. */
|
||||
motor_info->no_motion_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
motor_info->position = motor_info->encoder_position = motorData;
|
||||
motor_info->no_motion_count = 0;
|
||||
}
|
||||
|
||||
plusdir = (status.Bits.RA_DIRECTION) ? true : false;
|
||||
|
||||
/* Set limit switch error indicators. */
|
||||
if (plusLS == true)
|
||||
{
|
||||
status.Bits.RA_PLUS_LS = 1;
|
||||
if (plusdir == true)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_PLUS_LS = 0;
|
||||
|
||||
if (minusLS == true)
|
||||
{
|
||||
status.Bits.RA_MINUS_LS = 1;
|
||||
if (plusdir == false)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_MINUS_LS = 0;
|
||||
|
||||
/* encoder status */
|
||||
status.Bits.EA_SLIP = 0;
|
||||
status.Bits.EA_SLIP_STALL = 0;
|
||||
status.Bits.EA_HOME = 0;
|
||||
|
||||
status.Bits.RA_PROBLEM = 0;
|
||||
|
||||
if (!status.Bits.RA_DIRECTION)
|
||||
motor_info->velocity *= -1;
|
||||
|
||||
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
|
||||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
|
||||
|
||||
/* Test for post-move string. */
|
||||
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 &&
|
||||
nodeptr->postmsgptr != 0)
|
||||
{
|
||||
strcpy(buff, nodeptr->postmsgptr);
|
||||
send_mess(card, buff, (char*) NULL);
|
||||
nodeptr->postmsgptr = NULL;
|
||||
}
|
||||
|
||||
exit:
|
||||
motor_info->status.All = status.All;
|
||||
return(rtn_state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* send a message to the PIC862 board */
|
||||
/* send_mess() */
|
||||
/*****************************************************/
|
||||
static RTN_STATUS send_mess(int card, char const *com, char *name)
|
||||
{
|
||||
char local_buff[MAX_MSG_SIZE];
|
||||
struct PIC862controller *cntrl;
|
||||
int comsize, namesize;
|
||||
size_t nwrite;
|
||||
|
||||
comsize = (com == NULL) ? 0 : strlen(com);
|
||||
namesize = (name == NULL) ? 0 : strlen(name);
|
||||
|
||||
if ((comsize + namesize) > MAX_MSG_SIZE)
|
||||
{
|
||||
errlogMessage("drvPIC862.cc:send_mess(); message size violation.\n");
|
||||
return(ERROR);
|
||||
}
|
||||
else if (comsize == 0) /* Normal exit on empty input message. */
|
||||
return(OK);
|
||||
|
||||
if (!motor_state[card])
|
||||
{
|
||||
errlogPrintf("drvPIC862.cc:send_mess() - invalid card #%d\n", card);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
local_buff[0] = (char) NULL; /* Terminate local buffer. */
|
||||
|
||||
/* this device deos not have axis info and so name is ignored! */
|
||||
|
||||
strcat(local_buff, com); /* Make a local copy of the string. */
|
||||
Debug(2, "send_mess(): message = %s\n", local_buff);
|
||||
|
||||
cntrl = (struct PIC862controller *) motor_state[card]->DevicePrivate;
|
||||
pasynOctetSyncIO->write(cntrl->pasynUser, local_buff, strlen(local_buff),
|
||||
COMM_TIMEOUT, &nwrite);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* receive a message from the PIC862 board */
|
||||
/* recv_mess() */
|
||||
/*****************************************************/
|
||||
static int recv_mess(int card, char *com, int flag)
|
||||
{
|
||||
struct PIC862controller *cntrl;
|
||||
size_t nread = 0;
|
||||
asynStatus status = asynError;
|
||||
int eomReason;
|
||||
|
||||
/* Check that card exists */
|
||||
if (!motor_state[card])
|
||||
return(ERROR);
|
||||
|
||||
cntrl = (struct PIC862controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
if (flag == FLUSH)
|
||||
pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
else
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
|
||||
COMM_TIMEOUT, &nread, &eomReason);
|
||||
|
||||
if ((status != asynSuccess) || (nread <= 0))
|
||||
{
|
||||
com[0] = '\0';
|
||||
nread = 0;
|
||||
}
|
||||
else
|
||||
com[nread - 1] = '\0'; /* Strip traling CR. */
|
||||
|
||||
Debug(2, "recv_mess(): message = \"%s\"\n", com);
|
||||
return(nread);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Setup system configuration */
|
||||
/* PIC862Setup() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIC862Setup(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 > PIC862_NUM_CARDS)
|
||||
PIC862_num_cards = PIC862_NUM_CARDS;
|
||||
else
|
||||
PIC862_num_cards = num_cards;
|
||||
|
||||
/* Set motor polling task rate */
|
||||
if (scan_rate >= 1 && scan_rate <= 60)
|
||||
targs.motor_scan_rate = scan_rate;
|
||||
else
|
||||
targs.motor_scan_rate = SCAN_RATE;
|
||||
|
||||
/*
|
||||
* Allocate space for motor_state structures. Note this must be done
|
||||
* before PIC862Config 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(PIC862_num_cards *
|
||||
sizeof(struct controller *));
|
||||
|
||||
for (itera = 0; itera < PIC862_num_cards; itera++)
|
||||
motor_state[itera] = (struct controller *) NULL;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Configure a controller */
|
||||
/* PIC862Config() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIC862Config(int card, /* card being configured */
|
||||
const char *name, /* asyn port name */
|
||||
int addr) /* asyn address ( device address for daisy chaining */
|
||||
{
|
||||
struct PIC862controller *cntrl;
|
||||
|
||||
if (card < 0 || card >= PIC862_num_cards)
|
||||
return(ERROR);
|
||||
|
||||
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
||||
motor_state[card]->DevicePrivate = malloc(sizeof(struct PIC862controller));
|
||||
cntrl = (struct PIC862controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
strcpy(cntrl->asyn_port, name);
|
||||
cntrl->asyn_address = addr;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* initialize all software and hardware */
|
||||
/* This is called from the initialization routine in */
|
||||
/* device support. */
|
||||
/* motor_init() */
|
||||
/*****************************************************/
|
||||
static int motor_init()
|
||||
{
|
||||
struct controller *brdptr;
|
||||
struct PIC862controller *cntrl;
|
||||
int card_index, motor_index;
|
||||
char buff[BUFF_SIZE];
|
||||
int status;
|
||||
asynStatus success_rtn;
|
||||
static const char output_terminator[] = "\r";
|
||||
static const char input_terminator[] = "\n\03";
|
||||
|
||||
initialized = true; /* Indicate that driver is initialized. */
|
||||
|
||||
/* Check for setup */
|
||||
if (PIC862_num_cards <= 0)
|
||||
return(ERROR);
|
||||
|
||||
for (card_index = 0; card_index < PIC862_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 PIC862controller *) brdptr->DevicePrivate;
|
||||
|
||||
/* Initialize communications channel */
|
||||
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));
|
||||
|
||||
/* 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);
|
||||
|
||||
/* To start communicating with the device requires to enable the device
|
||||
To do this send "0x01" and a singel letter address (0-F)
|
||||
To make sure we talk ask the status with "TB" command for the address
|
||||
It replies "B:000x" where x is 0-F
|
||||
The command "VE" provides a complete Identification string if we need.
|
||||
*/
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
sprintf(buff,"\001%1XVE", cntrl->asyn_address);
|
||||
send_mess(card_index, buff, (char*) NULL);
|
||||
status = recv_mess(card_index, buff, 1);
|
||||
retry++;
|
||||
} while (status == 0 && retry < 3);
|
||||
}
|
||||
|
||||
if (success_rtn == asynSuccess && status > 0)
|
||||
{
|
||||
strcpy(brdptr->ident, &buff[0]);
|
||||
brdptr->localaddr = (char *) NULL;
|
||||
brdptr->motor_in_motion = 0;
|
||||
|
||||
/* number of axes is always one.*/
|
||||
brdptr->total_axis = 1;
|
||||
motor_index = 0;
|
||||
|
||||
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;
|
||||
/* PIC862 has DC motor support only */
|
||||
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;
|
||||
|
||||
mess_queue.head = (struct mess_node *) NULL;
|
||||
mess_queue.tail = (struct mess_node *) NULL;
|
||||
|
||||
free_list.head = (struct mess_node *) NULL;
|
||||
free_list.tail = (struct mess_node *) NULL;
|
||||
|
||||
epicsThreadCreate((char *) "PIC862_motor", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
/* File: drvPIC862.h */
|
||||
|
||||
|
||||
/* Device Driver Support definitions for motor */
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Current Author: Mohan Ramanathan
|
||||
* Date: 09/04/2006
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 09/05/2006 mr copied from drvPIC848.h
|
||||
* .01 09/25/2006 rls COMM_TIMEOUT must be a float.
|
||||
* .02 09/26/2006 rsl bit fields must be padded out to 16 bit words for
|
||||
* WRS compiler.
|
||||
*/
|
||||
|
||||
#ifndef INCdrvPIC862h
|
||||
#define INCdrvPIC862h 1
|
||||
|
||||
#include "motordrvCom.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
|
||||
#define COMM_TIMEOUT 2.0 /* Timeout in seconds. */
|
||||
|
||||
struct PIC862controller
|
||||
{
|
||||
asynUser *pasynUser; /* asynUser structure */
|
||||
int asyn_address; /* Use for GPIB or other address with asyn */
|
||||
CommStatus status; /* Controller communication status. */
|
||||
char asyn_port[80]; /* asyn port name */
|
||||
};
|
||||
|
||||
|
||||
/* LM629 Status bits */
|
||||
typedef union
|
||||
{
|
||||
epicsUInt16 All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
unsigned int na8 :8; /* NA8. */
|
||||
unsigned int motor_off :1; /* 7 - Motor loop OFF. */
|
||||
unsigned int breakpt :1; /* 6 - Breakpoint reached flag. */
|
||||
unsigned int max_pos_err :1; /* 5 - Maximum position error is exceeded. */
|
||||
unsigned int max_pos_lmt :1; /* 4 - Maximum position Limit exceeded. */
|
||||
unsigned int index :1; /* 3 - Index pulse received flag. */
|
||||
unsigned int trty_done :1; /* 2 - Trajectory Complete. */
|
||||
unsigned int cmnd_err :1; /* 1 - Command error flag. */
|
||||
unsigned int busy :1; /* 0 - Busy. */
|
||||
#else
|
||||
unsigned int busy :1; /* 0 - Busy. */
|
||||
unsigned int cmnd_err :1; /* 1 - Command error flag. */
|
||||
unsigned int trty_done :1; /* 2 - Trajectory Complete. */
|
||||
unsigned int index :1; /* 3 - Index pulse received flag. */
|
||||
unsigned int max_pos_lmt :1; /* 4 - Maximum position Limit exceeded. */
|
||||
unsigned int max_pos_err :1; /* 5 - Maximum position error is exceeded. */
|
||||
unsigned int breakpt :1; /* 6 - Breakpoint reached flag. */
|
||||
unsigned int motor_off :1; /* 7 - Motor loop OFF. */
|
||||
unsigned int na8 :8; /* NA8. */
|
||||
#endif
|
||||
} Bits;
|
||||
} C862_Status_Reg1;
|
||||
|
||||
/* Internal operation flags */
|
||||
typedef union
|
||||
{
|
||||
epicsUInt16 All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
unsigned int na8 :8; /* NA8. */
|
||||
unsigned int brd_addr :1; /* 7 - Board Addressed. */
|
||||
unsigned int num_mode :1; /* 6 - Number mode in Effect. */
|
||||
unsigned int ldzero_dis :1; /* 3 - Leading Zero Suppression disabled. */
|
||||
unsigned int macro_act :1; /* 4 - Macro Command called. */
|
||||
unsigned int ldzero_act :1; /* 3 - Leading Zero Suppression active. */
|
||||
unsigned int cmnd_err :1; /* 2 - Command error flag. */
|
||||
unsigned int wait_prgs :1; /* 1 - Wait in Progress. */
|
||||
unsigned int echo_on :1; /* 0 - Echo ON. */
|
||||
#else
|
||||
unsigned int echo_on :1; /* 0 - Echo ON. */
|
||||
unsigned int wait_prgs :1; /* 1 - Wait in Progress. */
|
||||
unsigned int cmnd_err :1; /* 2 - Command error flag. */
|
||||
unsigned int ldzero_act :1; /* 3 - Leading Zero Suppression active. */
|
||||
unsigned int macro_act :1; /* 4 - Macro Command called. */
|
||||
unsigned int ldzero_dis :1; /* 3 - Leading Zero Suppression disabled. */
|
||||
unsigned int num_mode :1; /* 6 - Number mode in Effect. */
|
||||
unsigned int brd_addr :1; /* 7 - Board Addressed. */
|
||||
unsigned int na8 :8; /* NA8. */
|
||||
#endif
|
||||
} Bits;
|
||||
} C862_Status_Reg2;
|
||||
|
||||
/* Motor loop flags */
|
||||
typedef union
|
||||
{
|
||||
epicsUInt16 All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
unsigned int na8 :8; /* NA8. */
|
||||
unsigned int int_comm :1; /* 7 - Command error flag. */
|
||||
unsigned int move_err_ex :1; /* 6 - Move Error Excess flag. */
|
||||
unsigned int na34 :2;
|
||||
unsigned int move_err :1; /* 3 - Move Error */
|
||||
unsigned int mvdir_pol :1; /* 2 - Move driection polarity. */
|
||||
unsigned int na30 :2;
|
||||
#else
|
||||
unsigned int na30 :2;
|
||||
unsigned int mvdir_pol :1; /* 2 - Move driection polarity. */
|
||||
unsigned int move_err :1; /* 3 - Move Error */
|
||||
unsigned int na34 :2;
|
||||
unsigned int move_err_ex :1; /* 6 - Move Error Excess flag. */
|
||||
unsigned int int_comm :1; /* 7 - Command error flag. */
|
||||
unsigned int na8 :8; /* NA8. */
|
||||
#endif
|
||||
} Bits;
|
||||
} C862_Status_Reg3;
|
||||
|
||||
/* Signal lines status */
|
||||
typedef union
|
||||
{
|
||||
epicsUInt16 All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
unsigned int na44 :12;
|
||||
unsigned int brake_on :1; /* 3 - Brake ON. */
|
||||
unsigned int find_prgs :1; /* 2 - Find Edge Operation in Progress. */
|
||||
unsigned int lmt_high :1; /* 1 - Limit Switch Active Stet HIGH */
|
||||
unsigned int lmt_on :1; /* 0 - Limit Swicth ON flag. */
|
||||
#else
|
||||
unsigned int lmt_on :1; /* 0 - Limit Swicth ON flag. */
|
||||
unsigned int lmt_high :1; /* 1 - Limit Switch Active Stet HIGH */
|
||||
unsigned int find_prgs :1; /* 2 - Find Edge Operation in Progress. */
|
||||
unsigned int brake_on :1; /* 3 - Brake ON. */
|
||||
unsigned int na44 :12;
|
||||
#endif
|
||||
} Bits;
|
||||
} C862_Status_Reg4;
|
||||
|
||||
/* Signal lines inputs */
|
||||
typedef union
|
||||
{
|
||||
epicsUInt16 All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
unsigned int na54 :12;
|
||||
unsigned int minus_ls :1; /* 3 - Negative limit signal flag. */
|
||||
unsigned int plus_ls :1; /* 2 - Positive limit signal flag. */
|
||||
unsigned int index :1; /* 1 - Reference signal flag */
|
||||
unsigned int na50 :1;
|
||||
#else
|
||||
unsigned int na50 :1;
|
||||
unsigned int index :1; /* 1 - Reference signal flag */
|
||||
unsigned int plus_ls :1; /* 2 - Positive limit signal flag. */
|
||||
unsigned int minus_ls :1; /* 3 - Negative limit signal flag. */
|
||||
unsigned int na54 :12;
|
||||
#endif
|
||||
} Bits;
|
||||
} C862_Status_Reg5;
|
||||
|
||||
|
||||
/* Function prototypes. */
|
||||
extern RTN_STATUS PIC862Setup(int, int);
|
||||
extern RTN_STATUS PIC862Config(int, const char *, int);
|
||||
|
||||
#endif /* INCdrvPIC862h */
|
||||
@@ -1,669 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvPIE516.cc
|
||||
USAGE... Motor record driver level support for Physik Instrumente (PI)
|
||||
GmbH & Co. E-516 motor controller.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 10/18/05
|
||||
* Current Author: Joe Sullivan
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 03/26/07 jps - copied from drvPIC710.cc tested on PI VER "DSP V3.11,MCU V5"
|
||||
*/
|
||||
|
||||
/*
|
||||
DESIGN LIMITATIONS...
|
||||
1 - Like all controllers, the PIE516 must be powered-on when EPICS is first
|
||||
booted up.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <epicsThread.h>
|
||||
#include <drvSup.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "drvPIE516.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define GET_IDENT "VER?"
|
||||
#define SET_ONLINE "ONL 1" /* Set Online Mode ON */
|
||||
#define SET_VELCTRL "VCO A1 B1 C1" /* Set Velocity Control Mode - Required for DONE */
|
||||
#define READ_ONLINE "ONL?" /* Read Online Mode */
|
||||
#define READ_POS "POS? #" /* Read position */
|
||||
#define READ_OVERFLOW "OVF? #" /* Read Servo Overflow Status */
|
||||
#define READ_ONTARGET "ONT? #" /* Read Position ON Target */
|
||||
#define READ_SERVO "SVO? #" /* Read Servo Enable Status */
|
||||
|
||||
|
||||
#define PIE516_NUM_CARDS 10
|
||||
#define MAX_AXES 3
|
||||
#define BUFF_SIZE 100 /* Maximum length of string to/from PIE516 */
|
||||
|
||||
/*----------------debugging-----------------*/
|
||||
volatile int drvPIE516debug = 0;
|
||||
extern "C" {epicsExportAddress(int, drvPIE516debug);}
|
||||
static inline void Debug(int level, const char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
if (level < drvPIE516debug) {
|
||||
va_list pVar;
|
||||
va_start(pVar, format);
|
||||
vprintf(format, pVar);
|
||||
va_end(pVar);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- Local data. --- */
|
||||
int PIE516_num_cards = 0;
|
||||
static char *PIE516_axis[] = {"A", "B", "C"};
|
||||
|
||||
/* Local data required for every driver; see "motordrvComCode.h" */
|
||||
#include "motordrvComCode.h"
|
||||
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
static int recv_mess(int, char *, int);
|
||||
static RTN_STATUS send_mess(int, char const *, char *);
|
||||
static int set_status(int, int);
|
||||
static long report(int);
|
||||
static long init();
|
||||
static int motor_init();
|
||||
static void query_done(int, int, struct mess_node *);
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
|
||||
struct driver_table PIE516_access =
|
||||
{
|
||||
motor_init,
|
||||
motor_send,
|
||||
motor_free,
|
||||
motor_card_info,
|
||||
motor_axis_info,
|
||||
&mess_queue,
|
||||
&queue_lock,
|
||||
&free_list,
|
||||
&freelist_lock,
|
||||
&motor_sem,
|
||||
&motor_state,
|
||||
&total_cards,
|
||||
&any_motor_in_motion,
|
||||
send_mess,
|
||||
recv_mess,
|
||||
set_status,
|
||||
query_done,
|
||||
NULL,
|
||||
&initialized,
|
||||
PIE516_axis
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
long number;
|
||||
long (*report) (int);
|
||||
long (*init) (void);
|
||||
} drvPIE516 = {2, report, init};
|
||||
|
||||
extern "C" {epicsExportAddress(drvet, drvPIE516);}
|
||||
|
||||
static struct thread_args targs = {SCAN_RATE, &PIE516_access, 0.0};
|
||||
|
||||
/*********************************************************
|
||||
* Print out driver status report
|
||||
*********************************************************/
|
||||
static long report(int level)
|
||||
{
|
||||
int card;
|
||||
|
||||
if (PIE516_num_cards <=0)
|
||||
printf(" No PIE516 controllers configured.\n");
|
||||
else
|
||||
{
|
||||
for (card = 0; card < PIE516_num_cards; card++)
|
||||
{
|
||||
struct controller *brdptr = motor_state[card];
|
||||
|
||||
if (brdptr == NULL)
|
||||
printf(" PIE516 controller %d connection failed.\n", card);
|
||||
else
|
||||
{
|
||||
struct PIE516controller *cntrl;
|
||||
|
||||
cntrl = (struct PIE516controller *) brdptr->DevicePrivate;
|
||||
printf(" PIE516 controller #%d, port=%s, id: %s \n", card,
|
||||
cntrl->asyn_port, brdptr->ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
static long init()
|
||||
{
|
||||
/*
|
||||
* We cannot call motor_init() here, because that function can do GPIB I/O,
|
||||
* and hence requires that the drvGPIB have already been initialized.
|
||||
* That cannot be guaranteed, so we need to call motor_init from device
|
||||
* support
|
||||
*/
|
||||
/* Check for setup */
|
||||
if (PIE516_num_cards <= 0)
|
||||
{
|
||||
Debug(1, "init(): PIE516 driver disabled. PIE516Setup() missing from startup script.\n");
|
||||
}
|
||||
return((long) 0);
|
||||
}
|
||||
|
||||
|
||||
static void query_done(int card, int axis, struct mess_node *nodeptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* FUNCTION NAME: set_status *
|
||||
* *
|
||||
* LOGIC: *
|
||||
* Initialize. *
|
||||
* Send "Moving Status" query. *
|
||||
* Read response. *
|
||||
* IF normal response to query. *
|
||||
* Set communication status to NORMAL. *
|
||||
* ELSE *
|
||||
* IF communication status is NORMAL. *
|
||||
* Set communication status to RETRY. *
|
||||
* NORMAL EXIT. *
|
||||
* ELSE *
|
||||
* Set communication status error. *
|
||||
* ERROR EXIT. *
|
||||
* ENDIF *
|
||||
* ENDIF *
|
||||
* *
|
||||
* IF "Moving Status" indicates any motion (i.e. status != 0). *
|
||||
* Clear "Done Moving" status bit. *
|
||||
* ELSE *
|
||||
* Set "Done Moving" status bit. *
|
||||
* ENDIF *
|
||||
* *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
static int set_status(int card, int signal)
|
||||
{
|
||||
struct PIE516controller *cntrl;
|
||||
struct mess_node *nodeptr;
|
||||
struct mess_info *motor_info;
|
||||
struct motorRecord *mr;
|
||||
/* Message parsing variables */
|
||||
char buff[BUFF_SIZE];
|
||||
int rtn_state;
|
||||
unsigned int overflow_status, ontarget_status, servo_status, online_status;
|
||||
epicsInt32 motorData;
|
||||
bool plusdir, ls_active, plusLS, minusLS;
|
||||
bool readOK;
|
||||
msta_field status;
|
||||
|
||||
cntrl = (struct PIE516controller *) motor_state[card]->DevicePrivate;
|
||||
motor_info = &(motor_state[card]->motor_info[signal]);
|
||||
nodeptr = motor_info->motor_motion;
|
||||
if (nodeptr != NULL)
|
||||
mr = (struct motorRecord *) nodeptr->mrecord;
|
||||
else
|
||||
mr = NULL;
|
||||
status.All = motor_info->status.All;
|
||||
|
||||
recv_mess(card, buff, FLUSH);
|
||||
|
||||
readOK = false;
|
||||
send_mess(card, READ_ONLINE, (char*) NULL);
|
||||
if (recv_mess(card, buff, 1) && sscanf(buff, "%d", &online_status))
|
||||
{
|
||||
if (!online_status)
|
||||
{
|
||||
/* Assume Controller Reboot - Set ONLINE and Velocity Control ON */
|
||||
send_mess(card, SET_ONLINE, (char*) NULL);
|
||||
send_mess(card, SET_VELCTRL, (char*) NULL);
|
||||
}
|
||||
|
||||
send_mess(card, READ_ONTARGET, PIE516_axis[signal]);
|
||||
if (recv_mess(card, buff, 1) && sscanf(buff, "%d", &ontarget_status))
|
||||
{
|
||||
send_mess(card, READ_OVERFLOW, PIE516_axis[signal]);
|
||||
if (recv_mess(card, buff, 1) && sscanf(buff, "%d", &overflow_status))
|
||||
{
|
||||
send_mess(card, READ_SERVO, PIE516_axis[signal]);
|
||||
if (recv_mess(card, buff, 1) && sscanf(buff, "%d", &servo_status))
|
||||
{
|
||||
send_mess(card, READ_POS, PIE516_axis[signal]);
|
||||
if (recv_mess(card, buff, 1))
|
||||
{
|
||||
motorData = NINT(atof(buff) / cntrl->drive_resolution[signal]);
|
||||
readOK = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (readOK)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Always DONE if torque disabled */
|
||||
status.Bits.RA_DONE = (ontarget_status) ? 1 : 0;
|
||||
status.Bits.RA_HOME = status.Bits.RA_DONE;
|
||||
|
||||
status.Bits.EA_POSITION = (servo_status) ? 1 : 0; /* Torgue disabled flag */
|
||||
|
||||
ls_active = plusLS = minusLS = false;
|
||||
|
||||
/* LS status may be true but servo is not within position error - keep updating */
|
||||
/* No Limit switches but if the Servo Controller overflows indicate with a + LS */
|
||||
if (status.Bits.RA_DONE)
|
||||
plusLS = overflow_status ? true : false;
|
||||
|
||||
if (motorData == motor_info->position)
|
||||
{
|
||||
if (nodeptr != 0) /* Increment counter only if motor is moving. */
|
||||
motor_info->no_motion_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
status.Bits.RA_DIRECTION = (motorData >= motor_info->position) ? 1 : 0;
|
||||
motor_info->position = motor_info->encoder_position = motorData;
|
||||
motor_info->no_motion_count = 0;
|
||||
}
|
||||
|
||||
plusdir = (status.Bits.RA_DIRECTION) ? true : false;
|
||||
|
||||
/* Set limit switch error indicators. */
|
||||
if (plusLS == true)
|
||||
{
|
||||
status.Bits.RA_PLUS_LS = 1;
|
||||
if (plusdir == true)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_PLUS_LS = 0;
|
||||
|
||||
if (minusLS == true)
|
||||
{
|
||||
status.Bits.RA_MINUS_LS = 1;
|
||||
if (plusdir == false)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_MINUS_LS = 0;
|
||||
|
||||
/* encoder status */
|
||||
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 */
|
||||
|
||||
motor_info->velocity = 0;
|
||||
|
||||
if (!status.Bits.RA_DIRECTION)
|
||||
motor_info->velocity *= -1;
|
||||
|
||||
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
|
||||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
|
||||
|
||||
/* Test for post-move string. */
|
||||
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 &&
|
||||
nodeptr->postmsgptr != 0)
|
||||
{
|
||||
strcpy(buff, nodeptr->postmsgptr);
|
||||
send_mess(card, buff, (char*) NULL);
|
||||
nodeptr->postmsgptr = NULL;
|
||||
}
|
||||
|
||||
exit:
|
||||
motor_info->status.All = status.All;
|
||||
return(rtn_state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* send a message to the PIE516 board */
|
||||
/* send_mess() */
|
||||
/*****************************************************/
|
||||
static RTN_STATUS send_mess(int card, char const *com, char *name)
|
||||
{
|
||||
char local_buff[MAX_MSG_SIZE];
|
||||
char *pbuff;
|
||||
struct PIE516controller *cntrl;
|
||||
int comsize, namesize;
|
||||
size_t nwrite;
|
||||
|
||||
comsize = (com == NULL) ? 0 : strlen(com);
|
||||
namesize = (name == NULL) ? 0 : strlen(name);
|
||||
|
||||
if ((comsize + namesize) > MAX_MSG_SIZE)
|
||||
{
|
||||
errlogMessage("drvPIE516.cc:send_mess(); message size violation.\n");
|
||||
return(ERROR);
|
||||
}
|
||||
else if (comsize == 0) /* Normal exit on empty input message. */
|
||||
return(OK);
|
||||
|
||||
if (!motor_state[card])
|
||||
{
|
||||
errlogPrintf("drvPIE516.cc:send_mess() - invalid card #%d\n", card);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
local_buff[0] = (char) NULL; /* Terminate local buffer. */
|
||||
|
||||
if (name == NULL)
|
||||
strcat(local_buff, com); /* Make a local copy of the string. */
|
||||
else
|
||||
{
|
||||
strcpy(local_buff, com);
|
||||
pbuff = strchr(local_buff, '#');
|
||||
if (pbuff != NULL)
|
||||
*pbuff = *name;
|
||||
else
|
||||
Debug(1, "send_mess(): NAME ERROR: message = %s\n", local_buff);
|
||||
}
|
||||
|
||||
Debug(2, "send_mess(): message = %s\n", local_buff);
|
||||
|
||||
cntrl = (struct PIE516controller *) motor_state[card]->DevicePrivate;
|
||||
pasynOctetSyncIO->write(cntrl->pasynUser, local_buff, strlen(local_buff),
|
||||
COMM_TIMEOUT, &nwrite);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* receive a message from the PIE516 board */
|
||||
/* recv_mess() */
|
||||
/*****************************************************/
|
||||
static int recv_mess(int card, char *com, int flag)
|
||||
{
|
||||
struct PIE516controller *cntrl;
|
||||
size_t nread = 0;
|
||||
asynStatus status = asynError;
|
||||
int eomReason;
|
||||
|
||||
/* Check that card exists */
|
||||
if (!motor_state[card])
|
||||
return(ERROR);
|
||||
|
||||
cntrl = (struct PIE516controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
if (flag == FLUSH)
|
||||
pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
else
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
|
||||
COMM_TIMEOUT, &nread, &eomReason);
|
||||
|
||||
if ((status != asynSuccess) || (nread <= 0))
|
||||
{
|
||||
com[0] = '\0';
|
||||
nread = 0;
|
||||
}
|
||||
|
||||
Debug(2, "recv_mess(): message = \"%s\"\n", com);
|
||||
return(nread);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Setup system configuration */
|
||||
/* PIE516Setup() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIE516Setup(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 > PIE516_NUM_CARDS)
|
||||
PIE516_num_cards = PIE516_NUM_CARDS;
|
||||
else
|
||||
PIE516_num_cards = num_cards;
|
||||
|
||||
/* Set motor polling task rate */
|
||||
if (scan_rate >= 1 && scan_rate <= 60)
|
||||
targs.motor_scan_rate = scan_rate;
|
||||
else
|
||||
targs.motor_scan_rate = SCAN_RATE;
|
||||
|
||||
/*
|
||||
* Allocate space for motor_state structures. Note this must be done
|
||||
* before PIE516Config 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(PIE516_num_cards *
|
||||
sizeof(struct controller *));
|
||||
|
||||
for (itera = 0; itera < PIE516_num_cards; itera++)
|
||||
motor_state[itera] = (struct controller *) NULL;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Configure a controller */
|
||||
/* PIE516Config() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIE516Config(int card, /* card being configured */
|
||||
const char *name, /* asyn port name */
|
||||
int addr) /* asyn address (GPIB) */
|
||||
{
|
||||
struct PIE516controller *cntrl;
|
||||
|
||||
if (card < 0 || card >= PIE516_num_cards)
|
||||
return(ERROR);
|
||||
|
||||
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
||||
motor_state[card]->DevicePrivate = malloc(sizeof(struct PIE516controller));
|
||||
cntrl = (struct PIE516controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
strcpy(cntrl->asyn_port, name);
|
||||
cntrl->asyn_address = addr;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* initialize all software and hardware */
|
||||
/* This is called from the initialization routine in */
|
||||
/* device support. */
|
||||
/* motor_init() */
|
||||
/*****************************************************/
|
||||
static int motor_init()
|
||||
{
|
||||
struct controller *brdptr;
|
||||
struct PIE516controller *cntrl;
|
||||
int card_index, motor_index;
|
||||
char buff[BUFF_SIZE], *pbuff;
|
||||
int total_axis;
|
||||
int status;
|
||||
int version;
|
||||
bool online;
|
||||
asynStatus success_rtn;
|
||||
static const char output_terminator[] = EOL_E516;
|
||||
static const char input_terminator[] = EOL_E516;
|
||||
|
||||
initialized = true; /* Indicate that driver is initialized. */
|
||||
|
||||
/* Check for setup */
|
||||
if (PIE516_num_cards <= 0)
|
||||
return(ERROR);
|
||||
|
||||
for (card_index = 0; card_index < PIE516_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 PIE516controller *) brdptr->DevicePrivate;
|
||||
|
||||
status = version = 0;
|
||||
|
||||
/* Initialize communications channel */
|
||||
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));
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Assure that Controller is ONLINE */
|
||||
do
|
||||
{
|
||||
online = false;
|
||||
/* Set Controller to ONLINE mode */
|
||||
send_mess(card_index, SET_ONLINE, (char*) NULL);
|
||||
send_mess(card_index, READ_ONLINE, (char*) NULL);
|
||||
if ((status = recv_mess(card_index, buff, 1)))
|
||||
online = (atoi(buff)==1) ? true : false;
|
||||
else
|
||||
retry++;
|
||||
} while (online == false && retry < 3);
|
||||
|
||||
send_mess(card_index, GET_IDENT, (char*) NULL);
|
||||
status = recv_mess(card_index, buff, 1);
|
||||
|
||||
/* Parse out E516 revision (2 decimal places) and convert to int */
|
||||
if ((pbuff = strchr(buff, 'V')))
|
||||
version = NINT(atof(pbuff+1) * 100);
|
||||
else
|
||||
version = 0;
|
||||
}
|
||||
|
||||
if (success_rtn == asynSuccess && online == true)
|
||||
{
|
||||
strcpy(brdptr->ident, buff);
|
||||
brdptr->localaddr = (char *) NULL;
|
||||
brdptr->motor_in_motion = 0;
|
||||
|
||||
/* Check for E516 versions that need the status word shifted up 8 bits */
|
||||
if (version >= 311)
|
||||
cntrl->versionSupport = true;
|
||||
else
|
||||
cntrl->versionSupport = false;
|
||||
|
||||
/* Determine # of axes. Request stage name. See if it responds */
|
||||
for (total_axis = 0; total_axis < MAX_AXES; total_axis++)
|
||||
{
|
||||
send_mess(card_index, READ_POS, PIE516_axis[total_axis]);
|
||||
status = recv_mess(card_index, buff, 1);
|
||||
if (!status)
|
||||
break;
|
||||
}
|
||||
brdptr->total_axis = total_axis;
|
||||
|
||||
/* Turn ON velocity control mode - All axis */
|
||||
send_mess(card_index, SET_VELCTRL, (char*) NULL);
|
||||
|
||||
for (motor_index = 0; motor_index < total_axis; motor_index++)
|
||||
{
|
||||
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
|
||||
|
||||
motor_info->status.All = 0;
|
||||
motor_info->no_motion_count = 0;
|
||||
motor_info->encoder_position = 0;
|
||||
motor_info->position = 0;
|
||||
brdptr->motor_info[motor_index].motor_motion = NULL;
|
||||
/* PIE516 has DC motor support only */
|
||||
motor_info->encoder_present = YES;
|
||||
motor_info->status.Bits.EA_PRESENT = 1;
|
||||
motor_info->pid_present = NO;
|
||||
motor_info->status.Bits.GAIN_SUPPORT = 1;
|
||||
|
||||
cntrl->drive_resolution[motor_index] = POS_RES;
|
||||
|
||||
set_status(card_index, motor_index); /* Read status of each motor */
|
||||
}
|
||||
}
|
||||
else
|
||||
motor_state[card_index] = (struct controller *) NULL;
|
||||
}
|
||||
|
||||
any_motor_in_motion = 0;
|
||||
|
||||
mess_queue.head = (struct mess_node *) NULL;
|
||||
mess_queue.tail = (struct mess_node *) NULL;
|
||||
|
||||
free_list.head = (struct mess_node *) NULL;
|
||||
free_list.tail = (struct mess_node *) NULL;
|
||||
|
||||
epicsThreadCreate((char *) "PIE516_motor", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/* File: drvPIE516.h */
|
||||
|
||||
|
||||
/* Device Driver Support definitions for motor */
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Current Author: Joe Sullivan
|
||||
* Date: 09/20/2005
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 09/13/2006 jps copied from drvPIC838.h
|
||||
*/
|
||||
|
||||
#ifndef INCdrvPIE516h
|
||||
#define INCdrvPIE516h 1
|
||||
|
||||
#include "motordrvCom.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
|
||||
#define COMM_TIMEOUT 2 /* Timeout in seconds. */
|
||||
#define POS_RES 0.001 /* Position resolution. */
|
||||
|
||||
#define EOL_E516 "\n" /* Command End-Of-Line = LF (0x10) */
|
||||
|
||||
struct PIE516controller
|
||||
{
|
||||
asynUser *pasynUser; /* asynUser structure */
|
||||
int asyn_address; /* Use for GPIB or other address with asyn */
|
||||
CommStatus status; /* Controller communication status. */
|
||||
double drive_resolution[4];
|
||||
bool versionSupport; /* Track supported Versions - include in Report */
|
||||
char asyn_port[80]; /* asyn port name */
|
||||
};
|
||||
|
||||
|
||||
typedef union
|
||||
{
|
||||
epicsUInt16 All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
unsigned int cmnd_err :1; /* 15 - Command Error */
|
||||
unsigned int na6 :1; /* 14 - */
|
||||
unsigned int autozero :1; /* 13 - AutoZero function is running */
|
||||
unsigned int plus_ls :1; /* 12 - Positive limit switch flag. */
|
||||
unsigned int minus_ls :1; /* 11 - Negative limit switch flag. */
|
||||
unsigned int moving :1; /* 10 - Moving indicator - position error outside tolerance */
|
||||
unsigned int volt_limit :1; /* 9 - piezo voltage limit reached */
|
||||
unsigned int torque :1; /* 8 - Servo-control status */
|
||||
unsigned int nabyte :8;
|
||||
|
||||
#else
|
||||
unsigned int nabyte :8;
|
||||
unsigned int torque :1; /* 8 - Servo-control status */
|
||||
unsigned int volt_limit :1; /* 9 - piezo voltage limit reached */
|
||||
unsigned int moving :1; /* 10 - Moving indicator - position error outside tolerance */
|
||||
unsigned int minus_ls :1; /* 11 - Negative limit switch flag. */
|
||||
unsigned int plus_ls :1; /* 12 - Positive limit switch flag. */
|
||||
unsigned int autozero :1; /* 13 - AutoZero function is running */
|
||||
unsigned int na6 :1; /* 14 - */
|
||||
unsigned int cmnd_err :1; /* 15 - Command Error */
|
||||
#endif
|
||||
} Bits;
|
||||
} E516_Status_Reg;
|
||||
|
||||
|
||||
/* Function prototypes. */
|
||||
extern RTN_STATUS PIE516Setup(int, int);
|
||||
extern RTN_STATUS PIE516Config(int, const char *, int);
|
||||
|
||||
#endif /* INCdrvPIE516h */
|
||||
@@ -1,682 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvPIE517.cc
|
||||
USAGE... Motor record driver level support for Physik Instrumente (PI)
|
||||
GmbH & Co. E-516 motor controller.
|
||||
|
||||
Version: $Revision: 1.1 $
|
||||
Modified By: $Author: sullivan $
|
||||
Last Modified: $Date: 2007-03-30 20:01:05 $
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 10/18/05
|
||||
* Current Author: Joe Sullivan
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 08/10/16 Bruno Luvizotto (brunoluvizotto@gmail.com) - copied from devPIE516.cc.
|
||||
* .02 08/10/16 Bruno Luvizotto (brunoluvizotto@gmail.com) - edited the files for the E517 controller.
|
||||
* Tested on PI VER:
|
||||
* FW_DSP: 02.034
|
||||
* FW_FPGA: 02.040
|
||||
* FW_MCU: 1.22.6
|
||||
*/
|
||||
|
||||
/*
|
||||
DESIGN LIMITATIONS...
|
||||
1 - Like all controllers, the PIE517 must be powered-on when EPICS is first
|
||||
booted up.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <epicsThread.h>
|
||||
#include <drvSup.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "drvPIE517.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define GET_IDENT "VER?"
|
||||
#define SET_ONLINE "ONL # 1" /* Set Online Mode ON */
|
||||
#define SET_VELCTRL "VCO # 1" /* Set Velocity Control Mode - Required for DONE */
|
||||
#define READ_ONLINE "ONL? #" /* Read Online Mode */
|
||||
#define READ_POS "POS? #" /* Read position */
|
||||
#define READ_OVERFLOW "OVF? #" /* Read Servo Overflow Status */
|
||||
#define READ_ONTARGET "ONT? #" /* Read Position ON Target */
|
||||
#define READ_SERVO "SVO? #" /* Read Servo Enable Status */
|
||||
|
||||
|
||||
#define PIE517_NUM_CARDS 10
|
||||
#define MAX_AXES 3
|
||||
#define BUFF_SIZE 100 /* Maximum length of string to/from PIE517 */
|
||||
|
||||
/*----------------debugging-----------------*/
|
||||
volatile int drvPIE517debug = 0;
|
||||
extern "C" {epicsExportAddress(int, drvPIE517debug);}
|
||||
static inline void Debug(int level, const char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
if (level < drvPIE517debug) {
|
||||
va_list pVar;
|
||||
va_start(pVar, format);
|
||||
vprintf(format, pVar);
|
||||
va_end(pVar);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- Local data. --- */
|
||||
int PIE517_num_cards = 0;
|
||||
static char *PIE517_axis[] = {"1 ", "2 ", "3 "}; //{"A", "B", "C"};
|
||||
|
||||
/* Local data required for every driver; see "motordrvComCode.h" */
|
||||
#include "motordrvComCode.h"
|
||||
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
static int recv_mess(int, char *, int);
|
||||
static RTN_STATUS send_mess(int, char const *, char *);
|
||||
static int set_status(int, int);
|
||||
static long report(int);
|
||||
static long init();
|
||||
static int motor_init();
|
||||
static void query_done(int, int, struct mess_node *);
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
|
||||
struct driver_table PIE517_access =
|
||||
{
|
||||
motor_init,
|
||||
motor_send,
|
||||
motor_free,
|
||||
motor_card_info,
|
||||
motor_axis_info,
|
||||
&mess_queue,
|
||||
&queue_lock,
|
||||
&free_list,
|
||||
&freelist_lock,
|
||||
&motor_sem,
|
||||
&motor_state,
|
||||
&total_cards,
|
||||
&any_motor_in_motion,
|
||||
send_mess,
|
||||
recv_mess,
|
||||
set_status,
|
||||
query_done,
|
||||
NULL,
|
||||
&initialized,
|
||||
PIE517_axis
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
long number;
|
||||
long (*report) (int);
|
||||
long (*init) (void);
|
||||
} drvPIE517 = {2, report, init};
|
||||
|
||||
extern "C" {epicsExportAddress(drvet, drvPIE517);}
|
||||
|
||||
static struct thread_args targs = {SCAN_RATE, &PIE517_access, 0.0};
|
||||
|
||||
/*********************************************************
|
||||
* Print out driver status report
|
||||
*********************************************************/
|
||||
static long report(int level)
|
||||
{
|
||||
int card;
|
||||
|
||||
if (PIE517_num_cards <=0)
|
||||
printf(" No PIE517 controllers configured.\n");
|
||||
else
|
||||
{
|
||||
for (card = 0; card < PIE517_num_cards; card++)
|
||||
{
|
||||
struct controller *brdptr = motor_state[card];
|
||||
|
||||
if (brdptr == NULL)
|
||||
printf(" PIE517 controller %d connection failed.\n", card);
|
||||
else
|
||||
{
|
||||
struct PIE517controller *cntrl;
|
||||
|
||||
cntrl = (struct PIE517controller *) brdptr->DevicePrivate;
|
||||
printf(" PIE517 controller #%d, port=%s, id: %s \n", card,
|
||||
cntrl->asyn_port, brdptr->ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
static long init()
|
||||
{
|
||||
/*
|
||||
* We cannot call motor_init() here, because that function can do GPIB I/O,
|
||||
* and hence requires that the drvGPIB have already been initialized.
|
||||
* That cannot be guaranteed, so we need to call motor_init from device
|
||||
* support
|
||||
*/
|
||||
/* Check for setup */
|
||||
if (PIE517_num_cards <= 0)
|
||||
{
|
||||
Debug(1, "init(): PIE517 driver disabled. PIE517Setup() missing from startup script.\n");
|
||||
}
|
||||
return((long) 0);
|
||||
}
|
||||
|
||||
|
||||
static void query_done(int card, int axis, struct mess_node *nodeptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* FUNCTION NAME: set_status *
|
||||
* *
|
||||
* LOGIC: *
|
||||
* Initialize. *
|
||||
* Send "Moving Status" query. *
|
||||
* Read response. *
|
||||
* IF normal response to query. *
|
||||
* Set communication status to NORMAL. *
|
||||
* ELSE *
|
||||
* IF communication status is NORMAL. *
|
||||
* Set communication status to RETRY. *
|
||||
* NORMAL EXIT. *
|
||||
* ELSE *
|
||||
* Set communication status error. *
|
||||
* ERROR EXIT. *
|
||||
* ENDIF *
|
||||
* ENDIF *
|
||||
* *
|
||||
* IF "Moving Status" indicates any motion (i.e. status != 0). *
|
||||
* Clear "Done Moving" status bit. *
|
||||
* ELSE *
|
||||
* Set "Done Moving" status bit. *
|
||||
* ENDIF *
|
||||
* *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
static int set_status(int card, int signal)
|
||||
{
|
||||
struct PIE517controller *cntrl;
|
||||
struct mess_node *nodeptr;
|
||||
struct mess_info *motor_info;
|
||||
struct motorRecord *mr;
|
||||
/* Message parsing variables */
|
||||
char buff[BUFF_SIZE];
|
||||
int rtn_state;
|
||||
unsigned int overflow_status, ontarget_status, servo_status, online_status;
|
||||
epicsInt32 motorData;
|
||||
bool plusdir, ls_active, plusLS, minusLS;
|
||||
bool readOK;
|
||||
msta_field status;
|
||||
|
||||
cntrl = (struct PIE517controller *) motor_state[card]->DevicePrivate;
|
||||
motor_info = &(motor_state[card]->motor_info[signal]);
|
||||
nodeptr = motor_info->motor_motion;
|
||||
if (nodeptr != NULL)
|
||||
mr = (struct motorRecord *) nodeptr->mrecord;
|
||||
else
|
||||
mr = NULL;
|
||||
status.All = motor_info->status.All;
|
||||
|
||||
recv_mess(card, buff, FLUSH);
|
||||
|
||||
readOK = false;
|
||||
// send_mess(card, READ_ONLINE, PIE517_axis[signal]);
|
||||
// if (recv_mess(card, buff, 1) && sscanf(buff, "%d", &online_status))
|
||||
// {
|
||||
// if (!online_status)
|
||||
// {
|
||||
// /* Assume Controller Reboot - Set ONLINE and Velocity Control ON */
|
||||
// send_mess(card, SET_ONLINE, PIE517_axis[signal]);
|
||||
// //send_mess(card, SET_VELCTRL, (char*) NULL);
|
||||
// }
|
||||
|
||||
send_mess(card, READ_ONTARGET, PIE517_axis[signal]);
|
||||
if (recv_mess(card, buff, 1) && sscanf(buff, "%d", &ontarget_status))
|
||||
{
|
||||
send_mess(card, READ_OVERFLOW, PIE517_axis[signal]);
|
||||
if (recv_mess(card, buff, 1) && sscanf(buff, "%d", &overflow_status))
|
||||
{
|
||||
send_mess(card, READ_SERVO, PIE517_axis[signal]);
|
||||
if (recv_mess(card, buff, 1) && sscanf(buff, "%d", &servo_status))
|
||||
{
|
||||
send_mess(card, READ_POS, PIE517_axis[signal]);
|
||||
if (recv_mess(card, buff, 1))
|
||||
{
|
||||
motorData = NINT(atof(buff) / cntrl->drive_resolution[signal]);
|
||||
readOK = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// }
|
||||
|
||||
if (readOK)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Always DONE if torque disabled */
|
||||
status.Bits.RA_DONE = (ontarget_status) ? 1 : 0;
|
||||
status.Bits.RA_HOME = status.Bits.RA_DONE;
|
||||
|
||||
status.Bits.EA_POSITION = (servo_status) ? 1 : 0; /* Torgue disabled flag */
|
||||
|
||||
ls_active = plusLS = minusLS = false;
|
||||
|
||||
/* LS status may be true but servo is not within position error - keep updating */
|
||||
/* No Limit switches but if the Servo Controller overflows indicate with a + LS */
|
||||
if (status.Bits.RA_DONE)
|
||||
plusLS = overflow_status ? true : false;
|
||||
|
||||
if (motorData == motor_info->position)
|
||||
{
|
||||
if (nodeptr != 0) /* Increment counter only if motor is moving. */
|
||||
motor_info->no_motion_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
status.Bits.RA_DIRECTION = (motorData >= motor_info->position) ? 1 : 0;
|
||||
motor_info->position = motor_info->encoder_position = motorData;
|
||||
motor_info->no_motion_count = 0;
|
||||
}
|
||||
|
||||
plusdir = (status.Bits.RA_DIRECTION) ? true : false;
|
||||
|
||||
/* Set limit switch error indicators. */
|
||||
if (plusLS == true)
|
||||
{
|
||||
status.Bits.RA_PLUS_LS = 1;
|
||||
if (plusdir == true)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_PLUS_LS = 0;
|
||||
|
||||
if (minusLS == true)
|
||||
{
|
||||
status.Bits.RA_MINUS_LS = 1;
|
||||
if (plusdir == false)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_MINUS_LS = 0;
|
||||
|
||||
/* encoder status */
|
||||
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 */
|
||||
|
||||
motor_info->velocity = 0;
|
||||
|
||||
if (!status.Bits.RA_DIRECTION)
|
||||
motor_info->velocity *= -1;
|
||||
|
||||
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
|
||||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
|
||||
|
||||
/* Test for post-move string. */
|
||||
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 &&
|
||||
nodeptr->postmsgptr != 0)
|
||||
{
|
||||
strcpy(buff, nodeptr->postmsgptr);
|
||||
send_mess(card, buff, (char*) NULL);
|
||||
nodeptr->postmsgptr = NULL;
|
||||
}
|
||||
|
||||
exit:
|
||||
motor_info->status.All = status.All;
|
||||
return(rtn_state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* send a message to the PIE517 board */
|
||||
/* send_mess() */
|
||||
/*****************************************************/
|
||||
static RTN_STATUS send_mess(int card, char const *com, char *name)
|
||||
{
|
||||
char local_buff[MAX_MSG_SIZE];
|
||||
char *pbuff;
|
||||
struct PIE517controller *cntrl;
|
||||
int comsize, namesize;
|
||||
size_t nwrite;
|
||||
|
||||
comsize = (com == NULL) ? 0 : strlen(com);
|
||||
namesize = (name == NULL) ? 0 : strlen(name);
|
||||
|
||||
if ((comsize + namesize) > MAX_MSG_SIZE)
|
||||
{
|
||||
errlogMessage("drvPIE517.cc:send_mess(); message size violation.\n");
|
||||
return(ERROR);
|
||||
}
|
||||
else if (comsize == 0) /* Normal exit on empty input message. */
|
||||
return(OK);
|
||||
|
||||
if (!motor_state[card])
|
||||
{
|
||||
errlogPrintf("drvPIE517.cc:send_mess() - invalid card #%d\n", card);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
local_buff[0] = (char) NULL; /* Terminate local buffer. */
|
||||
|
||||
if (name == NULL)
|
||||
strcat(local_buff, com); /* Make a local copy of the string. */
|
||||
else
|
||||
{
|
||||
strcpy(local_buff, com);
|
||||
pbuff = strchr(local_buff, '#');
|
||||
if (pbuff != NULL)
|
||||
*pbuff = *name;
|
||||
else
|
||||
Debug(1, "send_mess(): NAME ERROR: message = %s\n", local_buff);
|
||||
}
|
||||
|
||||
Debug(2, "send_mess(): message = %s\n", local_buff);
|
||||
|
||||
cntrl = (struct PIE517controller *) motor_state[card]->DevicePrivate;
|
||||
pasynOctetSyncIO->write(cntrl->pasynUser, local_buff, strlen(local_buff),
|
||||
COMM_TIMEOUT, &nwrite);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* receive a message from the PIE517 board */
|
||||
/* recv_mess() */
|
||||
/*****************************************************/
|
||||
static int recv_mess(int card, char *com, int flag)
|
||||
{
|
||||
struct PIE517controller *cntrl;
|
||||
size_t nread = 0;
|
||||
asynStatus status = asynError;
|
||||
int eomReason;
|
||||
char *pos;
|
||||
|
||||
/* Check that card exists */
|
||||
if (!motor_state[card])
|
||||
return(ERROR);
|
||||
|
||||
cntrl = (struct PIE517controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
if (flag == FLUSH)
|
||||
pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
else
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
|
||||
COMM_TIMEOUT, &nread, &eomReason);
|
||||
pos=strchr(com,'=');
|
||||
if(pos != NULL)
|
||||
strcpy(com,&pos[1]);
|
||||
|
||||
if ((status != asynSuccess) || (nread <= 0))
|
||||
{
|
||||
com[0] = '\0';
|
||||
nread = 0;
|
||||
}
|
||||
|
||||
Debug(2, "recv_mess(): message = \"%s\"\n", com);
|
||||
return(nread);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Setup system configuration */
|
||||
/* PIE517Setup() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIE517Setup(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 > PIE517_NUM_CARDS)
|
||||
PIE517_num_cards = PIE517_NUM_CARDS;
|
||||
else
|
||||
PIE517_num_cards = num_cards;
|
||||
|
||||
/* Set motor polling task rate */
|
||||
if (scan_rate >= 1 && scan_rate <= 60)
|
||||
targs.motor_scan_rate = scan_rate;
|
||||
else
|
||||
targs.motor_scan_rate = SCAN_RATE;
|
||||
|
||||
/*
|
||||
* Allocate space for motor_state structures. Note this must be done
|
||||
* before PIE517Config 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(PIE517_num_cards *
|
||||
sizeof(struct controller *));
|
||||
|
||||
for (itera = 0; itera < PIE517_num_cards; itera++)
|
||||
motor_state[itera] = (struct controller *) NULL;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Configure a controller */
|
||||
/* PIE517Config() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIE517Config(int card, /* card being configured */
|
||||
const char *name, /* asyn port name */
|
||||
int addr) /* asyn address (GPIB) */
|
||||
{
|
||||
struct PIE517controller *cntrl;
|
||||
|
||||
if (card < 0 || card >= PIE517_num_cards)
|
||||
return(ERROR);
|
||||
|
||||
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
||||
motor_state[card]->DevicePrivate = malloc(sizeof(struct PIE517controller));
|
||||
cntrl = (struct PIE517controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
strcpy(cntrl->asyn_port, name);
|
||||
cntrl->asyn_address = addr;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* initialize all software and hardware */
|
||||
/* This is called from the initialization routine in */
|
||||
/* device support. */
|
||||
/* motor_init() */
|
||||
/*****************************************************/
|
||||
static int motor_init()
|
||||
{
|
||||
struct controller *brdptr;
|
||||
struct PIE517controller *cntrl;
|
||||
int card_index, motor_index;
|
||||
char buff[BUFF_SIZE], *pbuff;
|
||||
int total_axis;
|
||||
int status;
|
||||
int version;
|
||||
bool online;
|
||||
asynStatus success_rtn;
|
||||
static const char output_terminator[] = EOL_E517;
|
||||
static const char input_terminator[] = EOL_E517;
|
||||
|
||||
initialized = true; /* Indicate that driver is initialized. */
|
||||
|
||||
/* Check for setup */
|
||||
if (PIE517_num_cards <= 0)
|
||||
return(ERROR);
|
||||
|
||||
for (card_index = 0; card_index < PIE517_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 PIE517controller *) brdptr->DevicePrivate;
|
||||
|
||||
status = version = 0;
|
||||
|
||||
/* Initialize communications channel */
|
||||
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));
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Assure that Controller is ONLINE */
|
||||
online = true;
|
||||
//do
|
||||
//{
|
||||
// online = false;
|
||||
// /* Set Controller to ONLINE mode */
|
||||
// send_mess(card_index, SET_ONLINE, (char*) NULL);
|
||||
// send_mess(card_index, READ_ONLINE, (char*) NULL);
|
||||
// if ((status = recv_mess(card_index, buff, 1)))
|
||||
//online = (atoi(buff)==1) ? true : false;
|
||||
// else
|
||||
//retry++;
|
||||
//} while (online == false && retry < 3);
|
||||
|
||||
//send_mess(card_index, GET_IDENT, (char*) NULL);
|
||||
//status = recv_mess(card_index, buff, 1);
|
||||
|
||||
/* Parse out E517 revision (2 decimal places) and convert to int */
|
||||
if ((pbuff = strchr(buff, 'V')))
|
||||
version = NINT(atof(pbuff+1) * 100);
|
||||
else
|
||||
version = 0;
|
||||
}
|
||||
|
||||
if (success_rtn == asynSuccess && online == true)
|
||||
{
|
||||
strcpy(brdptr->ident, buff);
|
||||
brdptr->localaddr = (char *) NULL;
|
||||
brdptr->motor_in_motion = 0;
|
||||
|
||||
/* Check for E517 versions that need the status word shifted up 8 bits */
|
||||
/*if (version >= 311)
|
||||
cntrl->versionSupport = true;
|
||||
else
|
||||
cntrl->versionSupport = false;*/
|
||||
|
||||
/* Determine # of axes. Request stage name. See if it responds */
|
||||
for (total_axis = 0; total_axis < MAX_AXES; total_axis++)
|
||||
{
|
||||
send_mess(card_index, READ_POS, PIE517_axis[total_axis]);
|
||||
status = recv_mess(card_index, buff, 1);
|
||||
if (!status)
|
||||
break;
|
||||
}
|
||||
brdptr->total_axis = total_axis;
|
||||
|
||||
/* Turn ON velocity control mode - All axis */
|
||||
//send_mess(card_index, SET_VELCTRL, (char*) NULL);
|
||||
|
||||
for (motor_index = 0; motor_index < total_axis; motor_index++)
|
||||
{
|
||||
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
|
||||
|
||||
motor_info->status.All = 0;
|
||||
motor_info->no_motion_count = 0;
|
||||
motor_info->encoder_position = 0;
|
||||
motor_info->position = 0;
|
||||
brdptr->motor_info[motor_index].motor_motion = NULL;
|
||||
/* PIE517 has DC motor support only */
|
||||
motor_info->encoder_present = YES;
|
||||
motor_info->status.Bits.EA_PRESENT = 1;
|
||||
motor_info->pid_present = NO;
|
||||
motor_info->status.Bits.GAIN_SUPPORT = 1;
|
||||
|
||||
cntrl->drive_resolution[motor_index] = POS_RES;
|
||||
|
||||
set_status(card_index, motor_index); /* Read status of each motor */
|
||||
}
|
||||
}
|
||||
else
|
||||
motor_state[card_index] = (struct controller *) NULL;
|
||||
}
|
||||
|
||||
any_motor_in_motion = 0;
|
||||
|
||||
mess_queue.head = (struct mess_node *) NULL;
|
||||
mess_queue.tail = (struct mess_node *) NULL;
|
||||
|
||||
free_list.head = (struct mess_node *) NULL;
|
||||
free_list.tail = (struct mess_node *) NULL;
|
||||
|
||||
epicsThreadCreate((char *) "PIE517_motor", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/* File: drvPIE516.h */
|
||||
|
||||
|
||||
/* Device Driver Support definitions for motor */
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Current Author: Joe Sullivan
|
||||
* Date: 09/20/2005
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 08/10/16 Bruno Luvizotto (brunoluvizotto@gmail.com) - copied from drvPIE516.h
|
||||
* .02 08/10/16 Bruno Luvizotto (brunoluvizotto@gmail.com) - edited the files for the E517 controller
|
||||
*/
|
||||
|
||||
#ifndef INCdrvPIE517h
|
||||
#define INCdrvPIE517h 1
|
||||
|
||||
#include "motordrvCom.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
|
||||
#define COMM_TIMEOUT 2 /* Timeout in seconds. */
|
||||
#define POS_RES 0.001 /* Position resolution. */
|
||||
|
||||
#define EOL_E517 "\n" /* Command End-Of-Line = LF (0x10) */
|
||||
|
||||
struct PIE517controller
|
||||
{
|
||||
asynUser *pasynUser; /* asynUser structure */
|
||||
int asyn_address; /* Use for GPIB or other address with asyn */
|
||||
CommStatus status; /* Controller communication status. */
|
||||
double drive_resolution[4];
|
||||
bool versionSupport; /* Track supported Versions - include in Report */
|
||||
char asyn_port[80]; /* asyn port name */
|
||||
};
|
||||
|
||||
|
||||
typedef union
|
||||
{
|
||||
epicsUInt16 All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
unsigned int cmnd_err :1; /* 15 - Command Error */
|
||||
unsigned int na6 :1; /* 14 - */
|
||||
unsigned int autozero :1; /* 13 - AutoZero function is running */
|
||||
unsigned int plus_ls :1; /* 12 - Positive limit switch flag. */
|
||||
unsigned int minus_ls :1; /* 11 - Negative limit switch flag. */
|
||||
unsigned int moving :1; /* 10 - Moving indicator - position error outside tolerance */
|
||||
unsigned int volt_limit :1; /* 9 - piezo voltage limit reached */
|
||||
unsigned int torque :1; /* 8 - Servo-control status */
|
||||
unsigned int nabyte :8;
|
||||
|
||||
#else
|
||||
unsigned int nabyte :8;
|
||||
unsigned int torque :1; /* 8 - Servo-control status */
|
||||
unsigned int volt_limit :1; /* 9 - piezo voltage limit reached */
|
||||
unsigned int moving :1; /* 10 - Moving indicator - position error outside tolerance */
|
||||
unsigned int minus_ls :1; /* 11 - Negative limit switch flag. */
|
||||
unsigned int plus_ls :1; /* 12 - Positive limit switch flag. */
|
||||
unsigned int autozero :1; /* 13 - AutoZero function is running */
|
||||
unsigned int na6 :1; /* 14 - */
|
||||
unsigned int cmnd_err :1; /* 15 - Command Error */
|
||||
#endif
|
||||
} Bits;
|
||||
} E517_Status_Reg;
|
||||
|
||||
|
||||
/* Function prototypes. */
|
||||
extern RTN_STATUS PIE517Setup(int, int);
|
||||
extern RTN_STATUS PIE517Config(int, const char *, int);
|
||||
|
||||
#endif /* INCdrvPIE517h */
|
||||
@@ -1,639 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvPIE710.cc
|
||||
USAGE... Motor record driver level support for Physik Instrumente (PI)
|
||||
GmbH & Co. E-710 motor controller.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 10/18/05
|
||||
* Current Author: Joe Sullivan
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 09/13/06 jps - copied from drvPIC848.cc
|
||||
*/
|
||||
|
||||
/*
|
||||
DESIGN LIMITATIONS...
|
||||
1 - Like all controllers, the PIE710 must be powered-on when EPICS is first
|
||||
booted up.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <epicsThread.h>
|
||||
#include <drvSup.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "drvPIE710.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define GET_IDENT "GI"
|
||||
|
||||
#define PIE710_NUM_CARDS 8
|
||||
#define MAX_AXES 6
|
||||
#define BUFF_SIZE 100 /* Maximum length of string to/from PIE710 */
|
||||
|
||||
/*----------------debugging-----------------*/
|
||||
volatile int drvPIE710debug = 0;
|
||||
extern "C" {epicsExportAddress(int, drvPIE710debug);}
|
||||
static inline void Debug(int level, const char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
if (level < drvPIE710debug) {
|
||||
va_list pVar;
|
||||
va_start(pVar, format);
|
||||
vprintf(format, pVar);
|
||||
va_end(pVar);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- Local data. --- */
|
||||
int PIE710_num_cards = 0;
|
||||
static char *PIE710_axis[] = {"1", "2", "3", "4", "5", "6"};
|
||||
|
||||
/* Local data required for every driver; see "motordrvComCode.h" */
|
||||
#include "motordrvComCode.h"
|
||||
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
static int recv_mess(int, char *, int);
|
||||
static RTN_STATUS send_mess(int, char const *, char *);
|
||||
static int set_status(int, int);
|
||||
static long report(int);
|
||||
static long init();
|
||||
static int motor_init();
|
||||
static void query_done(int, int, struct mess_node *);
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
|
||||
struct driver_table PIE710_access =
|
||||
{
|
||||
motor_init,
|
||||
motor_send,
|
||||
motor_free,
|
||||
motor_card_info,
|
||||
motor_axis_info,
|
||||
&mess_queue,
|
||||
&queue_lock,
|
||||
&free_list,
|
||||
&freelist_lock,
|
||||
&motor_sem,
|
||||
&motor_state,
|
||||
&total_cards,
|
||||
&any_motor_in_motion,
|
||||
send_mess,
|
||||
recv_mess,
|
||||
set_status,
|
||||
query_done,
|
||||
NULL,
|
||||
&initialized,
|
||||
PIE710_axis
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
long number;
|
||||
long (*report) (int);
|
||||
long (*init) (void);
|
||||
} drvPIE710 = {2, report, init};
|
||||
|
||||
extern "C" {epicsExportAddress(drvet, drvPIE710);}
|
||||
|
||||
static struct thread_args targs = {SCAN_RATE, &PIE710_access, 0.0};
|
||||
|
||||
/*********************************************************
|
||||
* Print out driver status report
|
||||
*********************************************************/
|
||||
static long report(int level)
|
||||
{
|
||||
int card;
|
||||
|
||||
if (PIE710_num_cards <=0)
|
||||
printf(" No PIE710 controllers configured.\n");
|
||||
else
|
||||
{
|
||||
for (card = 0; card < PIE710_num_cards; card++)
|
||||
{
|
||||
struct controller *brdptr = motor_state[card];
|
||||
|
||||
if (brdptr == NULL)
|
||||
printf(" PIE710 controller %d connection failed.\n", card);
|
||||
else
|
||||
{
|
||||
struct PIE710controller *cntrl;
|
||||
|
||||
cntrl = (struct PIE710controller *) brdptr->DevicePrivate;
|
||||
printf(" PIE710 controller #%d, port=%s, id: %s \n", card,
|
||||
cntrl->asyn_port, brdptr->ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
static long init()
|
||||
{
|
||||
/*
|
||||
* We cannot call motor_init() here, because that function can do GPIB I/O,
|
||||
* and hence requires that the drvGPIB have already been initialized.
|
||||
* That cannot be guaranteed, so we need to call motor_init from device
|
||||
* support
|
||||
*/
|
||||
/* Check for setup */
|
||||
if (PIE710_num_cards <= 0)
|
||||
{
|
||||
Debug(1, "init(): PIE710 driver disabled. PIE710Setup() missing from startup script.\n");
|
||||
}
|
||||
return((long) 0);
|
||||
}
|
||||
|
||||
|
||||
static void query_done(int card, int axis, struct mess_node *nodeptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* FUNCTION NAME: set_status *
|
||||
* *
|
||||
* LOGIC: *
|
||||
* Initialize. *
|
||||
* Send "Moving Status" query. *
|
||||
* Read response. *
|
||||
* IF normal response to query. *
|
||||
* Set communication status to NORMAL. *
|
||||
* ELSE *
|
||||
* IF communication status is NORMAL. *
|
||||
* Set communication status to RETRY. *
|
||||
* NORMAL EXIT. *
|
||||
* ELSE *
|
||||
* Set communication status error. *
|
||||
* ERROR EXIT. *
|
||||
* ENDIF *
|
||||
* ENDIF *
|
||||
* *
|
||||
* IF "Moving Status" indicates any motion (i.e. status != 0). *
|
||||
* Clear "Done Moving" status bit. *
|
||||
* ELSE *
|
||||
* Set "Done Moving" status bit. *
|
||||
* ENDIF *
|
||||
* *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
static int set_status(int card, int signal)
|
||||
{
|
||||
struct PIE710controller *cntrl;
|
||||
struct mess_node *nodeptr;
|
||||
struct mess_info *motor_info;
|
||||
struct motorRecord *mr;
|
||||
/* Message parsing variables */
|
||||
char buff[BUFF_SIZE];
|
||||
char rtnBuff[BUFF_SIZE];
|
||||
E710_Status_Reg mstat;
|
||||
int rtn_state;
|
||||
unsigned int convert_cnt, charcnt, statusInt;
|
||||
epicsInt32 motorData;
|
||||
bool plusdir, ls_active, plusLS, minusLS;
|
||||
msta_field status;
|
||||
|
||||
cntrl = (struct PIE710controller *) motor_state[card]->DevicePrivate;
|
||||
motor_info = &(motor_state[card]->motor_info[signal]);
|
||||
nodeptr = motor_info->motor_motion;
|
||||
if (nodeptr != NULL)
|
||||
mr = (struct motorRecord *) nodeptr->mrecord;
|
||||
else
|
||||
mr = NULL;
|
||||
status.All = motor_info->status.All;
|
||||
|
||||
if (cntrl->status != NORMAL)
|
||||
charcnt = recv_mess(card, buff, FLUSH);
|
||||
|
||||
send_mess(card, "#GI8", PIE710_axis[signal]);
|
||||
charcnt = recv_mess(card, buff, 1);
|
||||
if (charcnt > 2)
|
||||
convert_cnt = sscanf(buff, "%s %s %d\n", rtnBuff, rtnBuff, &statusInt);
|
||||
else
|
||||
convert_cnt = 0;
|
||||
|
||||
if (charcnt > 2 && convert_cnt == 3)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check for 1 byte status of earlier E710 revisions
|
||||
* and shift into high byte */
|
||||
if (cntrl->statusShift)
|
||||
mstat.All = statusInt * (2^8);
|
||||
else
|
||||
mstat.All = statusInt;
|
||||
|
||||
/* Always DONE if torque disabled */
|
||||
status.Bits.RA_DONE = (mstat.Bits.moving && !mstat.Bits.torque) ? 0 : 1;
|
||||
status.Bits.RA_HOME = status.Bits.RA_DONE;
|
||||
|
||||
status.Bits.EA_POSITION = (mstat.Bits.torque) ? 0 : 1; /* Torgue disabled flag */
|
||||
|
||||
ls_active = plusLS = minusLS = false;
|
||||
|
||||
/* LS status may be true but servo is not within position error - keep updating */
|
||||
if (status.Bits.RA_DONE)
|
||||
{
|
||||
plusLS = mstat.Bits.plus_ls ? true : false;
|
||||
minusLS = mstat.Bits.minus_ls ? true : false;
|
||||
}
|
||||
|
||||
send_mess(card, "#TP", PIE710_axis[signal]);
|
||||
recv_mess(card, buff, 1);
|
||||
|
||||
motorData = NINT(atof(buff) / cntrl->drive_resolution[signal]);
|
||||
|
||||
if (motorData == motor_info->position)
|
||||
{
|
||||
if (nodeptr != 0) /* Increment counter only if motor is moving. */
|
||||
motor_info->no_motion_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
status.Bits.RA_DIRECTION = (motorData >= motor_info->position) ? 1 : 0;
|
||||
motor_info->position = motor_info->encoder_position = motorData;
|
||||
motor_info->no_motion_count = 0;
|
||||
}
|
||||
|
||||
plusdir = (status.Bits.RA_DIRECTION) ? true : false;
|
||||
|
||||
/* Set limit switch error indicators. */
|
||||
if (plusLS == true)
|
||||
{
|
||||
status.Bits.RA_PLUS_LS = 1;
|
||||
if (plusdir == true)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_PLUS_LS = 0;
|
||||
|
||||
if (minusLS == true)
|
||||
{
|
||||
status.Bits.RA_MINUS_LS = 1;
|
||||
if (plusdir == false)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_MINUS_LS = 0;
|
||||
|
||||
/* encoder status */
|
||||
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 */
|
||||
|
||||
motor_info->velocity = 0;
|
||||
|
||||
if (!status.Bits.RA_DIRECTION)
|
||||
motor_info->velocity *= -1;
|
||||
|
||||
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
|
||||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
|
||||
|
||||
/* Test for post-move string. */
|
||||
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 &&
|
||||
nodeptr->postmsgptr != 0)
|
||||
{
|
||||
strcpy(buff, nodeptr->postmsgptr);
|
||||
send_mess(card, buff, (char*) NULL);
|
||||
nodeptr->postmsgptr = NULL;
|
||||
}
|
||||
|
||||
exit:
|
||||
motor_info->status.All = status.All;
|
||||
return(rtn_state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* send a message to the PIE710 board */
|
||||
/* send_mess() */
|
||||
/*****************************************************/
|
||||
static RTN_STATUS send_mess(int card, char const *com, char *name)
|
||||
{
|
||||
char local_buff[MAX_MSG_SIZE];
|
||||
struct PIE710controller *cntrl;
|
||||
int comsize, namesize;
|
||||
size_t nwrite;
|
||||
|
||||
comsize = (com == NULL) ? 0 : strlen(com);
|
||||
namesize = (name == NULL) ? 0 : strlen(name);
|
||||
|
||||
if ((comsize + namesize) > MAX_MSG_SIZE)
|
||||
{
|
||||
errlogMessage("drvPIE710.cc:send_mess(); message size violation.\n");
|
||||
return(ERROR);
|
||||
}
|
||||
else if (comsize == 0) /* Normal exit on empty input message. */
|
||||
return(OK);
|
||||
|
||||
if (!motor_state[card])
|
||||
{
|
||||
errlogPrintf("drvPIE710.cc:send_mess() - invalid card #%d\n", card);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
local_buff[0] = (char) NULL; /* Terminate local buffer. */
|
||||
|
||||
if (name == NULL)
|
||||
strcat(local_buff, com); /* Make a local copy of the string. */
|
||||
else
|
||||
{
|
||||
strcpy(local_buff, com);
|
||||
local_buff[0] = *name; /* put in axis. */
|
||||
}
|
||||
|
||||
Debug(2, "send_mess(): message = %s\n", local_buff);
|
||||
|
||||
cntrl = (struct PIE710controller *) motor_state[card]->DevicePrivate;
|
||||
pasynOctetSyncIO->write(cntrl->pasynUser, local_buff, strlen(local_buff),
|
||||
COMM_TIMEOUT, &nwrite);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* receive a message from the PIE710 board */
|
||||
/* recv_mess() */
|
||||
/*****************************************************/
|
||||
static int recv_mess(int card, char *com, int flag)
|
||||
{
|
||||
struct PIE710controller *cntrl;
|
||||
size_t nread = 0;
|
||||
asynStatus status = asynError;
|
||||
int eomReason;
|
||||
|
||||
/* Check that card exists */
|
||||
if (!motor_state[card])
|
||||
return(ERROR);
|
||||
|
||||
cntrl = (struct PIE710controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
if (flag == FLUSH)
|
||||
pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
else
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
|
||||
COMM_TIMEOUT, &nread, &eomReason);
|
||||
|
||||
if ((status != asynSuccess) || (nread <= 0))
|
||||
{
|
||||
com[0] = '\0';
|
||||
nread = 0;
|
||||
}
|
||||
|
||||
Debug(2, "recv_mess(): message = \"%s\"\n", com);
|
||||
return(nread);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Setup system configuration */
|
||||
/* PIE710Setup() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIE710Setup(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 > PIE710_NUM_CARDS)
|
||||
PIE710_num_cards = PIE710_NUM_CARDS;
|
||||
else
|
||||
PIE710_num_cards = num_cards;
|
||||
|
||||
/* Set motor polling task rate */
|
||||
if (scan_rate >= 1 && scan_rate <= 60)
|
||||
targs.motor_scan_rate = scan_rate;
|
||||
else
|
||||
targs.motor_scan_rate = SCAN_RATE;
|
||||
|
||||
/*
|
||||
* Allocate space for motor_state structures. Note this must be done
|
||||
* before PIE710Config 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(PIE710_num_cards *
|
||||
sizeof(struct controller *));
|
||||
|
||||
for (itera = 0; itera < PIE710_num_cards; itera++)
|
||||
motor_state[itera] = (struct controller *) NULL;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Configure a controller */
|
||||
/* PIE710Config() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIE710Config(int card, /* card being configured */
|
||||
const char *name, /* asyn port name */
|
||||
int addr) /* asyn address (GPIB) */
|
||||
{
|
||||
struct PIE710controller *cntrl;
|
||||
|
||||
if (card < 0 || card >= PIE710_num_cards)
|
||||
return(ERROR);
|
||||
|
||||
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
||||
motor_state[card]->DevicePrivate = malloc(sizeof(struct PIE710controller));
|
||||
cntrl = (struct PIE710controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
strcpy(cntrl->asyn_port, name);
|
||||
cntrl->asyn_address = addr;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* initialize all software and hardware */
|
||||
/* This is called from the initialization routine in */
|
||||
/* device support. */
|
||||
/* motor_init() */
|
||||
/*****************************************************/
|
||||
static int motor_init()
|
||||
{
|
||||
struct controller *brdptr;
|
||||
struct PIE710controller *cntrl;
|
||||
int card_index, motor_index;
|
||||
char buff[2][BUFF_SIZE], *pbuff;
|
||||
int total_axis;
|
||||
int status;
|
||||
int version;
|
||||
asynStatus success_rtn;
|
||||
static const char output_terminator[] = "\n";
|
||||
static const char input_terminator[] = "\n";
|
||||
|
||||
initialized = true; /* Indicate that driver is initialized. */
|
||||
|
||||
/* Check for setup */
|
||||
if (PIE710_num_cards <= 0)
|
||||
return(ERROR);
|
||||
|
||||
for (card_index = 0; card_index < PIE710_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 PIE710controller *) brdptr->DevicePrivate;
|
||||
|
||||
status = version = 0;
|
||||
|
||||
/* Initialize communications channel */
|
||||
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));
|
||||
|
||||
/* 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[0], 1);
|
||||
|
||||
/* Parse out E710 revision (3 decimal places) and convert to int */
|
||||
if ((pbuff = strchr(buff[0], 'V')))
|
||||
version = NINT(atof(pbuff+1) * 1000);
|
||||
else
|
||||
version = 0;
|
||||
|
||||
/* Get second return string */
|
||||
status = recv_mess(card_index, buff[1], 1);
|
||||
retry++;
|
||||
} while (status == 0 && !version && retry < 3);
|
||||
}
|
||||
|
||||
if (success_rtn == asynSuccess && status > 0)
|
||||
{
|
||||
strcpy(brdptr->ident, buff[0]);
|
||||
brdptr->localaddr = (char *) NULL;
|
||||
brdptr->motor_in_motion = 0;
|
||||
|
||||
/* Check for E710 versions that need the status word shifted up 8 bits */
|
||||
if ((version >= 5000 || version == 4019 || version == 4020) &&
|
||||
version != 5018)
|
||||
cntrl->statusShift = false;
|
||||
else
|
||||
cntrl->statusShift = true;
|
||||
|
||||
/* Determine # of axes. Request stage name. See if it responds */
|
||||
for (total_axis = 0; total_axis < MAX_AXES; total_axis++)
|
||||
{
|
||||
send_mess(card_index, "#TP", PIE710_axis[total_axis]);
|
||||
status = recv_mess(card_index, buff[0], 1);
|
||||
if (!status)
|
||||
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];
|
||||
|
||||
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;
|
||||
/* PIE710 has DC motor support only */
|
||||
motor_info->encoder_present = YES;
|
||||
motor_info->status.Bits.EA_PRESENT = 1;
|
||||
motor_info->pid_present = YES;
|
||||
motor_info->status.Bits.GAIN_SUPPORT = 1;
|
||||
|
||||
cntrl->drive_resolution[motor_index] = POS_RES;
|
||||
|
||||
set_status(card_index, motor_index); /* Read status of each motor */
|
||||
}
|
||||
}
|
||||
else
|
||||
motor_state[card_index] = (struct controller *) NULL;
|
||||
}
|
||||
|
||||
any_motor_in_motion = 0;
|
||||
|
||||
mess_queue.head = (struct mess_node *) NULL;
|
||||
mess_queue.tail = (struct mess_node *) NULL;
|
||||
|
||||
free_list.head = (struct mess_node *) NULL;
|
||||
free_list.tail = (struct mess_node *) NULL;
|
||||
|
||||
epicsThreadCreate((char *) "PIE710_motor", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/* File: drvPIE710.h */
|
||||
|
||||
|
||||
/* Device Driver Support definitions for motor */
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Current Author: Joe Sullivan
|
||||
* Date: 09/20/2005
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 09/13/2006 jps copied from drvPIC838.h
|
||||
*/
|
||||
|
||||
#ifndef INCdrvPIE710h
|
||||
#define INCdrvPIE710h 1
|
||||
|
||||
#include "motordrvCom.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
|
||||
#define COMM_TIMEOUT 2 /* Timeout in seconds. */
|
||||
#define POS_RES 0.0001 /* Position resolution. */
|
||||
|
||||
struct PIE710controller
|
||||
{
|
||||
asynUser *pasynUser; /* asynUser structure */
|
||||
int asyn_address; /* Use for GPIB or other address with asyn */
|
||||
CommStatus status; /* Controller communication status. */
|
||||
double drive_resolution[4];
|
||||
bool statusShift; /* Older E710 reversions need the status word shifted 8 bits */
|
||||
char asyn_port[80]; /* asyn port name */
|
||||
};
|
||||
|
||||
|
||||
typedef union
|
||||
{
|
||||
epicsUInt16 All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
unsigned int cmnd_err :1; /* 15 - Command Error */
|
||||
unsigned int na6 :1; /* 14 - */
|
||||
unsigned int autozero :1; /* 13 - AutoZero function is running */
|
||||
unsigned int plus_ls :1; /* 12 - Positive limit switch flag. */
|
||||
unsigned int minus_ls :1; /* 11 - Negative limit switch flag. */
|
||||
unsigned int moving :1; /* 10 - Moving indicator - position error outside tolerance */
|
||||
unsigned int volt_limit :1; /* 9 - piezo voltage limit reached */
|
||||
unsigned int torque :1; /* 8 - Servo-control status */
|
||||
unsigned int nabyte :8;
|
||||
|
||||
#else
|
||||
unsigned int nabyte :8;
|
||||
unsigned int torque :1; /* 8 - Servo-control status */
|
||||
unsigned int volt_limit :1; /* 9 - piezo voltage limit reached */
|
||||
unsigned int moving :1; /* 10 - Moving indicator - position error outside tolerance */
|
||||
unsigned int minus_ls :1; /* 11 - Negative limit switch flag. */
|
||||
unsigned int plus_ls :1; /* 12 - Positive limit switch flag. */
|
||||
unsigned int autozero :1; /* 13 - AutoZero function is running */
|
||||
unsigned int na6 :1; /* 14 - */
|
||||
unsigned int cmnd_err :1; /* 15 - Command Error */
|
||||
#endif
|
||||
} Bits;
|
||||
} E710_Status_Reg;
|
||||
|
||||
|
||||
/* Function prototypes. */
|
||||
extern RTN_STATUS PIE710Setup(int, int);
|
||||
extern RTN_STATUS PIE710Config(int, const char *, int);
|
||||
|
||||
#endif /* INCdrvPIE710h */
|
||||
@@ -1,682 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvPIE816.cc
|
||||
USAGE... Motor record driver level support for Physik Instrumente (PI)
|
||||
GmbH & Co. E-816 motor controller.
|
||||
|
||||
Version: 1.1
|
||||
Modified By: sullivan
|
||||
Last Modified: 2008/10/23 20:01:05
|
||||
|
||||
Version: 1.2
|
||||
Modified By: K. Gofron & K. Lauer
|
||||
Last Modified: 2011/09/19
|
||||
Changes required for PIE621 controller.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 10/18/05
|
||||
* Current Author: John Hammonds
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 03/26/07 jph - copied from drvPIE816.cc tested on PI VER "DSP V3.11,MCU V5"
|
||||
*/
|
||||
|
||||
/*
|
||||
DESIGN LIMITATIONS...
|
||||
1 - Like all controllers, the PIE816 must be powered-on when EPICS is first
|
||||
booted up.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <epicsThread.h>
|
||||
#include <drvSup.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "drvPIE816.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define GET_IDENT "*IDN?"
|
||||
#define SET_ONLINE "ONL 1" /* Set Online Mode ON */
|
||||
/*#define SET_VELCTRL "VCO A1 B1 C1" */ /* Set Velocity Control Mode - Required for DONE */
|
||||
#define READ_ONLINE "ONL?" /* Read Online Mode */
|
||||
#define READ_POS "POS? #" /* Read position */
|
||||
#define READ_OVERFLOW "OVF? #" /* Read Servo Overflow Status */
|
||||
#define READ_ONTARGET "ONT? #" /* Read Position ON Target */
|
||||
#define READ_SERVO "SVO? #" /* Read Servo Enable Status */
|
||||
|
||||
|
||||
#define PIE816_NUM_CARDS 10
|
||||
#define MAX_AXES 12
|
||||
#define BUFF_SIZE 100 /* Maximum length of string to/from PIE816 */
|
||||
|
||||
/*----------------debugging-----------------*/
|
||||
volatile int drvPIE816debug = 0;
|
||||
extern "C" {epicsExportAddress(int, drvPIE816debug);}
|
||||
static inline void Debug(int level, const char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
if (level < drvPIE816debug) {
|
||||
va_list pVar;
|
||||
va_start(pVar, format);
|
||||
vprintf(format, pVar);
|
||||
va_end(pVar);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- Local data. --- */
|
||||
int PIE816_num_cards = 0;
|
||||
static char *PIE816_axis[] = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
|
||||
"K","L"};
|
||||
|
||||
/* Local data required for every driver; see "motordrvComCode.h" */
|
||||
#include "motordrvComCode.h"
|
||||
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
static int recv_mess(int, char *, int);
|
||||
static RTN_STATUS send_mess(int, char const *, char *);
|
||||
static int set_status(int, int);
|
||||
static long report(int);
|
||||
static long init();
|
||||
static int motor_init();
|
||||
static void query_done(int, int, struct mess_node *);
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
|
||||
struct driver_table PIE816_access =
|
||||
{
|
||||
motor_init,
|
||||
motor_send,
|
||||
motor_free,
|
||||
motor_card_info,
|
||||
motor_axis_info,
|
||||
&mess_queue,
|
||||
&queue_lock,
|
||||
&free_list,
|
||||
&freelist_lock,
|
||||
&motor_sem,
|
||||
&motor_state,
|
||||
&total_cards,
|
||||
&any_motor_in_motion,
|
||||
send_mess,
|
||||
recv_mess,
|
||||
set_status,
|
||||
query_done,
|
||||
NULL,
|
||||
&initialized,
|
||||
PIE816_axis
|
||||
};
|
||||
|
||||
struct drvPIE816_drvet
|
||||
{
|
||||
long number;
|
||||
long (*report) (int);
|
||||
long (*init) (void);
|
||||
} drvPIE816 = {2, report, init};
|
||||
|
||||
extern "C" {epicsExportAddress(drvet, drvPIE816);}
|
||||
|
||||
static struct thread_args targs = {SCAN_RATE, &PIE816_access, 0.0};
|
||||
|
||||
/*********************************************************
|
||||
* Print out driver status report
|
||||
*********************************************************/
|
||||
static long report(int level)
|
||||
{
|
||||
int card;
|
||||
|
||||
if (PIE816_num_cards <=0)
|
||||
printf(" No PIE816 controllers configured.\n");
|
||||
else
|
||||
{
|
||||
for (card = 0; card < PIE816_num_cards; card++)
|
||||
{
|
||||
struct controller *brdptr = motor_state[card];
|
||||
|
||||
if (brdptr == NULL)
|
||||
printf(" PIE816 controller %d connection failed.\n", card);
|
||||
else
|
||||
{
|
||||
struct PIE816controller *cntrl;
|
||||
|
||||
cntrl = (struct PIE816controller *) brdptr->DevicePrivate;
|
||||
printf(" PIE816 controller #%d, port=%s, id: %s \n", card,
|
||||
cntrl->asyn_port, brdptr->ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
static long init()
|
||||
{
|
||||
/*
|
||||
* We cannot call motor_init() here, because that function can do GPIB I/O,
|
||||
* and hence requires that the drvGPIB have already been initialized.
|
||||
* That cannot be guaranteed, so we need to call motor_init from device
|
||||
* support
|
||||
*/
|
||||
/* Check for setup */
|
||||
if (PIE816_num_cards <= 0)
|
||||
{
|
||||
Debug(1, "init(): PIE816 driver disabled. PIE816Setup() missing from startup script.\n");
|
||||
}
|
||||
return((long) 0);
|
||||
}
|
||||
|
||||
|
||||
static void query_done(int card, int axis, struct mess_node *nodeptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* FUNCTION NAME: set_status *
|
||||
* *
|
||||
* LOGIC: *
|
||||
* Initialize. *
|
||||
* Send "Moving Status" query. *
|
||||
* Read response. *
|
||||
* IF normal response to query. *
|
||||
* Set communication status to NORMAL. *
|
||||
* ELSE *
|
||||
* IF communication status is NORMAL. *
|
||||
* Set communication status to RETRY. *
|
||||
* NORMAL EXIT. *
|
||||
* ELSE *
|
||||
* Set communication status error. *
|
||||
* ERROR EXIT. *
|
||||
* ENDIF *
|
||||
* ENDIF *
|
||||
* *
|
||||
* IF "Moving Status" indicates any motion (i.e. status != 0). *
|
||||
* Clear "Done Moving" status bit. *
|
||||
* ELSE *
|
||||
* Set "Done Moving" status bit. *
|
||||
* ENDIF *
|
||||
* *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
static int set_status(int card, int signal)
|
||||
{
|
||||
struct PIE816controller *cntrl;
|
||||
struct mess_node *nodeptr;
|
||||
struct mess_info *motor_info;
|
||||
struct motorRecord *mr;
|
||||
/* Message parsing variables */
|
||||
char buff[BUFF_SIZE];
|
||||
int rtn_state;
|
||||
unsigned int overflow_status, ontarget_status, servo_status, online_status;
|
||||
epicsInt32 motorData;
|
||||
bool plusdir, ls_active, plusLS, minusLS;
|
||||
bool readOK;
|
||||
msta_field status;
|
||||
|
||||
cntrl = (struct PIE816controller *) motor_state[card]->DevicePrivate;
|
||||
motor_info = &(motor_state[card]->motor_info[signal]);
|
||||
nodeptr = motor_info->motor_motion;
|
||||
if (nodeptr != NULL)
|
||||
mr = (struct motorRecord *) nodeptr->mrecord;
|
||||
else
|
||||
mr = NULL;
|
||||
status.All = motor_info->status.All;
|
||||
|
||||
recv_mess(card, buff, FLUSH);
|
||||
|
||||
readOK = false;
|
||||
//send_mess(card, READ_ONLINE, (char*) NULL);
|
||||
/* if (recv_mess(card, buff, 1) && sscanf(buff, "%d", &online_status))
|
||||
{
|
||||
if (!online_status)
|
||||
{
|
||||
*//* Assume Controller Reboot - Set ONLINE and Velocity Control ON */
|
||||
/*send_mess(card, SET_ONLINE, (char*) NULL);
|
||||
send_mess(card, SET_VELCTRL, (char*) NULL);
|
||||
}
|
||||
*/
|
||||
send_mess(card, READ_ONTARGET, PIE816_axis[signal]);
|
||||
if (recv_mess(card, buff, 1) && sscanf(buff, "%d", &ontarget_status))
|
||||
{
|
||||
send_mess(card, READ_OVERFLOW, PIE816_axis[signal]);
|
||||
if (recv_mess(card, buff, 1) && sscanf(buff, "%d", &overflow_status))
|
||||
{
|
||||
send_mess(card, READ_SERVO, PIE816_axis[signal]);
|
||||
if (recv_mess(card, buff, 1) && sscanf(buff, "%d", &servo_status))
|
||||
{
|
||||
send_mess(card, READ_POS, PIE816_axis[signal]);
|
||||
if (recv_mess(card, buff, 1))
|
||||
{
|
||||
motorData = NINT(atof(buff) / cntrl->drive_resolution[signal]);
|
||||
readOK = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
}
|
||||
*/
|
||||
if (readOK)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Always DONE if torque disabled */
|
||||
status.Bits.RA_DONE = (ontarget_status) ? 1 : 0;
|
||||
status.Bits.RA_HOME = status.Bits.RA_DONE;
|
||||
|
||||
status.Bits.EA_POSITION = (servo_status) ? 1 : 0; /* Torgue disabled flag */
|
||||
|
||||
ls_active = plusLS = minusLS = false;
|
||||
|
||||
/* LS status may be true but servo is not within position error - keep updating */
|
||||
/* No Limit switches but if the Servo Controller overflows indicate with a + LS */
|
||||
if (status.Bits.RA_DONE)
|
||||
plusLS = overflow_status ? true : false;
|
||||
|
||||
if (motorData == motor_info->position)
|
||||
{
|
||||
if (nodeptr != 0) /* Increment counter only if motor is moving. */
|
||||
motor_info->no_motion_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
status.Bits.RA_DIRECTION = (motorData >= motor_info->position) ? 1 : 0;
|
||||
motor_info->position = motor_info->encoder_position = motorData;
|
||||
motor_info->no_motion_count = 0;
|
||||
}
|
||||
|
||||
plusdir = (status.Bits.RA_DIRECTION) ? true : false;
|
||||
|
||||
/* Set limit switch error indicators. */
|
||||
if (plusLS == true)
|
||||
{
|
||||
status.Bits.RA_PLUS_LS = 1;
|
||||
if (plusdir == true)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_PLUS_LS = 0;
|
||||
|
||||
if (minusLS == true)
|
||||
{
|
||||
status.Bits.RA_MINUS_LS = 1;
|
||||
if (plusdir == false)
|
||||
ls_active = true;
|
||||
}
|
||||
else
|
||||
status.Bits.RA_MINUS_LS = 0;
|
||||
|
||||
/* encoder status */
|
||||
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 */
|
||||
|
||||
motor_info->velocity = 0;
|
||||
|
||||
if (!status.Bits.RA_DIRECTION)
|
||||
motor_info->velocity *= -1;
|
||||
|
||||
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
|
||||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
|
||||
|
||||
/* Test for post-move string. */
|
||||
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 &&
|
||||
nodeptr->postmsgptr != 0)
|
||||
{
|
||||
strcpy(buff, nodeptr->postmsgptr);
|
||||
send_mess(card, buff, (char*) NULL);
|
||||
nodeptr->postmsgptr = NULL;
|
||||
}
|
||||
|
||||
exit:
|
||||
motor_info->status.All = status.All;
|
||||
return(rtn_state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* send a message to the PIE816 board */
|
||||
/* send_mess() */
|
||||
/*****************************************************/
|
||||
static RTN_STATUS send_mess(int card, char const *com, char *name)
|
||||
{
|
||||
char local_buff[MAX_MSG_SIZE];
|
||||
char *pbuff;
|
||||
struct PIE816controller *cntrl;
|
||||
int comsize, namesize;
|
||||
size_t nwrite;
|
||||
|
||||
comsize = (com == NULL) ? 0 : strlen(com);
|
||||
namesize = (name == NULL) ? 0 : strlen(name);
|
||||
|
||||
if ((comsize + namesize) > MAX_MSG_SIZE)
|
||||
{
|
||||
errlogMessage("drvPIE816.cc:send_mess(); message size violation.\n");
|
||||
return(ERROR);
|
||||
}
|
||||
else if (comsize == 0) /* Normal exit on empty input message. */
|
||||
return(OK);
|
||||
|
||||
if (!motor_state[card])
|
||||
{
|
||||
errlogPrintf("drvPIE816.cc:send_mess() - invalid card #%d\n", card);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
local_buff[0] = (char) NULL; /* Terminate local buffer. */
|
||||
|
||||
if (name == NULL)
|
||||
strcat(local_buff, com); /* Make a local copy of the string. */
|
||||
else
|
||||
{
|
||||
strcpy(local_buff, com);
|
||||
pbuff = strchr(local_buff, '#');
|
||||
if (pbuff != NULL)
|
||||
*pbuff = *name;
|
||||
else
|
||||
Debug(1, "send_mess(): NAME ERROR: message = %s\n", local_buff);
|
||||
}
|
||||
|
||||
Debug(2, "send_mess(): message = %s\n", local_buff);
|
||||
|
||||
cntrl = (struct PIE816controller *) motor_state[card]->DevicePrivate;
|
||||
pasynOctetSyncIO->write(cntrl->pasynUser, local_buff, strlen(local_buff),
|
||||
COMM_TIMEOUT, &nwrite);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* receive a message from the PIE816 board */
|
||||
/* recv_mess() */
|
||||
/*****************************************************/
|
||||
static int recv_mess(int card, char *com, int flag)
|
||||
{
|
||||
struct PIE816controller *cntrl;
|
||||
size_t nread = 0;
|
||||
asynStatus status = asynError;
|
||||
int eomReason;
|
||||
|
||||
/* Check that card exists */
|
||||
if (!motor_state[card])
|
||||
return(ERROR);
|
||||
|
||||
cntrl = (struct PIE816controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
if (flag == FLUSH)
|
||||
pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
else
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
|
||||
COMM_TIMEOUT, &nread, &eomReason);
|
||||
|
||||
if ((status != asynSuccess) || (nread <= 0))
|
||||
{
|
||||
com[0] = '\0';
|
||||
nread = 0;
|
||||
}
|
||||
|
||||
Debug(2, "recv_mess(): message = \"%s\"\n", com);
|
||||
return(nread);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Setup system configuration */
|
||||
/* PIE816Setup() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIE816Setup(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 > PIE816_NUM_CARDS)
|
||||
PIE816_num_cards = PIE816_NUM_CARDS;
|
||||
else
|
||||
PIE816_num_cards = num_cards;
|
||||
|
||||
/* Set motor polling task rate */
|
||||
if (scan_rate >= 1 && scan_rate <= 60)
|
||||
targs.motor_scan_rate = scan_rate;
|
||||
else
|
||||
targs.motor_scan_rate = SCAN_RATE;
|
||||
|
||||
/*
|
||||
* Allocate space for motor_state structures. Note this must be done
|
||||
* before PIE816Config 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(PIE816_num_cards *
|
||||
sizeof(struct controller *));
|
||||
|
||||
for (itera = 0; itera < PIE816_num_cards; itera++)
|
||||
motor_state[itera] = (struct controller *) NULL;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Configure a controller */
|
||||
/* PIE816Config() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PIE816Config(int card, /* card being configured */
|
||||
const char *name, /* asyn port name */
|
||||
int addr) /* asyn address (GPIB) */
|
||||
{
|
||||
struct PIE816controller *cntrl;
|
||||
|
||||
if (card < 0 || card >= PIE816_num_cards)
|
||||
return(ERROR);
|
||||
|
||||
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
||||
motor_state[card]->DevicePrivate = malloc(sizeof(struct PIE816controller));
|
||||
cntrl = (struct PIE816controller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
strcpy(cntrl->asyn_port, name);
|
||||
cntrl->asyn_address = addr;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* initialize all software and hardware */
|
||||
/* This is called from the initialization routine in */
|
||||
/* device support. */
|
||||
/* motor_init() */
|
||||
/*****************************************************/
|
||||
static int motor_init()
|
||||
{
|
||||
struct controller *brdptr;
|
||||
struct PIE816controller *cntrl;
|
||||
int card_index, motor_index;
|
||||
char buff[BUFF_SIZE], *pbuff;
|
||||
int total_axis;
|
||||
int status;
|
||||
int version;
|
||||
bool online;
|
||||
asynStatus success_rtn;
|
||||
static const char output_terminator[] = EOL_E816;
|
||||
static const char input_terminator[] = EOL_E816;
|
||||
|
||||
initialized = true; /* Indicate that driver is initialized. */
|
||||
|
||||
/* Check for setup */
|
||||
if (PIE816_num_cards <= 0)
|
||||
return(ERROR);
|
||||
|
||||
for (card_index = 0; card_index < PIE816_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 PIE816controller *) brdptr->DevicePrivate;
|
||||
|
||||
status = version = 0;
|
||||
|
||||
/* Initialize communications channel */
|
||||
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));
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Assure that Controller is ONLINE */
|
||||
online = true;
|
||||
/* do
|
||||
{
|
||||
online = false;
|
||||
*/
|
||||
/* Set Controller to ONLINE mode */
|
||||
/* send_mess(card_index, SET_ONLINE, (char*) NULL);
|
||||
send_mess(card_index, READ_ONLINE, (char*) NULL);
|
||||
if ((status = recv_mess(card_index, buff, 1)))
|
||||
online = (atoi(buff)==1) ? true : false;
|
||||
else
|
||||
retry++;
|
||||
} while (online == false && retry < 3);
|
||||
*/
|
||||
send_mess(card_index, GET_IDENT, (char*) NULL);
|
||||
status = recv_mess(card_index, buff, 1);
|
||||
|
||||
/* Parse out E816 revision (2 decimal places) and convert to int */
|
||||
if ((pbuff = strchr(buff, 'V')))
|
||||
version = NINT(atof(pbuff+1) * 100);
|
||||
else
|
||||
version = 0;
|
||||
}
|
||||
|
||||
if (success_rtn == asynSuccess && online == true)
|
||||
{
|
||||
strcpy(brdptr->ident, buff);
|
||||
brdptr->localaddr = (char *) NULL;
|
||||
brdptr->motor_in_motion = 0;
|
||||
|
||||
/* Check for E816 versions that need the status word shifted up 8 bits */
|
||||
/*
|
||||
if (version >= 311)
|
||||
cntrl->versionSupport = true;
|
||||
else
|
||||
cntrl->versionSupport = false;
|
||||
*/
|
||||
/* Determine # of axes. Request stage name. See if it responds */
|
||||
for (total_axis = 0; total_axis < MAX_AXES; total_axis++)
|
||||
{
|
||||
send_mess(card_index, READ_POS, PIE816_axis[total_axis]);
|
||||
status = recv_mess(card_index, buff, 1);
|
||||
if (!status)
|
||||
break;
|
||||
}
|
||||
brdptr->total_axis = total_axis;
|
||||
|
||||
/* Turn ON velocity control mode - All axis */
|
||||
/*send_mess(card_index, SET_VELCTRL, (char*) NULL);*/
|
||||
|
||||
for (motor_index = 0; motor_index < total_axis; motor_index++)
|
||||
{
|
||||
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
|
||||
|
||||
motor_info->status.All = 0;
|
||||
motor_info->no_motion_count = 0;
|
||||
motor_info->encoder_position = 0;
|
||||
motor_info->position = 0;
|
||||
brdptr->motor_info[motor_index].motor_motion = NULL;
|
||||
/* PIE816 has DC motor support only */
|
||||
motor_info->encoder_present = YES;
|
||||
motor_info->status.Bits.EA_PRESENT = 1;
|
||||
motor_info->pid_present = NO;
|
||||
motor_info->status.Bits.GAIN_SUPPORT = 1;
|
||||
|
||||
cntrl->drive_resolution[motor_index] = POS_RES;
|
||||
|
||||
set_status(card_index, motor_index); /* Read status of each motor */
|
||||
}
|
||||
}
|
||||
else
|
||||
motor_state[card_index] = (struct controller *) NULL;
|
||||
}
|
||||
|
||||
any_motor_in_motion = 0;
|
||||
|
||||
mess_queue.head = (struct mess_node *) NULL;
|
||||
mess_queue.tail = (struct mess_node *) NULL;
|
||||
|
||||
free_list.head = (struct mess_node *) NULL;
|
||||
free_list.tail = (struct mess_node *) NULL;
|
||||
|
||||
epicsThreadCreate((char *) "PIE816_motor", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/* File: drvPIE816.h */
|
||||
|
||||
|
||||
/* Device Driver Support definitions for motor */
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Current Author: Joe Sullivan
|
||||
* Date: 09/20/2005
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 09/13/2006 jps copied from drvPIC838.h
|
||||
*/
|
||||
|
||||
#ifndef INCdrvPIE816h
|
||||
#define INCdrvPIE816h 1
|
||||
|
||||
#include "motordrvCom.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
|
||||
#define COMM_TIMEOUT 2 /* Timeout in seconds. */
|
||||
#define POS_RES 0.0001 /* Position resolution. */
|
||||
|
||||
#define EOL_E816 "\n" /* Command End-Of-Line = LF (0x10) */
|
||||
|
||||
struct PIE816controller
|
||||
{
|
||||
asynUser *pasynUser; /* asynUser structure */
|
||||
int asyn_address; /* Use for GPIB or other address with asyn */
|
||||
CommStatus status; /* Controller communication status. */
|
||||
double drive_resolution[4];
|
||||
bool versionSupport; /* Track supported Versions - include in Report */
|
||||
char asyn_port[80]; /* asyn port name */
|
||||
};
|
||||
|
||||
|
||||
typedef union
|
||||
{
|
||||
epicsUInt16 All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
unsigned int cmnd_err :1; /* 15 - Command Error */
|
||||
unsigned int na6 :1; /* 14 - */
|
||||
unsigned int autozero :1; /* 13 - AutoZero function is running */
|
||||
unsigned int plus_ls :1; /* 12 - Positive limit switch flag. */
|
||||
unsigned int minus_ls :1; /* 11 - Negative limit switch flag. */
|
||||
unsigned int moving :1; /* 10 - Moving indicator - position error outside tolerance */
|
||||
unsigned int volt_limit :1; /* 9 - piezo voltage limit reached */
|
||||
unsigned int torque :1; /* 8 - Servo-control status */
|
||||
unsigned int nabyte :8;
|
||||
|
||||
#else
|
||||
unsigned int nabyte :8;
|
||||
unsigned int torque :1; /* 8 - Servo-control status */
|
||||
unsigned int volt_limit :1; /* 9 - piezo voltage limit reached */
|
||||
unsigned int moving :1; /* 10 - Moving indicator - position error outside tolerance */
|
||||
unsigned int minus_ls :1; /* 11 - Negative limit switch flag. */
|
||||
unsigned int plus_ls :1; /* 12 - Positive limit switch flag. */
|
||||
unsigned int autozero :1; /* 13 - AutoZero function is running */
|
||||
unsigned int na6 :1; /* 14 - */
|
||||
unsigned int cmnd_err :1; /* 15 - Command Error */
|
||||
#endif
|
||||
} Bits;
|
||||
} E816_Status_Reg;
|
||||
|
||||
|
||||
/* Function prototypes. */
|
||||
extern RTN_STATUS PIE816Setup(int, int);
|
||||
extern RTN_STATUS PIE816Config(int, const char *, int);
|
||||
|
||||
#endif /* INCdrvPIE816h */
|
||||
Reference in New Issue
Block a user