Driver for smarAct MCS Positioner
==================================

Till Straumann <strauman@slac.stanford.edu>, 9/2011

Introduction
------------

This driver supports the smarAct MCS Positioner
by implementing subclasses of the 'asynMotorController'
and 'asynMotorAxis' objects.

Communication with the hardware is established via
a 'asyn port' driver layer and it is thus possible
to use either a physical RS232 port or a terminal
server in a transparent fashion. 

Note: the reader is assumed to be familiar with the
motor record. Please consult relevant documentation.

Restrictions
------------

The driver does not support all features of the MCS
firmware (some of which are outside of the scope of
the motor record). Neither are all features of the
motor record supported.

The driver currently relies on the presence of a
linear position sensor and uses a command set specific
to such sensors. Rotary sensors and the associated
command set are not supported. Closed-loop mode is
used exclusively for all motion commands.

Limit switches are not supported (the MCS command
set defines no interface to hardware limit switches).

The driver operates directly in user coordinates (nm)
no translation into 'steps' is supported.

The 'JOG' feature of the motor record is implemented
using a relative-move command to a 'far-away' target.
This might or might not work if a different position
sensor (working at a different scale) is employed.

Acceleration-control is not supported.

The drivers makes the following assumptions about
the setup
 - reset command ('R') is never used by third party
   while the driver is running.
 - 'synchronous' communication mode ('SCM') is in
   effect.
 - 'keep-alive' mode is not in effect (but if the
   keep-alive time is longer than the driver's 
   slowest polling period then 'keep-alive' mode
   should work).
 - sensor is never disabled ('SSE'). Permanent 'on'
   or power-save mode are OK.
 - sensor type ('SST') is configured correctly (must
   be performed once by third-party when a new unit
   is commissioned).
 - sensor is properly calibrated ('CS') but this
   must not be performed by third party while this
   driver is running.
 - baud rate is configured correctly at both ends
   ('CB') and terminal-server or UART port setup.

Otherwise, a secondary driver using an orthogonal
command set may run concurrently with this driver
as long as it properly shares the asyn port driver
in charge of serial communication.

Special Features
----------------

Position Reference
..................
After power-up the position sensor must be positioned
to a reference mark in order for it to provide
absolute positions. The 'MOTOR_HOMED' bit in the
'MSTA' field reflects the status of the positioner.
Only if 'MOTOR_HOMED' is set the absolute position
is correct. Note that this bit is read from the
hardware and is hence preserved across IOC reboots
(as long as power from the MCS is not removed).

Position Holding
................
All motion commands are executed in 'closed-loop'
mode of the MCS controller, i.e., the controller
hardware itself drives the positioner to the target
in 'closed-loop' mode.
The MCS can also be instructed to actively hold the
target position (compensating small movements, drift
etc.). This feature can be programmed using the 
motor record's CNEN field (enabled: MCS holds
target position indefinitely; disabled: MCS goes
to open-loop mode as soon as the target is
reached).

Usage Information
-----------------
The position sensor has a very high (1nm)
resolution and it is unlikely (especially
in 'no-hold' mode, i.e., if CNEN is 'disabled')
that the target position can be reached
exactly. In order to avoid many retries
the dead-band (RDBD) and/or other parameters
of the motor record may need appropriate
tuning.

It should also be noted that the positioner
is quite fast and performes moves almost
'instantaneously' (as perceived by an operator)
unless the speed is reduced (VELO).
'JOG' mode is probably useless unless the jog
velocity (JVEL) is set to a relatively low
value which allows the operator to observe
the motion. However, performing a JOG operation
with JVEL at zero will be rejected (since zero
would choose the default speed which is too
high to be useful). The driver immediately
reports the motion as 'DONE' (in MSTA).
It is the user's responsibility to clear the
JOGF/JOGR field if this happens.

Building an Application
- - - - - - - - - - - -
Building the driver into an application requires

a) the 'asyn', 'motor' and 'smarActMCSMotor' (this
   driver) packages/modules to be built and
   installed. The application's RELEASE file must
   point to these packages so that the build process
   locates headers and libraries etc.

b) the application's '.dbd' file must contain
    - motorSupport.dbd
    - devSmarActMCSMotor.dbd
   as well as an 'asyn' port driver for serial
   communication. In case of a connection via
   TCP/IP + terminal server this would be
    - drvAsynIPPort.dbd

   These '.dbd' files are best listed in the
   application Makefile:
    <app>_DBD += motorSupport.dbd
    <app>_DBD += devSmarActMCSMotor.dbd
    <app>_DBD += drvAsynIPPort.dbd

c) the application must be linked against
   the 'smarActMCSMotor', 'motor' and 'asyn'
   libraries, e.g.,

    <app>_LIBS += smarActMCSMotor motor asyn

Driver Run-Time Configuration
- - - - - - - - - - - - - - -
For each MCS controller a driver instance needs
to be configured either from a startup script,
C or C++ code (the C++ constructor takes the
same arguments).
However, at first an asyn port driver for
serial communication must be created (e.g.
from the startup script). E.g., when using
a terminal server then drvAsynIPPort may be
used:

  drvAsynIPPortConfigure("myTS1","terminalserver:port",0,0,0)

Next, an MCS controller driver instance is
created. The respective call takes the following
arguments:


smarActMCSCreateController(
     const char *motorPortName,
     const char *ioPortName,
     int         numAxes,
     double      movingPollPeriod,
     double      idlePollPeriod);

  motorPortName: unique string to identify this
                 instance to be used in the
                 motor record's 'OUT' field.
  ioPortName:    asyn port name identifying the
                 serial link for communication
                 with the MCS.
                 Note that such a link must
                 be created prior to creating
                 a MCS controller driver instance.
  numAxes:       number of axes this MCS supports.
  movingPollPeriod: period (in seconds - since 
                 this is  a 'double' parameter
                 fractional seconds are possible)
                 at which the MCS is polled for
                 status changes while the 
                 positioner is moving.
  idlePollPeriod: period (in seconds) at which 
                 the MCS is polled for status
                 changes while the positioner
                 is stopped.

E.g., to configure a driver with one axis using
the serial connection 'myTS1' configured in the
prior example we use

smarActMCSCreateController("myMotor1","myTS1",1,0.02,1.0)

This results in a polling interval of 20ms 
while moving and 1s while idle. The driver
instance is named 'myMotor1' and can be
addressed from a motorRecord's OUT field:

  field(DTYP, "asynMotor")
  field(OUT,  "asyn(myMotor1,0)")

After creating a controller, one or more MCS axes 
are created for that controller.  The respective
call takes the following arguments:


smarActMCSCreateAxis(
        const char *motorPortName,
        int        axisNumber,
        int        channel)
{

 motorPortName: unique string to identify this
                instance to be used in the
                motor record's 'OUT' field.
 axisNumber:    axis number being created.
 channel:       channel that the axis is physically
                connected to.
                Note that the channel will be 
                prepended to the command string
                sent to the particular axis.

Call the smarActMCSCreateAxis() function for
each axis that needs to be configured.                

Terminal Server / RS232 Port Notes
- - - - - - - - - - - - - - - - - -
It is the user's responsibility to configure
the serial port so it matches the MCS' setup.

Note that a terminal server might need
additional configuration to make sure that
a 'raw' TCP connection is used. Otherwise,
the terminal server might use other protocols
(most notably: the TELNET protocol) on top
of TCP which result in extra characters being
inserted in the data stream which are not
or mis-interpreted by this driver which
expects a 'raw' communication channel.
On some terminal servers a raw TCP socket
may listen on a different port number than
used for a TELNET connection. 

