summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortiagocoutinho <tiagocoutinho@users.sourceforge.net>2012-12-09 19:49:25 +0000
committertiagocoutinho <tiagocoutinho@users.sourceforge.net>2012-12-09 19:49:25 +0000
commit8041182782099f229a3c99527b5ae0007d4a6b31 (patch)
treec2e1183a31ff8a49aced7915dcf908c1225c62ab
parentd4f1a94f69f1c7963c2124a155010a6e0b7f8c5e (diff)
doc update
git-svn-id: file:///home/cpascual/src/sdnongit/svnbck/sardana/trunk@21020 c480fdf4-a248-4bb0-8e4a-34cd1ef68f4f
-rw-r--r--doc/source/devel/api/api_0D.rst4
-rw-r--r--doc/source/devel/api/api_1D.rst4
-rw-r--r--doc/source/devel/api/api_2D.rst4
-rw-r--r--doc/source/devel/api/api_IOR.rst4
-rw-r--r--doc/source/devel/api/api_controller.rst8
-rw-r--r--doc/source/devel/api/api_countertimer.rst4
-rw-r--r--doc/source/devel/api/api_macro.rst2
-rw-r--r--doc/source/devel/api/api_motor.rst4
-rw-r--r--doc/source/devel/api/api_pseudocounter.rst4
-rw-r--r--doc/source/devel/api/api_pseudomotor.rst4
-rw-r--r--doc/source/devel/api/sardana/pool/poolbasechannel.rst24
-rw-r--r--doc/source/devel/api/sardana/sardana.rst1
-rw-r--r--doc/source/devel/api/sardana/sardanavalue.rst24
-rw-r--r--doc/source/devel/api/sardana/tango/pool.rst3
-rw-r--r--doc/source/devel/api/sardana/tango/pool/Controller.rst37
-rw-r--r--doc/source/devel/examples/ControllerTemplate.py4
-rw-r--r--doc/source/devel/examples/controller_examples.rst2
-rw-r--r--doc/source/devel/examples/examples.rst2
-rw-r--r--doc/source/devel/examples/macro_call_examples.rst2
-rw-r--r--doc/source/devel/examples/macro_examples.rst2
-rw-r--r--doc/source/devel/examples/macro_input_examples.rst2
-rw-r--r--doc/source/devel/examples/macro_parameter_examples.rst2
-rw-r--r--doc/source/devel/examples/macro_plotting_examples.rst2
-rw-r--r--doc/source/devel/guide_coding.rst2
-rw-r--r--doc/source/devel/guide_migration.rst4
-rw-r--r--doc/source/devel/howto_controllers/howto_0dcontroller.rst37
-rw-r--r--doc/source/devel/howto_controllers/howto_1dcontroller.rst37
-rw-r--r--doc/source/devel/howto_controllers/howto_2dcontroller.rst37
-rw-r--r--doc/source/devel/howto_controllers/howto_countertimercontroller.rst105
-rw-r--r--doc/source/devel/howto_controllers/howto_ioregistercontroller.rst37
-rw-r--r--doc/source/devel/howto_controllers/howto_motorcontroller.rst694
-rw-r--r--doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst37
-rw-r--r--doc/source/devel/howto_controllers/howto_pseudomotorcontroller.rst37
-rw-r--r--doc/source/devel/howto_controllers/index.rst1033
-rw-r--r--doc/source/devel/howto_controllers/sf_ct_ctrl.py116
-rw-r--r--doc/source/devel/howto_controllers/sf_motor_ctrl.py6
-rw-r--r--doc/source/devel/howto_macros/index.rst2
-rw-r--r--doc/source/devel/howto_macros/macros_general.rst70
-rw-r--r--doc/source/devel/howto_macros/scan_framework.rst4
-rw-r--r--doc/source/devel/index.rst2
-rw-r--r--doc/source/devel/overview/index.rst2
-rw-r--r--doc/source/devel/overview/overview_0D.rst4
-rw-r--r--doc/source/devel/overview/overview_1D.rst17
-rw-r--r--doc/source/devel/overview/overview_2D.rst17
-rw-r--r--doc/source/devel/overview/overview_IOR.rst4
-rw-r--r--doc/source/devel/overview/overview_controller.rst18
-rw-r--r--doc/source/devel/overview/overview_countertimer.rst4
-rw-r--r--doc/source/devel/overview/overview_macroserver.rst15
-rw-r--r--doc/source/devel/overview/overview_motor.rst4
-rw-r--r--doc/source/devel/overview/overview_pool.rst2
-rw-r--r--doc/source/devel/overview/overview_pseudocounter.rst4
-rw-r--r--doc/source/devel/overview/overview_pseudomotor.rst4
-rw-r--r--doc/source/users/faq.rst10
-rw-r--r--doc/source/users/getting_started/index.rst2
-rw-r--r--doc/source/users/getting_started/installing.rst14
-rw-r--r--doc/source/users/getting_started/running_cli.rst6
-rw-r--r--doc/source/users/getting_started/running_server.rst12
-rw-r--r--doc/source/users/index.rst2
-rw-r--r--doc/source/users/overview.rst2
-rw-r--r--doc/source/users/scan.rst8
-rw-r--r--doc/source/users/screenshots.rst4
-rw-r--r--doc/source/users/standard_macro_catalog.rst2
62 files changed, 1424 insertions, 1142 deletions
diff --git a/doc/source/devel/api/api_0D.rst b/doc/source/devel/api/api_0D.rst
index bfa96de2..6cb919c0 100644
--- a/doc/source/devel/api/api_0D.rst
+++ b/doc/source/devel/api/api_0D.rst
@@ -1,6 +1,6 @@
.. currentmodule:: sardana.pool.poolzerodexpchannel
-.. _pool-0d-api:
+.. _sardana-0d-api:
=============================
0D channel API reference
@@ -10,7 +10,7 @@
.. seealso::
- :ref:`pool-0d-overview`
+ :ref:`sardana-0d-overview`
the 0D experiment channel overview
:class:`~sardana.tango.pool.ZeroDExpChannel.ZeroDExpChannel`
diff --git a/doc/source/devel/api/api_1D.rst b/doc/source/devel/api/api_1D.rst
index 43c36946..ae210a46 100644
--- a/doc/source/devel/api/api_1D.rst
+++ b/doc/source/devel/api/api_1D.rst
@@ -1,6 +1,6 @@
.. currentmodule:: sardana.pool.poolonedexpchannel
-.. _pool-1d-api:
+.. _sardana-1d-api:
=============================
1D channel API reference
@@ -10,7 +10,7 @@
.. seealso::
- :ref:`pool-1d-overview`
+ :ref:`sardana-1d-overview`
the 1D experiment channel overview
:class:`~sardana.tango.pool.OneDExpChannel.OneDExpChannel`
diff --git a/doc/source/devel/api/api_2D.rst b/doc/source/devel/api/api_2D.rst
index e93503af..5d80590a 100644
--- a/doc/source/devel/api/api_2D.rst
+++ b/doc/source/devel/api/api_2D.rst
@@ -1,6 +1,6 @@
.. currentmodule:: sardana.pool.pooltwodexpchannel
-.. _pool-2d-api:
+.. _sardana-2d-api:
=============================
2D channel API reference
@@ -10,7 +10,7 @@
.. seealso::
- :ref:`pool-2d-overview`
+ :ref:`sardana-2d-overview`
the 2D experiment channel overview
:class:`~sardana.tango.pool.TwoDExpChannel.TwoDExpChannel`
diff --git a/doc/source/devel/api/api_IOR.rst b/doc/source/devel/api/api_IOR.rst
index 53ba0d92..43638824 100644
--- a/doc/source/devel/api/api_IOR.rst
+++ b/doc/source/devel/api/api_IOR.rst
@@ -1,6 +1,6 @@
.. currentmodule:: sardana.pool.poolioregister
-.. _pool-ior-api:
+.. _sardana-ior-api:
=============================
I/O register API reference
@@ -10,7 +10,7 @@ I/O register API reference
.. seealso::
- :ref:`pool-ior-overview`
+ :ref:`sardana-ior-overview`
the I/O register overview
:class:`~sardana.tango.pool.IORegister.IORegister`
diff --git a/doc/source/devel/api/api_controller.rst b/doc/source/devel/api/api_controller.rst
index db2d78fc..f77e55bf 100644
--- a/doc/source/devel/api/api_controller.rst
+++ b/doc/source/devel/api/api_controller.rst
@@ -1,7 +1,7 @@
.. currentmodule:: sardana.pool.controller
-.. _pool-controller-api:
+.. _sardana-controller-api:
========================
Controller API reference
@@ -15,18 +15,18 @@ Controller API reference
* :class:`PseudoCounterController` - PseudoCounter controller API
* :class:`IORegisterController` - IORegister controller API
-.. _pool-controller-data-type:
+.. _sardana-controller-data-type:
Data Type definition
----------------------
-When writting a new controller you may need to specify extra attributes (per
+When writing a new controller you may need to specify extra attributes (per
controller or/and per axis) as well as extra properties. This chapter describes
how to describe the data type for each of this additional members.
Controller data type definition has the following equivalences. This means you
can use any of the given possibilities to describe a field data type. The
possibilities are ordered by preference (example: usage of :obj:`int` is
-prefered to "int" or "PyTango.DevLong"):
+preferred to "int" or "PyTango.DevLong"):
- for 0D data types:
- **integer**: :obj:`int` | :data:`DataType.Integer <sardana.sardanadefs.DataType>` | "int" | "integer" | "long" | :obj:`long` | [ "PyTango." ] "DevLong"
diff --git a/doc/source/devel/api/api_countertimer.rst b/doc/source/devel/api/api_countertimer.rst
index 470bd2da..3d07a563 100644
--- a/doc/source/devel/api/api_countertimer.rst
+++ b/doc/source/devel/api/api_countertimer.rst
@@ -1,6 +1,6 @@
.. currentmodule:: sardana.pool.poolcountertimer
-.. _pool-countertimer-api:
+.. _sardana-countertimer-api:
=============================
Counter/Timer API reference
@@ -10,7 +10,7 @@ Counter/Timer API reference
.. seealso::
- :ref:`pool-countertimer-overview`
+ :ref:`sardana-countertimer-overview`
the counter/timer overview
:class:`~sardana.tango.pool.CTExpChannel.CTExpChannel`
diff --git a/doc/source/devel/api/api_macro.rst b/doc/source/devel/api/api_macro.rst
index 44ae344f..7c0c4187 100644
--- a/doc/source/devel/api/api_macro.rst
+++ b/doc/source/devel/api/api_macro.rst
@@ -1,7 +1,7 @@
.. currentmodule:: sardana.macroserver.macro
-.. _macroserver-macro-api:
+.. _sardana-macro-api:
===================
Macro API reference
diff --git a/doc/source/devel/api/api_motor.rst b/doc/source/devel/api/api_motor.rst
index 11b20595..d95bbf08 100644
--- a/doc/source/devel/api/api_motor.rst
+++ b/doc/source/devel/api/api_motor.rst
@@ -1,6 +1,6 @@
.. currentmodule:: sardana.pool.poolmotor
-.. _pool-motor-api:
+.. _sardana-motor-api:
===================
Motor API reference
@@ -31,7 +31,7 @@ mimic the as closely as possible the :class:`PoolMotor` :term:`API`.
.. seealso::
- :ref:`pool-motor-overview`
+ :ref:`sardana-motor-overview`
the motor overview
:class:`~sardana.tango.pool.Motor.Motor`
diff --git a/doc/source/devel/api/api_pseudocounter.rst b/doc/source/devel/api/api_pseudocounter.rst
index c74e4428..89ece409 100644
--- a/doc/source/devel/api/api_pseudocounter.rst
+++ b/doc/source/devel/api/api_pseudocounter.rst
@@ -1,6 +1,6 @@
.. currentmodule:: sardana.pool.poolpseudocounter
-.. _pool-pseudocounter-api:
+.. _sardana-pseudocounter-api:
=============================
Pseudo counter API reference
@@ -10,7 +10,7 @@ Pseudo counter API reference
.. seealso::
- :ref:`pool-pseudocounter-overview`
+ :ref:`sardana-pseudocounter-overview`
the pseudo-counter overview
:class:`~sardana.tango.pool.PseudoCounter.PseudoCounter`
diff --git a/doc/source/devel/api/api_pseudomotor.rst b/doc/source/devel/api/api_pseudomotor.rst
index 9512c51e..57b054bb 100644
--- a/doc/source/devel/api/api_pseudomotor.rst
+++ b/doc/source/devel/api/api_pseudomotor.rst
@@ -1,6 +1,6 @@
.. currentmodule:: sardana.pool.poolpseudomotor
-.. _pool-pseudomotor-api:
+.. _sardana-pseudomotor-api:
=============================
Pseudo motor API reference
@@ -10,7 +10,7 @@ Pseudo motor API reference
.. seealso::
- :ref:`pool-pseudomotor-overview`
+ :ref:`sardana-pseudomotor-overview`
the pseudo-motor overview
:class:`~sardana.tango.pool.PseudoMotor.PseudoMotor`
diff --git a/doc/source/devel/api/sardana/pool/poolbasechannel.rst b/doc/source/devel/api/sardana/pool/poolbasechannel.rst
new file mode 100644
index 00000000..e8563fb4
--- /dev/null
+++ b/doc/source/devel/api/sardana/pool/poolbasechannel.rst
@@ -0,0 +1,24 @@
+.. currentmodule:: sardana.pool.poolbasechannel
+
+:mod:`~sardana.pool.poolbasechannel`
+======================================
+
+.. automodule:: sardana.pool.poolbasechannel
+
+.. rubric:: Classes
+
+.. hlist::
+ :columns: 3
+
+ * :class:`PoolBaseChannel`
+
+PoolBaseChannel
+-------------------
+
+.. inheritance-diagram:: PoolBaseChannel
+ :parts: 1
+
+.. autoclass:: PoolBaseChannel
+ :show-inheritance:
+ :members:
+ :undoc-members: \ No newline at end of file
diff --git a/doc/source/devel/api/sardana/sardana.rst b/doc/source/devel/api/sardana/sardana.rst
index 843c8a34..ff8985fe 100644
--- a/doc/source/devel/api/sardana/sardana.rst
+++ b/doc/source/devel/api/sardana/sardana.rst
@@ -27,4 +27,5 @@
sardanameta <sardanameta>
sardanamanager <sardanamanager>
sardanaattribute <sardanaattribute>
+ sardanavalue <sardanavalue>
diff --git a/doc/source/devel/api/sardana/sardanavalue.rst b/doc/source/devel/api/sardana/sardanavalue.rst
new file mode 100644
index 00000000..67f78afc
--- /dev/null
+++ b/doc/source/devel/api/sardana/sardanavalue.rst
@@ -0,0 +1,24 @@
+.. currentmodule:: sardana.sardanavalue
+
+:mod:`~sardana.pool.sardanavalue`
+=================================
+
+.. automodule:: sardana.sardanavalue
+
+.. rubric:: Classes
+
+.. hlist::
+ :columns: 3
+
+ * :class:`SardanaValue`
+
+SardanaValue
+------------
+
+.. inheritance-diagram:: SardanaValue
+ :parts: 1
+
+.. autoclass:: SardanaValue
+ :inherited-members:
+ :members:
+ :undoc-members:
diff --git a/doc/source/devel/api/sardana/tango/pool.rst b/doc/source/devel/api/sardana/tango/pool.rst
index 0083a83e..7b63e7ac 100644
--- a/doc/source/devel/api/sardana/tango/pool.rst
+++ b/doc/source/devel/api/sardana/tango/pool.rst
@@ -1,7 +1,7 @@
.. currentmodule:: sardana.tango.pool
:mod:`~sardana.tango.pool`
-============================
+==========================
.. automodule:: sardana.tango.pool
@@ -12,6 +12,7 @@
Pool <pool/Pool>
PoolDevice <pool/PoolDevice>
+ Controller <pool/Controller>
Motor <pool/Motor>
I/O register <pool/IORegister>
Counter/Timer <pool/CTExpChannel>
diff --git a/doc/source/devel/api/sardana/tango/pool/Controller.rst b/doc/source/devel/api/sardana/tango/pool/Controller.rst
new file mode 100644
index 00000000..801a33a8
--- /dev/null
+++ b/doc/source/devel/api/sardana/tango/pool/Controller.rst
@@ -0,0 +1,37 @@
+.. currentmodule:: sardana.tango.pool.Controller
+
+:mod:`~sardana.tango.pool.Controller`
+=====================================
+
+.. automodule:: sardana.tango.pool.Controller
+
+.. rubric:: Classes
+
+.. hlist::
+ :columns: 3
+
+ * :class:`Controller`
+ * :class:`ControllerClass`
+
+Controller
+----------
+
+.. inheritance-diagram:: Controller
+ :parts: 1
+
+.. autoclass:: Controller
+ :show-inheritance:
+ :members:
+ :undoc-members:
+
+ControllerClass
+---------------
+
+.. inheritance-diagram:: ControllerClass
+ :parts: 1
+
+.. autoclass:: ControllerClass
+ :show-inheritance:
+ :members:
+ :undoc-members:
+
diff --git a/doc/source/devel/examples/ControllerTemplate.py b/doc/source/devel/examples/ControllerTemplate.py
index b88917e3..3fbf5f97 100644
--- a/doc/source/devel/examples/ControllerTemplate.py
+++ b/doc/source/devel/examples/ControllerTemplate.py
@@ -5,8 +5,8 @@ import sys
ControllerTemplate.py: Create a basic controller's template.
Its parameters are the file name plus .py,
the class inherited if it had (optional)
- and "yes" if you wanna use the obsolete convention.
-The necesary "defs" are marked as #TODO
+ and "yes" if you want to use the obsolete convention.
+The necessary "defs" are marked as #TODO
python ControllerTemplate.py ExampleClass.py InheritedClass NoCT
"""
diff --git a/doc/source/devel/examples/controller_examples.rst b/doc/source/devel/examples/controller_examples.rst
index c3dbcb2e..e7aacb21 100644
--- a/doc/source/devel/examples/controller_examples.rst
+++ b/doc/source/devel/examples/controller_examples.rst
@@ -1,4 +1,4 @@
-.. _devel-controller-examples:
+.. _sardana-devel-controller-examples:
=========================
Controller examples
diff --git a/doc/source/devel/examples/examples.rst b/doc/source/devel/examples/examples.rst
index 439c7957..d19bd62a 100644
--- a/doc/source/devel/examples/examples.rst
+++ b/doc/source/devel/examples/examples.rst
@@ -1,5 +1,5 @@
-.. _devel-examples:
+.. _sardana-devel-examples:
=========
Examples
diff --git a/doc/source/devel/examples/macro_call_examples.rst b/doc/source/devel/examples/macro_call_examples.rst
index 707368ed..2e9e41d2 100644
--- a/doc/source/devel/examples/macro_call_examples.rst
+++ b/doc/source/devel/examples/macro_call_examples.rst
@@ -1,4 +1,4 @@
-.. _devel-macro-call-examples:
+.. _sardana-devel-macro-call-examples:
=========================
Macro call examples
diff --git a/doc/source/devel/examples/macro_examples.rst b/doc/source/devel/examples/macro_examples.rst
index 5ed09083..8094866d 100644
--- a/doc/source/devel/examples/macro_examples.rst
+++ b/doc/source/devel/examples/macro_examples.rst
@@ -1,6 +1,6 @@
-.. _devel-macro-examples:
+.. _sardana-devel-macro-examples:
==============
Macro examples
diff --git a/doc/source/devel/examples/macro_input_examples.rst b/doc/source/devel/examples/macro_input_examples.rst
index 6ee77138..87e0ac06 100644
--- a/doc/source/devel/examples/macro_input_examples.rst
+++ b/doc/source/devel/examples/macro_input_examples.rst
@@ -1,5 +1,5 @@
-.. _devel-macro-input-examples:
+.. _sardana-devel-macro-input-examples:
=========================
Macro input examples
diff --git a/doc/source/devel/examples/macro_parameter_examples.rst b/doc/source/devel/examples/macro_parameter_examples.rst
index a4144050..15ccb0a3 100644
--- a/doc/source/devel/examples/macro_parameter_examples.rst
+++ b/doc/source/devel/examples/macro_parameter_examples.rst
@@ -1,5 +1,5 @@
-.. _devel-macro-parameter-examples:
+.. _sardana-devel-macro-parameter-examples:
=========================
Macro parameter examples
diff --git a/doc/source/devel/examples/macro_plotting_examples.rst b/doc/source/devel/examples/macro_plotting_examples.rst
index 8bf2845e..7bc63e6f 100644
--- a/doc/source/devel/examples/macro_plotting_examples.rst
+++ b/doc/source/devel/examples/macro_plotting_examples.rst
@@ -1,5 +1,5 @@
-.. _devel-macro-plotting-examples:
+.. _sardana-devel-macro-plotting-examples:
=========================
Macro plotting examples
diff --git a/doc/source/devel/guide_coding.rst b/doc/source/devel/guide_coding.rst
index a8e3078c..dddc5700 100644
--- a/doc/source/devel/guide_coding.rst
+++ b/doc/source/devel/guide_coding.rst
@@ -1,4 +1,4 @@
-.. _coding-guide:
+.. _sardana-coding-guide:
==============================
Sardana development guidelines
diff --git a/doc/source/devel/guide_migration.rst b/doc/source/devel/guide_migration.rst
index 446831e1..e85bcbb5 100644
--- a/doc/source/devel/guide_migration.rst
+++ b/doc/source/devel/guide_migration.rst
@@ -44,7 +44,7 @@ New features in API v1
This chapter is a summary of all new features in *API v1*.
-1. Macros can now be functions(see :ref:`macroserver-macros-howto`).
+1. Macros can now be functions(see :ref:`sardana-macros-howto`).
How to migrate your controller code
===================================
@@ -128,7 +128,7 @@ The following changes are not necessary to make your controller work. The
#. In *API v0* class member (like :attr:`~Controller.ctrl_extra_attributes`)
value for key *type* had to be a string (like 'PyTango.DevString' or
'PyTango.DevDouble'). Now they can be a python type (like str or float).
- Please check :ref:`pool-controller-data-type` for more information.
+ Please check :ref:`sardana-controller-data-type` for more information.
4. **generic controller method names**:
diff --git a/doc/source/devel/howto_controllers/howto_0dcontroller.rst b/doc/source/devel/howto_controllers/howto_0dcontroller.rst
new file mode 100644
index 00000000..23c5af66
--- /dev/null
+++ b/doc/source/devel/howto_controllers/howto_0dcontroller.rst
@@ -0,0 +1,37 @@
+.. currentmodule:: sardana.pool.controller
+
+.. _sardana-0dcontroller-howto-basics:
+
+============================
+How to write a 0D controller
+============================
+
+The basics
+----------
+
+.. todo:: document 0D controller howto
+
+.. _ALBA: http://www.cells.es/
+.. _ANKA: http://http://ankaweb.fzk.de/
+.. _ELETTRA: http://http://www.elettra.trieste.it/
+.. _ESRF: http://www.esrf.eu/
+.. _FRMII: http://www.frm2.tum.de/en/index.html
+.. _HASYLAB: http://hasylab.desy.de/
+.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
+.. _SOLEIL: http://www.synchrotron-soleil.fr/
+
+.. _Tango: http://www.tango-controls.org/
+.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
+.. _PyTango: http://packages.python.org/PyTango/
+.. _Taurus: http://packages.python.org/taurus/
+.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
+.. _Qt: http://qt.nokia.com/products/
+.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
+.. _PyQwt: http://pyqwt.sourceforge.net/
+.. _Python: http://www.python.org/
+.. _IPython: http://ipython.org/
+.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
+.. _Qub: http://www.blissgarden.org/projects/qub/
+.. _numpy: http://numpy.scipy.org/
+.. _SPEC: http://www.certif.com/
+.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/howto_1dcontroller.rst b/doc/source/devel/howto_controllers/howto_1dcontroller.rst
new file mode 100644
index 00000000..634654e7
--- /dev/null
+++ b/doc/source/devel/howto_controllers/howto_1dcontroller.rst
@@ -0,0 +1,37 @@
+.. currentmodule:: sardana.pool.controller
+
+.. _sardana-1dcontroller-howto-basics:
+
+============================
+How to write a 1D controller
+============================
+
+The basics
+----------
+
+.. todo:: document 1D controller howto
+
+.. _ALBA: http://www.cells.es/
+.. _ANKA: http://http://ankaweb.fzk.de/
+.. _ELETTRA: http://http://www.elettra.trieste.it/
+.. _ESRF: http://www.esrf.eu/
+.. _FRMII: http://www.frm2.tum.de/en/index.html
+.. _HASYLAB: http://hasylab.desy.de/
+.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
+.. _SOLEIL: http://www.synchrotron-soleil.fr/
+
+.. _Tango: http://www.tango-controls.org/
+.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
+.. _PyTango: http://packages.python.org/PyTango/
+.. _Taurus: http://packages.python.org/taurus/
+.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
+.. _Qt: http://qt.nokia.com/products/
+.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
+.. _PyQwt: http://pyqwt.sourceforge.net/
+.. _Python: http://www.python.org/
+.. _IPython: http://ipython.org/
+.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
+.. _Qub: http://www.blissgarden.org/projects/qub/
+.. _numpy: http://numpy.scipy.org/
+.. _SPEC: http://www.certif.com/
+.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/howto_2dcontroller.rst b/doc/source/devel/howto_controllers/howto_2dcontroller.rst
new file mode 100644
index 00000000..bc73fceb
--- /dev/null
+++ b/doc/source/devel/howto_controllers/howto_2dcontroller.rst
@@ -0,0 +1,37 @@
+.. currentmodule:: sardana.pool.controller
+
+.. _sardana-2dcontroller-howto-basics:
+
+============================
+How to write a 2D controller
+============================
+
+The basics
+----------
+
+.. todo:: document 2D controller howto
+
+.. _ALBA: http://www.cells.es/
+.. _ANKA: http://http://ankaweb.fzk.de/
+.. _ELETTRA: http://http://www.elettra.trieste.it/
+.. _ESRF: http://www.esrf.eu/
+.. _FRMII: http://www.frm2.tum.de/en/index.html
+.. _HASYLAB: http://hasylab.desy.de/
+.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
+.. _SOLEIL: http://www.synchrotron-soleil.fr/
+
+.. _Tango: http://www.tango-controls.org/
+.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
+.. _PyTango: http://packages.python.org/PyTango/
+.. _Taurus: http://packages.python.org/taurus/
+.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
+.. _Qt: http://qt.nokia.com/products/
+.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
+.. _PyQwt: http://pyqwt.sourceforge.net/
+.. _Python: http://www.python.org/
+.. _IPython: http://ipython.org/
+.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
+.. _Qub: http://www.blissgarden.org/projects/qub/
+.. _numpy: http://numpy.scipy.org/
+.. _SPEC: http://www.certif.com/
+.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/howto_countertimercontroller.rst b/doc/source/devel/howto_controllers/howto_countertimercontroller.rst
new file mode 100644
index 00000000..22976064
--- /dev/null
+++ b/doc/source/devel/howto_controllers/howto_countertimercontroller.rst
@@ -0,0 +1,105 @@
+.. currentmodule:: sardana.pool.controller
+
+.. _sardana-countertimercontroller-howto-basics:
+
+=======================================
+How to write a counter/timer controller
+=======================================
+
+The basics
+----------
+
+An example of a hypothetical *Springfield* counter/timer controller will be build
+incrementally from scratch to aid in the explanation.
+
+By now you should have read the general controller basics chapter. You should
+be able to create a CounterTimerController with:
+
+- a proper constructor,
+- add and delete axis methods
+- get axis state
+
+
+.. code-block:: python
+
+ import springfieldlib
+
+ from sardana.pool.controller import CounterTimerController
+
+ class SpringfieldCounterTimerController(CounterTimerController):
+
+ def __init__(self, inst, props, *args, **kwargs):
+ super(SpringfieldCounterTimerController, self).__init__(inst, props, *args, **kwargs)
+
+ # initialize hardware communication
+ self.springfield = springfieldlib.SpringfieldCounterHW()
+
+ # do some initialization
+ self._counters = {}
+
+ def AddDevice(self, axis):
+ self._counters[axis] = True
+
+ def DeleteDevice(self, axis):
+ del self._counters[axis]
+
+ StateMap = {
+ 1 : State.On,
+ 2 : State.Moving,
+ 3 : State.Fault,
+ }
+
+ def StateOne(self, axis):
+ springfield = self.springfield
+ state = self.StateMap[ springfield.getState(axis) ]
+ status = springfield.getStatus(axis)
+ return state, status
+
+The examples use a :mod:`springfieldlib` module which emulates a counter/timer
+hardware access library.
+
+The :mod:`springfieldlib` can be downloaded from
+:download:`here <springfieldlib.py>`.
+
+The Springfield counter/timer controller can be downloaded from
+:download:`here <sf_ct_ctrl.py>`.
+
+The following code describes a minimal *Springfield* base counter/timer controller
+which is able to return both the state and value of an individual counter as
+well as to start an acquisition:
+
+.. literalinclude:: sf_ct_ctrl.py
+ :pyobject: SpringfieldBaseCounterTimerController
+
+This code is shown only to demonstrate the minimal controller :term:`API`.
+The advanced counter/timer controller chapters describe how to account for more
+complex behaviour like reducing the number of hardware accesses.
+
+.. todo:: finish counter/timer controller howto
+
+
+
+.. _ALBA: http://www.cells.es/
+.. _ANKA: http://http://ankaweb.fzk.de/
+.. _ELETTRA: http://http://www.elettra.trieste.it/
+.. _ESRF: http://www.esrf.eu/
+.. _FRMII: http://www.frm2.tum.de/en/index.html
+.. _HASYLAB: http://hasylab.desy.de/
+.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
+.. _SOLEIL: http://www.synchrotron-soleil.fr/
+
+.. _Tango: http://www.tango-controls.org/
+.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
+.. _PyTango: http://packages.python.org/PyTango/
+.. _Taurus: http://packages.python.org/taurus/
+.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
+.. _Qt: http://qt.nokia.com/products/
+.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
+.. _PyQwt: http://pyqwt.sourceforge.net/
+.. _Python: http://www.python.org/
+.. _IPython: http://ipython.org/
+.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
+.. _Qub: http://www.blissgarden.org/projects/qub/
+.. _numpy: http://numpy.scipy.org/
+.. _SPEC: http://www.certif.com/
+.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/howto_ioregistercontroller.rst b/doc/source/devel/howto_controllers/howto_ioregistercontroller.rst
new file mode 100644
index 00000000..ed669c03
--- /dev/null
+++ b/doc/source/devel/howto_controllers/howto_ioregistercontroller.rst
@@ -0,0 +1,37 @@
+.. currentmodule:: sardana.pool.controller
+
+.. _sardana-ioregistercontroller-howto-basics:
+
+=======================================
+How to write an I/O register controller
+=======================================
+
+The basics
+----------
+
+.. todo:: document IORegister controller howto
+
+.. _ALBA: http://www.cells.es/
+.. _ANKA: http://http://ankaweb.fzk.de/
+.. _ELETTRA: http://http://www.elettra.trieste.it/
+.. _ESRF: http://www.esrf.eu/
+.. _FRMII: http://www.frm2.tum.de/en/index.html
+.. _HASYLAB: http://hasylab.desy.de/
+.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
+.. _SOLEIL: http://www.synchrotron-soleil.fr/
+
+.. _Tango: http://www.tango-controls.org/
+.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
+.. _PyTango: http://packages.python.org/PyTango/
+.. _Taurus: http://packages.python.org/taurus/
+.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
+.. _Qt: http://qt.nokia.com/products/
+.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
+.. _PyQwt: http://pyqwt.sourceforge.net/
+.. _Python: http://www.python.org/
+.. _IPython: http://ipython.org/
+.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
+.. _Qub: http://www.blissgarden.org/projects/qub/
+.. _numpy: http://numpy.scipy.org/
+.. _SPEC: http://www.certif.com/
+.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/howto_motorcontroller.rst b/doc/source/devel/howto_controllers/howto_motorcontroller.rst
new file mode 100644
index 00000000..e9e0d759
--- /dev/null
+++ b/doc/source/devel/howto_controllers/howto_motorcontroller.rst
@@ -0,0 +1,694 @@
+.. currentmodule:: sardana.pool.controller
+
+.. _sardana-motorcontroller-howto-basics:
+
+===============================
+How to write a motor controller
+===============================
+
+The basics
+----------
+
+An example of a hypothetical *Springfield* motor controller will be build
+incrementally from scratch to aid in the explanation.
+
+By now you should have read the general controller basics chapter. You should
+now have a MotorController with a proper constructor, add and delete axis methods:
+
+.. code-block:: python
+
+ import springfieldlib
+
+ from sardana.pool.controller import MotorController
+
+ class SpringfieldMotorController(MotorController):
+
+ def __init__(self, inst, props, *args, **kwargs):
+ super(SpringfieldMotorController, self).__init__(inst, props, *args, **kwargs)
+
+ # initialize hardware communication
+ self.springfield = springfieldlib.SpringfieldMotorHW()
+
+ # do some initialization
+ self._motors = {}
+
+ def AddDevice(self, axis):
+ self._motors[axis] = True
+
+ def DeleteDevice(self, axis):
+ del self._motor[axis]
+
+The *get axis state* method has some details that will be explained below.
+
+The examples use a :mod:`springfieldlib` module which emulates a motor hardware
+access library.
+
+The :mod:`springfieldlib` can be downloaded from
+:download:`here <springfieldlib.py>`.
+
+The Springfield motor controller can be downloaded from
+:download:`here <sf_motor_ctrl.py>`.
+
+The following code describes a minimal *Springfield* base motor controller
+which is able to return both the state and position of a motor as well as move
+a motor to the desired position:
+
+.. literalinclude:: sf_motor_ctrl.py
+ :pyobject: SpringfieldBaseMotorController
+
+This code is shown only to demonstrate the minimal controller :term:`API`.
+The advanced motor controller chapters describe how to account for more complex
+behaviour like reducing the number of hardware accesses or synchronize motion of
+multiple motors.
+
+.. _sardana-motorcontroller-howto-axis-state:
+
+Get motor state
+~~~~~~~~~~~~~~~
+
+To get the state of a motor, sardana calls the
+:meth:`~sardana.pool.controller.Controller.StateOne` method. This method
+receives an axis as parameter and should return a sequence of three values:
+
+To get the state of a motor, sardana calls the
+:meth:`~sardana.pool.controller.Controller.StateOne` method. This method
+receives an axis as parameter and should return either:
+
+ - state (:obj:`~sardana.sardanadefs.State`) or
+ - a sequence of two elements:
+ - state (:obj:`~sardana.sardanadefs.State`)
+ - status (:obj:`str`) *or* limit switches (:obj:`int`)
+ - a sequence of three elements:
+ - state (:obj:`~sardana.sardanadefs.State`)
+ - status (:obj:`str`)
+ - limit switches (:obj:`int`)
+
+The state should be a member of :obj:`~sardana.sardanadefs.State` (For backward
+compatibility reasons, it is also supported to return one of
+:class:`PyTango.DevState`). The status could be any string. The limit switches
+is a integer with bits representing the three possible limits: home, upper
+and lower. Sardana provides three constants which can be *or*\ed together to
+provide the desired limit switch:
+
+.. hlist::
+ :columns: 4
+
+ - :attr:`~MotorController.NoLimitSwitch`
+ - :attr:`~MotorController.HomeLimitSwitch`
+ - :attr:`~MotorController.UpperLimitSwitch`
+ - :attr:`~MotorController.LowerLimitSwitch`
+
+To say both home and lower limit switches are active (rare!) you can do::
+
+ limit_switches = MotorController.HomeLimitSwitch | MotorController.LowerLimitSwitch
+
+If you don't return a status, sardana will compose a status string with:
+
+ <axis name> is in <state name>
+
+If you don't return limit switches, sardana will assume all limit switches are
+off.
+
+Here is an example of the possible implementation of
+:meth:`~sardana.pool.controller.Controller.StateOne`:
+
+.. code-block:: python
+ :emphasize-lines: 11
+
+ from sardana import State
+
+ class SpringfieldMotorController(MotorController):
+
+ StateMap = {
+ 1 : State.On,
+ 2 : State.Moving,
+ 3 : State.Fault,
+ }
+
+ def StateOne(self, axis):
+ springfield = self.springfield
+ state = self.StateMap[ springfield.getState(axis) ]
+ status = springfield.getStatus(axis)
+
+ limit_switches = MotorController.NoLimitSwitch
+ hw_limit_switches = springfield.getLimits(axis)
+ if hw_limit_switches[0]:
+ limit_switches |= MotorController.HomeLimitSwitch
+ if hw_limit_switches[1]:
+ limit_switches |= MotorController.UpperLimitSwitch
+ if hw_limit_switches[2]:
+ limit_switches |= MotorController.LowerLimitSwitch
+ return state, status, limit_switches
+
+.. _sardana-motorcontroller-howto-value:
+
+Get motor position
+~~~~~~~~~~~~~~~~~~
+
+To get the motor position, sardana calls the
+:meth:`~sardana.pool.controller.Readable.ReadOne` method. This method
+receives an axis as parameter and should return a valid position. Sardana
+interprets the returned position as a :term:`dial position`.
+
+Here is an example of the possible implementation of
+:meth:`~sardana.pool.controller.Readable.ReadOne`:
+
+.. code-block:: python
+ :emphasize-lines: 3
+
+ class SpringfieldMotorController(MotorController):
+
+ def ReadOne(self, axis):
+ position = self.springfield.getPosition(axis)
+ return position
+
+.. _sardana-motorcontroller-howto-move:
+
+Move a motor
+~~~~~~~~~~~~
+
+When an order comes for sardana to move a motor, sardana will call the
+:meth:`~sardana.pool.controller.Startable.StartOne` method. This method receives
+an axis and a position. The controller code should trigger the hardware motion.
+The given position is always the :term:`dial position`.
+
+Here is an example of the possible implementation of
+:meth:`~sardana.pool.controller.Startable.StartOne`:
+
+.. code-block:: python
+ :emphasize-lines: 3
+
+ class SpringfieldMotorController(MotorController):
+
+ def StartOne(self, axis, position):
+ self.springfield.move(axis, position)
+
+As soon as :meth:`~sardana.pool.controller.Startable.StartOne` is invoked,
+sardana expects the motor to be moving. It enters a high frequency motion
+loop which asks for the motor state through calls to
+:meth:`~sardana.pool.controller.Controller.StateOne`. It will keep the loop
+running as long as the controller responds with ``State.Moving``.
+If :meth:`~sardana.pool.controller.Controller.StateOne` raises an exception
+or returns something other than ``State.Moving``, sardana will assume the motor
+is stopped and exit the motion loop.
+
+For a motion to work properly, it is therefore, **very important** that
+:meth:`~sardana.pool.controller.Controller.StateOne` responds correctly.
+
+.. _sardana-motorcontroller-howto-stop:
+
+Stop a motor
+~~~~~~~~~~~~
+
+It is possible to stop a motor when it is moving. When sardana is ordered to
+stop a motor motion, it invokes the :meth:`~sardana.pool.controller.Stopable.StopOne`
+method. This method receives an axis parameter. The controller should make
+sure the desired motor is *gracefully* stopped, if possible, respecting the
+configured motion parameters (like deceleration and base_rate).
+
+Here is an example of the possible implementation of
+:meth:`~sardana.pool.controller.Stopable.StopOne`:
+
+.. code-block:: python
+ :emphasize-lines: 3
+
+ class SpringfieldMotorController(MotorController):
+
+ def StopOne(self, axis):
+ self.springfield.stop(axis)
+
+.. _sardana-motorcontroller-howto-abort:
+
+Abort a motor
+~~~~~~~~~~~~~
+
+In a danger situation (motor moving a table about to hit a wall), it is
+desirable to abort a motion *as fast as possible*. When sardana is ordered to
+abort a motor motion, it invokes the :meth:`~sardana.pool.controller.Stopable.AbortOne`
+method. This method receives an axis parameter. The controller should make
+sure the desired motor is stopped as fast as it can be done, possibly losing
+track of position.
+
+Here is an example of the possible implementation of
+:meth:`~sardana.pool.controller.Stopable.AbortOne`:
+
+.. code-block:: python
+ :emphasize-lines: 3
+
+ class SpringfieldMotorController(MotorController):
+
+ def AbortOne(self, axis):
+ self.springfield.abort(axis)
+
+.. note::
+
+ The default implementation of :meth:`~sardana.pool.controller.Stopable.StopOne`
+ calls :meth:`~sardana.pool.controller.Stopable.AbortOne` so, if your
+ controller cannot distinguish stopping from aborting, it is sufficient
+ to implement :meth:`~sardana.pool.controller.Stopable.AbortOne`.
+
+.. _sardana-motorcontroller-howto-standard-axis-attributes:
+
+Standard axis attributes
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default, sardana expects every axis to have a set of attributes:
+
+- acceleration
+- deceleration
+- velocity
+- base rate
+- steps per unit
+
+To set and retrieve the value of these attributes, sardana invokes pair of
+methods: :meth:`~sardana.pool.controller.Controller.GetAxisPar`
+/:meth:`~sardana.pool.controller.Controller.SetAxisPar`
+
+Here is an example of the possible implementation:
+
+.. code-block:: python
+ :emphasize-lines: 3, 18
+
+ class SpringfieldMotorController(MotorController):
+
+ def GetAxisPar(self, axis, name):
+ springfield = self.springfield
+ name = name.lower()
+ if name == "acceleration":
+ v = springfield.getAccelerationTime(axis)
+ elif name == "deceleration":
+ v = springfield.getDecelerationTime(axis)
+ elif name == "base_rate":
+ v = springfield.getMinVelocity(axis)
+ elif name == "velocity":
+ v = springfield.getMaxVelocity(axis)
+ elif name == "step_per_unit":
+ v = springfield.getStepPerUnit(axis)
+ return v
+
+ def SetAxisPar(self, axis, name, value):
+ springfield = self.springfield
+ name = name.lower()
+ if name == "acceleration":
+ springfield.setAccelerationTime(axis, value)
+ elif name == "deceleration":
+ springfield.setDecelerationTime(axis, value)
+ elif name == "base_rate":
+ springfield.setMinVelocity(axis, value)
+ elif name == "velocity":
+ springfield.setMaxVelocity(axis, value)
+ elif name == "step_per_unit":
+ springfield.setStepPerUnit(axis, value)
+
+.. seealso::
+
+ :ref:`sardana-motorcontroller-what-to-do`
+ What to do when your hardware motor controller doesn't support
+ steps per unit
+
+.. _sardana-motorcontroller-define-position:
+
+Define a position
+~~~~~~~~~~~~~~~~~
+
+Sometimes it is useful to reset the current position to a certain value.
+Imagine you are writting a controller for a hardware controller which handles
+stepper motors. When the hardware is asked for a motor position it will
+probably answer some value from an internal register which is
+incremented/decremented each time the motor goes up/down a step. Probably this
+value as physical meaning so the usual procedure is to move the motor to a known
+position (home switch, for example) and once there, set a meaningful position to
+the current position. Some motor controllers support reseting the internal
+register to the desired value. If your motor controller can do this the
+implementation is as easy as writting the
+:meth:`~sardana.pool.controller.MotorController.DefinePosition` and call the
+proper code of your hardware library to do it:
+
+.. code-block:: python
+
+ class SpringfieldMotorController(MotorController):
+
+ def DefinePosition(self, axis, position):
+ self.springfield.setCurrentPosition(axis, position)
+
+.. seealso::
+
+ :ref:`sardana-motorcontroller-what-to-do`
+
+ What to do when your hardware motor controller doesn't support
+ defining the position
+
+.. _sardana-motorcontroller-what-to-do:
+
+What to do when...
+~~~~~~~~~~~~~~~~~~
+
+This chapter describes common difficult situations you may face when writting
+a motor controller in sardana, and possible solutions to solve them.
+
+*my controller doesn't support steps per unit*
+ Many (probably, most) hardware motor controllers don't support steps per
+ unit at the hardware level. This means that your sardana controller should
+ be able to emulate steps per unit at the software level.
+ This can be easily done, but it requires you to make some changes in your
+ code.
+
+ We will assume now that the Springfield motor controller doesn't support
+ steps per unit feature. The first that needs to be done is to modify the
+ :meth:`~sardana.pool.controller.Controller.AddDevice` method so it is able to
+ to store the resulting conversion factor between the hardware read position
+ and the position the should be returned (the *step_per_unit*).
+ The :meth:`~sardana.pool.controller.Readable.ReadOne` also needs to be
+ rewritten to make the proper calculation.
+ Finally :meth:`~sardana.pool.controller.Controller.GetAxisPar` /
+ :meth:`~sardana.pool.controller.Controller.SetAxisPar` methods need to
+ be rewritten to properly get/set the step per unit value:
+
+ .. code-block:: python
+
+ class SpringfieldMotorController(MotorController):
+
+ def AddDevice(self, axis):
+ self._motor[axis] = dict(step_per_unit=1.0)
+
+ def ReadOne(self, axis):
+ step_per_unit = self._motor[axis]["step_per_unit"]
+ position = self.springfield.getPosition(axis)
+ return position / step_per_unit
+
+ def GetAxisPar(self, axis, name):
+ springfield = self.springfield
+ name = name.lower()
+ if name == "acceleration":
+ v = springfield.getAccelerationTime(axis)
+ elif name == "deceleration":
+ v = springfield.getDecelerationTime(axis)
+ elif name == "base_rate":
+ v = springfield.getMinVelocity(axis)
+ elif name == "velocity":
+ v = springfield.getMaxVelocity(axis)
+ elif name == "step_per_unit":
+ v = self._motor[axis]["step_per_unit"]
+ return v
+
+ def SetAxisPar(self, axis, name, value):
+ springfield = self.springfield
+ name = name.lower()
+ if name == "acceleration":
+ springfield.setAccelerationTime(axis, value)
+ elif name == "deceleration":
+ springfield.setDecelerationTime(axis, value)
+ elif name == "base_rate":
+ springfield.setMinVelocity(axis, value)
+ elif name == "velocity":
+ springfield.setMaxVelocity(axis, value)
+ elif name == "step_per_unit":
+ self._motor[axis]["step_per_unit"] = value
+
+*my controller doesn't support defining the position*
+ Some controllers may not be able to reset the position to a different value.
+ In these cases, your controller code should be able to emulate such a
+ feature. This can be easily done, but it requires you to make some changes
+ in your code.
+
+ We will now assume that the Springfield motor controller doesn't support
+ steps per unit feature. The first thing that needs to be done is to modify the
+ :meth:`~sardana.pool.controller.Controller.AddDevice` method so it is able
+ to store the resulting offset between the hardware read position and the
+ position the should be returned (the *define_position_offset*).
+ The :meth:`~sardana.pool.controller.Readable.ReadOne` also needs to be
+ rewritten to take the *define_position_offset* into account.
+ Finally :meth:`~sardana.pool.controller.MotorController.DefinePosition`
+ needs to be written to update the *define_position_offset* to the desired
+ value:
+
+ .. code-block:: python
+
+ class SpringfieldMotorController(MotorController):
+
+ def AddDevice(self, axis):
+ self._motor[axis] = dict(define_position_offset=0.0)
+
+ def ReadOne(self, axis):
+ dp_offset = self._motor[axis]["define_position_offset"]
+ position = self.springfield.getPosition(axis)
+ return position + dp_offset
+
+ def DefinePosition(self, axis, position):
+ current_position = self.springfield.getPosition(axis)
+ self._motor[axis]["define_position_offset"] = position - current_position
+
+
+Advanced topics
+---------------
+
+.. _sardana-motorcontroller-howto-timestamp-position:
+
+Timestamp a motor position
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When you read the position of a motor from the hardware sometimes it is
+necessary to associate a timestamp with that position so you can track the
+position of a motor in time.
+
+If sardana is executed as a Tango device server, reading the position
+attribute from the motor device triggers the execution of your controller's
+:meth:`~sardana.pool.controller.Readable.ReadOne` method. Tango responds with
+the value your controller returns from the call to
+:meth:`~sardana.pool.controller.Readable.ReadOne` and automatically assigns
+a timestamp. However this timestamp has a certain delay since the time the
+value was actually read from hardware and the time Tango generates the timestamp.
+
+To avoid this, sardana supports returning in
+:meth:`~sardana.pool.controller.Readable.ReadOne` an object that contains both
+the value and the timestamp instead of the usual :class:`numbers.Number`.
+The object must be an instance of :class:`~sardana.sardanavalue.SardanaValue`.
+
+Here is an example of associating a timestamp in
+:meth:`~sardana.pool.controller.Readable.ReadOne`:
+
+.. code-block:: python
+
+ import time
+ from sardana.pool.controller import SardanaValue
+
+ class SpringfieldMotorController(MotorController):
+
+ def ReadOne(self, axis):
+ return SardanaValue(value=self.springfield.getPosition(axis),
+ timestamp=time.time())
+
+If your controller communicates with a Tango device, Sardana also supports
+returning a :class:`~PyTango.DeviceAttribute` object. Sardana will use this
+object's value and timestamp. Example:
+
+.. code-block:: python
+
+ class TangoMotorController(MotorController):
+
+ def ReadOne(self, axis):
+ return self.device.read_attribute("position")
+
+.. _sardana-motorcontroller-howto-mutiple-motion:
+
+Multiple motion synchronization
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This chapter describes an extended :term:`API` that allows you to better
+synchronize motions involing more than one motor, as well as optimize
+hardware communication (in case the hardware interface also supports this).
+
+Often it is the case that the experiment/procedure the user runs requires to
+move more than one motor at the same time.
+Imagine that the user requires motor at axis 1 to be moved to 100mm and motor
+axis 2 to be moved to -20mm.
+Your controller will receive two consecutive calls to
+:meth:`~sardana.pool.controller.Startable.StartOne`:
+
+.. code-block:: python
+
+ StartOne(1, 100)
+ StartOne(2, -20)
+
+and each StartOne will probably connect to the hardware (through serial line,
+socket, Tango_ or EPICS_) and ask the motor to be moved.
+This will do the job but, there will be a slight desynchronization between the
+two motors because hardware call of motor 1 will be done before hardware call
+to motor 2.
+
+Sardana provides an extended *start motion* which gives you the possibility
+to improve the syncronization (and probably reduce communications) but your
+hardware controller must somehow support this feature as well.
+
+The complete start motion :term:`API` consists of four methods:
+
+ - :meth:`~sardana.pool.controller.Startable.PreStartAll`
+ - :meth:`~sardana.pool.controller.Startable.PreStartOne`
+ - :meth:`~sardana.pool.controller.Startable.StartOne`
+ - :meth:`~sardana.pool.controller.Startable.StartAll`
+
+Except for :meth:`~sardana.pool.controller.Startable.StartOne`, the
+implemenation of all other start methods is optional and their default
+implementation does nothing (:meth:`~sardana.pool.controller.Startable.PreStartOne`
+actually returns ``True``).
+
+So, actually, the complete algorithm for motor motion in sardana is::
+
+ /FOR/ Each controller(s) implied in the motion
+ - Call PreStartAll()
+ /END FOR/
+
+ /FOR/ Each motor(s) implied in the motion
+ - ret = PreStartOne(motor to move, new position)
+ - /IF/ ret is not true
+ /RAISE/ Cannot start. Motor PreStartOne returns False
+ - /END IF/
+ - Call StartOne(motor to move, new position)
+ /END FOR/
+
+ /FOR/ Each controller(s) implied in the motion
+ - Call StartAll()
+ /END FOR/
+
+So, for the example above where we move two motors, the complete sequence of
+calls to the controller is:
+
+.. code-block:: python
+
+ PreStartAll()
+
+ if not PreStartOne(1, 100):
+ raise Exception("Cannot start. Motor(1) PreStartOne returns False")
+ if not PreStartOne(2, -20):
+ raise Exception("Cannot start. Motor(2) PreStartOne returns False")
+
+ StartOne(1, 100)
+ StartOne(2, -20)
+
+ StartAll()
+
+Sardana assures that the above sequence is never interrupted by other calls,
+like a call from a different user to get motor state.
+
+Suppose the springfield library tells us in the documentation that:
+
+ ... to move multiple motors at the same time use::
+
+ moveMultiple(seq<pair<axis, position>>)
+
+ Example::
+
+ moveMultiple([[1, 100], [2, -20]])
+
+We can modify our motor controller to take profit of this hardware feature:
+
+.. code-block:: python
+
+ class SpringfieldMotorController(MotorController):
+
+ def PreStartAll(self):
+ # clear the local motion information dictionary
+ self._moveable_info = []
+
+ def StartOne(self, axis, position):
+ # store information about this axis motion
+ motion_info = axis, position
+ self._moveable_info.append(motion_info)
+
+ def StartAll(self):
+ self.springfield.moveMultiple(self._moveable_info)
+
+A similar principle applies when sardana asks for the state and position of
+multiple axis. The two sets of methods are, in these cases:
+
+.. hlist::
+ :columns: 2
+
+ - :meth:`~sardana.pool.controller.Controller.PreStateAll`
+ - :meth:`~sardana.pool.controller.Controller.PreStateOne`
+ - :meth:`~sardana.pool.controller.Controller.StateAll`
+ - :meth:`~sardana.pool.controller.Controller.StateOne`
+ - :meth:`~sardana.pool.controller.Readable.PreReadAll`
+ - :meth:`~sardana.pool.controller.Readable.PreReadOne`
+ - :meth:`~sardana.pool.controller.Readable.ReadAll`
+ - :meth:`~sardana.pool.controller.Readable.ReadOne`
+
+The main differences between these sets of methods and the ones from start motion
+is that :meth:`~sardana.pool.controller.Controller.StateOne` /
+:meth:`~sardana.pool.controller.Readable.ReadOne` methods are called **AFTER**
+the corresponding :meth:`~sardana.pool.controller.Controller.StateAll` /
+:meth:`~sardana.pool.controller.Readable.ReadAll` counterparts and they are
+expeced to return the state/position of the requested axis.
+
+The internal sardana algorithm to read position is::
+
+ /FOR/ Each controller(s) implied in the reading
+ - Call PreReadAll()
+ /END FOR/
+
+ /FOR/ Each motor(s) implied in the reading
+ - PreReadOne(motor to read)
+ /END FOR/
+
+ /FOR/ Each controller(s) implied in the reading
+ - Call ReadAll()
+ /END FOR/
+
+ /FOR/ Each motor(s) implied in the reading
+ - Call ReadOne(motor to read)
+ /END FOR/
+
+Here is an example assuming the springfield library tells us in the
+documentation that:
+
+ ... to read the position of multiple motors at the same time use::
+
+ getMultiplePosition(seq<axis>) -> dict<axis, position>
+
+ Example::
+
+ positions = getMultiplePosition([1, 2])
+
+The new improved code could look like this::
+
+ class SpringfieldMotorController(MotorController):
+
+ def PreRealAll(self):
+ # clear the local position information dictionary
+ self._position_info = []
+
+ def PreReadOne(self, axis):
+ self._position_info.append(axis)
+
+ def ReadAll(self):
+ self._positions = self.springfield.getMultiplePosition(self._position_info)
+
+ def ReadOne(self, axis):
+ return self._positions[axis]
+
+
+.. _ALBA: http://www.cells.es/
+.. _ANKA: http://http://ankaweb.fzk.de/
+.. _ELETTRA: http://http://www.elettra.trieste.it/
+.. _ESRF: http://www.esrf.eu/
+.. _FRMII: http://www.frm2.tum.de/en/index.html
+.. _HASYLAB: http://hasylab.desy.de/
+.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
+.. _SOLEIL: http://www.synchrotron-soleil.fr/
+
+.. _Tango: http://www.tango-controls.org/
+.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
+.. _PyTango: http://packages.python.org/PyTango/
+.. _Taurus: http://packages.python.org/taurus/
+.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
+.. _Qt: http://qt.nokia.com/products/
+.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
+.. _PyQwt: http://pyqwt.sourceforge.net/
+.. _Python: http://www.python.org/
+.. _IPython: http://ipython.org/
+.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
+.. _Qub: http://www.blissgarden.org/projects/qub/
+.. _numpy: http://numpy.scipy.org/
+.. _SPEC: http://www.certif.com/
+.. _EPICS: http://www.aps.anl.gov/epics/
+ \ No newline at end of file
diff --git a/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst b/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst
new file mode 100644
index 00000000..91ef8d7e
--- /dev/null
+++ b/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst
@@ -0,0 +1,37 @@
+.. currentmodule:: sardana.pool.controller
+
+.. _sardana-pseudocountercontroller-howto-basics:
+
+========================================
+How to write a pseudo counter controller
+========================================
+
+The basics
+----------
+
+.. todo:: document pseudo counter controller howto
+
+.. _ALBA: http://www.cells.es/
+.. _ANKA: http://http://ankaweb.fzk.de/
+.. _ELETTRA: http://http://www.elettra.trieste.it/
+.. _ESRF: http://www.esrf.eu/
+.. _FRMII: http://www.frm2.tum.de/en/index.html
+.. _HASYLAB: http://hasylab.desy.de/
+.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
+.. _SOLEIL: http://www.synchrotron-soleil.fr/
+
+.. _Tango: http://www.tango-controls.org/
+.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
+.. _PyTango: http://packages.python.org/PyTango/
+.. _Taurus: http://packages.python.org/taurus/
+.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
+.. _Qt: http://qt.nokia.com/products/
+.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
+.. _PyQwt: http://pyqwt.sourceforge.net/
+.. _Python: http://www.python.org/
+.. _IPython: http://ipython.org/
+.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
+.. _Qub: http://www.blissgarden.org/projects/qub/
+.. _numpy: http://numpy.scipy.org/
+.. _SPEC: http://www.certif.com/
+.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/howto_pseudomotorcontroller.rst b/doc/source/devel/howto_controllers/howto_pseudomotorcontroller.rst
new file mode 100644
index 00000000..b3a1a841
--- /dev/null
+++ b/doc/source/devel/howto_controllers/howto_pseudomotorcontroller.rst
@@ -0,0 +1,37 @@
+.. currentmodule:: sardana.pool.controller
+
+.. _sardana-pseudomotorcontroller-howto-basics:
+
+======================================
+How to write a pseudo motor controller
+======================================
+
+The basics
+----------
+
+.. todo:: document pseudo motor controller howto
+
+.. _ALBA: http://www.cells.es/
+.. _ANKA: http://http://ankaweb.fzk.de/
+.. _ELETTRA: http://http://www.elettra.trieste.it/
+.. _ESRF: http://www.esrf.eu/
+.. _FRMII: http://www.frm2.tum.de/en/index.html
+.. _HASYLAB: http://hasylab.desy.de/
+.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
+.. _SOLEIL: http://www.synchrotron-soleil.fr/
+
+.. _Tango: http://www.tango-controls.org/
+.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
+.. _PyTango: http://packages.python.org/PyTango/
+.. _Taurus: http://packages.python.org/taurus/
+.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
+.. _Qt: http://qt.nokia.com/products/
+.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
+.. _PyQwt: http://pyqwt.sourceforge.net/
+.. _Python: http://www.python.org/
+.. _IPython: http://ipython.org/
+.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
+.. _Qub: http://www.blissgarden.org/projects/qub/
+.. _numpy: http://numpy.scipy.org/
+.. _SPEC: http://www.certif.com/
+.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/index.rst b/doc/source/devel/howto_controllers/index.rst
index fda6afa0..964f332d 100644
--- a/doc/source/devel/howto_controllers/index.rst
+++ b/doc/source/devel/howto_controllers/index.rst
@@ -1,1027 +1,32 @@
.. currentmodule:: sardana.pool.controller
-.. _pool-controller-howto:
+.. _sardana-controller-howto:
-==============================================================================
-Writting controllers
-==============================================================================
+===================
+Writing controllers
+===================
This chapter provides the necessary information to write controllers in sardana.
An overview of the pool controller concept can be found
-:ref:`here <pool-controller-overview>`.
+:ref:`here <sardana-controller-overview>`.
The complete controller :term:`API` can be found
-:ref:`here <pool-controller-api>`.
+:ref:`here <sardana-controller-api>`.
-What is a controller
-------------------------------------------------------------------------------
+First, the common interface to all controller types is explained. After, a
+detailed chapter will focus on each specific controller type:
-A controller in sardana is a piece of software capable of *translating*
-between the sardana :term:`API` and a specific hardware :term:`API`. Sardana
-expects a controller to obey a specific :term:`API` in order to be able to
-properly configure and operate with it. The hardware :term:`API` used by the
-controller could be anything, from a pure serial line to shared memory or a
-remote server written in Tango_, Taco_ or even EPICS_.
-
-Controllers can only be written in Python_ (in future also C++ will be
-possible). A controller **must** be a :term:`class` inheriting from one of the
-existing controller types:
-
-.. hlist::
- :columns: 3
-
- - :class:`MotorController`
- - :class:`IORegisterController`
- - :class:`CounterTimerController`
- - :class:`ZeroDController`
- - :class:`OneDController`
- - :class:`TwoDController`
-
- - :class:`PseudoMotorController`
- - :class:`PseudoCounterController`
-
-A controller is designed to incorporate a set of generic individual elements.
-Each element has a corresponding *axis*. For example, in a motor
-controller the elements will be motors, but in a counter/timer controller the
-elements will be experimental channels.
-
-Some controller classes are designed to target a specific type of hardware.
-Other classes of controllers, the *pseudo* classes, are designed to provide a
-high level view over a set of underlying lower level controller elements.
-
-We will focus first on writting low level hardware controllers since they
-share some of the :term:`API` and after on the *pseudo* controllers.
-
-.. _pool-motorcontroller-howto-basics:
-
-Motor controller - The basics
-------------------------------------------------------------------------------
-
-An example of a hypothetical *Springfield* motor controller will be build
-incrementaly from scratch to aid the explanation.
-The examples use a :mod:`springfieldlib` module which emulates a motor hardware
-access library.
-
-The :mod:`springfieldlib` can be downloaded from
-:download:`here <springfieldlib.py>`.
-
-The Springfield motor controller can be downloaded from
-:download:`here <sf_motor_ctrl.py>`.
-
-The following code describes a minimalistic *Springfield* base motor controller
-which is able to return both the state and position of a motor as well as move
-a motor to the desired position:
-
-.. literalinclude:: sf_motor_ctrl.py
- :pyobject: SpringfieldBaseMotorController
-
-This code is shown only to demonstrate the minimalistic controller :term:`API`.
-The next chapters will guide you on how to build a proper motor controller from
-scratch.
-
-Starting
-~~~~~~~~~
-
-The first thing to do is to import the necessary symbols from sardana library.
-As you will see, most symbols can be imported through the
-:mod:`sardana.pool.controller` module:
-
-.. code-block:: python
-
- import springfieldlib
-
- from sardana.pool.controller import MotorController
-
- class SpringfieldMotorController(MotorController):
- """A motor controller intended from demonstration purposes only"""
- pass
-
-The common :term:`API` to all low level controllers includes the set of methods
-to:
-
- #. construct the controller
- #. add/delete a controller element
- #. obtain the state of controller element(s)
-
-.. _pool-motorcontroller-howto-constructor:
-
-Constructor
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The constructor consists of the
-:meth:`~sardana.pool.controller.Controller.__init__` method. This method is
-called when you create a new controller of that type and every time the sardana
-server is started. It will also be called if the controller code has changed
-on the file and the new code is reloaded into sardana.
-
-It is **NOT** mandatory to override the :meth:`~sardana.pool.controller.Controller.__init__`
-from the :meth:`~sardana.pool.controller.MotorController` class. Do it only
-if you need to add some initialization code. If you do it, it is **very important**
-to follow the two rules:
-
- #. use the method signature: ``__init__(self, inst, props, *args, **kwargs)``
- #. always call the super class constructor
-
-The example shows how to implement a constructor:
-
-.. code-block:: python
- :emphasize-lines: 3
-
- class SpringfieldMotorController(MotorController):
-
- def __init__(self, inst, props, *args, **kwargs):
- super(SpringfieldMotorController, self).__init__(inst, props, *args, **kwargs)
-
- # initialize hardware communication
- self.springfield = springfieldlib.SpringfieldMotorHW()
-
- # do some initialization
- self._motors = {}
-
-.. _pool-motorcontroller-howto-adddelete:
-
-Add/Delete motor
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Two methods are called when creating or removing an element from a controller.
-These methods are :meth:`~sardana.pool.controller.Controller.AddDevice` and
-:meth:`~sardana.pool.controller.Controller.DeleteDevice`. The
-:meth:`~sardana.pool.controller.Controller.AddDevice` method is called when a
-new motor belonging to the controller is created in sardana. The
-:meth:`~sardana.pool.controller.Controller.DeleteDevice` method is
-called when a motor belonging to the controller is removed from sardana.
-The example shows an example how to implement these methods:
-
-.. code-block:: python
- :emphasize-lines: 3, 6
-
- class SpringfieldMotorController(MotorController):
-
- def AddDevice(self, axis):
- self._motors[axis] = True
-
- def DeleteDevice(self, axis):
- del self._motor[axis]
-
-The code in the example initializes/clears a certain item in the *_motors*
-dictionary that was previously created in the constructor. The specific code
-for your controller will probably be completely different.
-
-.. _pool-motorcontroller-howto-state:
-
-Get motor state
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To get the state of a motor, sardana calls the
-:meth:`~sardana.pool.controller.Controller.StateOne` method. This method
-receives an axis as parameter and should return a sequence of three values:
-
-- state (:obj:`~sardana.sardanadefs.State`)
-- status (:obj:`str`)
-- limit switches (:obj:`int`)
-
-The state should be a member of :obj:`~sardana.sardanadefs.State` (For backward
-compatibility reasons, it is also supported to return one of
-:class:`PyTango.DevState`). The status could be any string. The limit switches
-is a integer with bits representing the three possible limits: home, upper
-and lower. Sardana provides three constants which can be *or*\ed together to
-provide the desired limit switch:
-
-.. hlist::
- :columns: 4
-
- - :attr:`~MotorController.NoLimitSwitch`
- - :attr:`~MotorController.HomeLimitSwitch`
- - :attr:`~MotorController.UpperLimitSwitch`
- - :attr:`~MotorController.LowerLimitSwitch`
-
-To say both home and lower limit switches are active (rare!) you can do::
-
- limit_switches = MotorController.HomeLimitSwitch | MotorController.LowerLimitSwitch
-
-Here is an example of the possible implementation of
-:meth:`~sardana.pool.controller.Controller.StateOne`:
-
-.. code-block:: python
- :emphasize-lines: 11
-
- from sardana import State
-
- class SpringfieldMotorController(MotorController):
-
- StateMap = {
- 1 : State.On,
- 2 : State.Moving,
- 3 : State.Fault,
- }
-
- def StateOne(self, axis):
- springfield = self.springfield
- state = self.StateMap[ springfield.getState(axis) ]
- status = springfield.getStatus(axis)
-
- limit_switches = MotorController.NoLimitSwitch
- hw_limit_switches = springfield.getLimits(axis)
- if hw_limit_switches[0]:
- limit_switches |= MotorController.HomeLimitSwitch
- if hw_limit_switches[1]:
- limit_switches |= MotorController.UpperLimitSwitch
- if hw_limit_switches[2]:
- limit_switches |= MotorController.LowerLimitSwitch
- return state, status, limit_switches
-
-.. _pool-motorcontroller-howto-value:
-
-Get motor position
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To get the motor position, sardana calls the
-:meth:`~sardana.pool.controller.Readable.ReadOne` method. This method
-receives an axis as parameter and should return a valid position. Sardana
-interprets the returned position as a :term:`dial position`.
-
-Here is an example of the possible implementation of
-:meth:`~sardana.pool.controller.Readable.ReadOne`:
-
-.. code-block:: python
- :emphasize-lines: 3
-
- class SpringfieldMotorController(MotorController):
-
- def ReadOne(self, axis):
- position = self.springfield.getPosition(axis)
- return position
-
-.. _pool-motorcontroller-howto-move:
-
-Move a motor
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When an order comes for sardana to move a motor, sardana will call the
-:meth:`~sardana.pool.controller.Startable.StartOne` method. This method receives
-an axis and a position. The controller code should trigger the hardware motion.
-The given position is always the :term:`dial position`.
-
-Here is an example of the possible implementation of
-:meth:`~sardana.pool.controller.Startable.StartOne`:
-
-.. code-block:: python
- :emphasize-lines: 3
-
- class SpringfieldMotorController(MotorController):
-
- def StartOne(self, axis, position):
- self.springfield.move(axis, position)
-
-As soon as :meth:`~sardana.pool.controller.Startable.StartOne` is invoked,
-sardana expects the motor to be moving. It enters a high frequency motion
-loop which asks for the motor state through calls to
-:meth:`~sardana.pool.controller.Controller.StateOne`. It will keep the loop
-running as long as the controller responds with ``State.Moving``.
-If :meth:`~sardana.pool.controller.Controller.StateOne` raises an exception
-or returns something other than ``State.Moving``, sardana will assume the motor
-is stopped and exit the motion loop.
-
-For a motion to work properly, it is therefore, **very important** that
-:meth:`~sardana.pool.controller.Controller.StateOne` responds correctly.
-
-.. _pool-motorcontroller-howto-stop:
-
-Stop a motor
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-It is possible to stop a motor when it is moving. When sardana is ordered to
-stop a motor motion, it invokes the :meth:`~sardana.pool.controller.Stopable.StopOne`
-method. This method receives an axis parameter. The controller should make
-sure the desired motor is *gracefully* stopped, if possible, respecting the
-configured motion parameters (like deceleration and base_rate).
-
-Here is an example of the possible implementation of
-:meth:`~sardana.pool.controller.Stopable.StopOne`:
-
-.. code-block:: python
- :emphasize-lines: 3
-
- class SpringfieldMotorController(MotorController):
-
- def StopOne(self, axis):
- self.springfield.stop(axis)
-
-.. _pool-motorcontroller-howto-abort:
-
-Abort a motor
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-In a danger situation (motor moving a table about to hit a wall), it is
-desirable to abort a motion *as fast as possible*. When sardana is ordered to
-abort a motor motion, it invokes the :meth:`~sardana.pool.controller.Stopable.AbortOne`
-method. This method receives an axis parameter. The controller should make
-sure the desired motor is stopped as fast as it can be done, possibly losing
-track of position.
-
-Here is an example of the possible implementation of
-:meth:`~sardana.pool.controller.Stopable.AbortOne`:
-
-.. code-block:: python
- :emphasize-lines: 3
-
- class SpringfieldMotorController(MotorController):
-
- def AbortOne(self, axis):
- self.springfield.abort(axis)
-
-.. note::
-
- The default implementation of :meth:`~sardana.pool.controller.Stopable.StopOne`
- calls :meth:`~sardana.pool.controller.Stopable.AbortOne` so, if your
- controller cannot distinguish stopping from aborting, it is sufficient
- to implement :meth:`~sardana.pool.controller.Stopable.AbortOne`.
-
-.. _pool-motorcontroller-howto-standard-axis-attributes:
-
-Standard axis attributes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-By default, sardana expects every axis to have a set of attributes:
-
-- acceleration
-- deceleration
-- velocity
-- base rate
-- steps per unit
-
-To set and retrieve the value of these attributes, sardana invokes pair of
-methods: :meth:`~sardana.pool.controller.Controller.GetAxisPar`
-/:meth:`~sardana.pool.controller.Controller.SetAxisPar`
-
-Here is an example of the possible implementation:
-
-.. code-block:: python
- :emphasize-lines: 3, 18
-
- class SpringfieldMotorController(MotorController):
-
- def GetAxisPar(self, axis, name):
- springfield = self.springfield
- name = name.lower()
- if name == "acceleration":
- v = springfield.getAccelerationTime(axis)
- elif name == "deceleration":
- v = springfield.getDecelerationTime(axis)
- elif name == "base_rate":
- v = springfield.getMinVelocity(axis)
- elif name == "velocity":
- v = springfield.getMaxVelocity(axis)
- elif name == "step_per_unit":
- v = springfield.getStepPerUnit(axis)
- return v
-
- def SetAxisPar(self, axis, name, value):
- springfield = self.springfield
- name = name.lower()
- if name == "acceleration":
- springfield.setAccelerationTime(axis, value)
- elif name == "deceleration":
- springfield.setDecelerationTime(axis, value)
- elif name == "base_rate":
- springfield.setMinVelocity(axis, value)
- elif name == "velocity":
- springfield.setMaxVelocity(axis, value)
- elif name == "step_per_unit":
- springfield.setStepPerUnit(axis, value)
-
-.. seealso::
-
- :ref:`pool-motorcontroller-whattodo`
- What to do when your hardware motor controller doesn't support
- steps per unit
-
-.. _pool-motorcontroller-howto-extra-axis-attributes:
-
-Extra axis attributes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You can specify your controller to have extra attributes on each motor.
-
-Lets suppose our Springfield motor controller can do close loop on hardware.
-We could define an extra motor attribute on each axis that (de)actives close
-loop on demand.
-
-The first thing to do is to specify which are the extra attributes.
-This is done through the :attr:`~sardana.pool.controller.Controller.axis_attributes`.
-This is basically a dictionary were the keys are attribute names and the value
-is a dictionary describing the folowing properties for each attribute:
-
-===================== ========= ============================================ ======================================================= ===============================================
-config. parameter Mandatory Key Default value Example
-===================== ========= ============================================ ======================================================= ===============================================
-data type & format Yes :obj:`~sardana.pool.controller.Type` --- :obj:`int`
-data access No :obj:`~sardana.pool.controller.Access` :obj:`~sardana.pool.controller.Access.ReadWrite` :obj:`~sardana.pool.controller.Access.ReadOnly`
-description No :obj:`~sardana.pool.controller.Description` "" (empty string) "the motor encoder source"
-default value No :obj:`~sardana.pool.controller.DefaultValue` --- 12345
-getter method name No :obj:`~sardana.pool.controller.FGet` "get" + <name> "getEncoderSource"
-setter method name No :obj:`~sardana.pool.controller.FSet` "set" + <name> "setEncoderSource"
-memorize value No :obj:`~sardana.pool.controller.Memorize` :obj:`~sardana.pool.controller.Memorized` :obj:`~sardana.pool.controller.NotMemorized`
-max dimension size No :obj:`~sardana.pool.controller.MaxDimSize` Scalar: ``()``; 1D: ``(2048,)``; 2D: ``(2048, 2048)`` ``(2048,)``
-===================== ========= ============================================ ======================================================= ===============================================
-
-Here is an example of how to specify the scalar, boolean, read-write *CloseLoop*
-extra attribute in our the Springfield motor controller:
-
-.. code-block:: python
- :emphasize-lines: 6, 14, 17
-
- from sardana import DataAccess
- from sardana.pool.controller import Type, Description, DefaultValue, Access, FGet, FSet
-
- class SpringfieldMotorController(MotorController):
-
- axis_attributes = {
- "CloseLoop" : {
- Type : bool,
- Description : "(de)activates the motor close loop algorithm",
- DefaultValue : False,
- },
- }
-
- def getCloseLoop(self, axis):
- return self.springfield.isCloseLoopActive(axis)
-
- def setCloseLoop(self, axis, value):
- self.springfield.setCloseLoop(axis, value)
-
-When sardana needs to read the close loop value, it will first check if the
-controller has the method specified by the :obj:`~sardana.pool.controller.FGet`
-keyword (we didn't specify it in
-:attr:`~sardana.pool.controller.Controller.axis_attributes` so it defaults to
-*getCloseLoop*). It will then call this controller method which
-should return a value compatible with the attribute data type.
-
-As an alternative, to avoid filling the controller code with pairs of get/set
-methods, you can choose not to write the getCloseLoop and setCloseLoop methods.
-This will trigger sardana to call the
-:meth:`~sardana.pool.controller.Controller.GetAxisExtraPar`
-/:meth:`~sardana.pool.controller.Controller.SetAxisExtraPar` pair of methods.
-The disadvantage is you will end up with a forest of :keyword:`if` ...
-:keyword:`elif` ... :keyword:`else` statements. Here is the alternative
-implementation:
-
-.. code-block:: python
- :emphasize-lines: 6, 14, 18
-
- from sardana import DataAccess
- from sardana.pool.controller import Type, Description, DefaultValue, Access, FGet, FSet
-
- class SpringfieldMotorController(MotorController):
-
- axis_attributes = {
- "CloseLoop" : {
- Type : bool,
- Description : "(de)activates the motor close loop algorithm",
- DefaultValue : False,
- },
- }
-
- def GetAxisExtraPar(self, axis, parameter):
- if parameter == 'CloseLoop':
- return self.springfield.isCloseLoopActive(axis)
-
- def SetAxisExtraPar(self, axis, parameter, value):
- if parameter == 'CloseLoop':
- self.springfield.setCloseLoop(axis, value)
-
-Sardana gives you the choice: we leave it up to you to decide which is the
-better option for your specific case.
-
-.. _pool-motorcontroller-howto-extra-controller-attributes:
-
-Extra controller attributes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Besides extra attributes per axis, you can also define extra attributes at the
-controller level.
-In order to do that you have to specify the extra controller attribute(s) within
-the :attr:`~sardana.pool.controller.Controller.ctrl_attributes` member. The
-syntax for this dictionary is the same as the one used for
-:attr:`~sardana.pool.controller.Controller.axis_attributes`.
-
-Here is an example on how to specify a read-only float matrix attribute called
-*ReflectionMatrix* at the controller level:
-
-.. code-block:: python
-
- class SpringfieldMotorController(MotorController):
-
- ctrl_attributes = {
- "ReflectionMatrix" : {
- Type : ( (float,), ),
- Description : "The reflection matrix",
- Access : DataAccess.ReadOnly,
- },
- }
-
- def getReflectionMatrix(self):
- return ( (1.0, 0.0), (0.0, 1.0) )
-
-Or, similar to what you can do with axis attributes:
-
-.. code-block:: python
-
- class SpringfieldMotorController(MotorController):
-
- ctrl_attributes = \
- {
- "ReflectionMatrix" : {
- Type : ( (float,), ),
- Description : "The reflection matrix",
- Access : DataAccess.ReadOnly,
- },
- }
-
- def GetCtrlPar(self, name):
- if name == "ReflectionMatrix":
- return ( (1.0, 0.0), (0.0, 1.0) )
-
-.. _pool-motorcontroller-howto-controller-properties:
-
-Controller properties
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A more static form of attributes can be defined at the controller level.
-These *properties* are loaded into the controller at the time of object
-construction. They are accessible to your controller at any time but it is
-not possible for a user from outside to modify them.
-The way to define :attr:`~sardana.pool.controller.Controller.ctrl_properties` is
-very similar to the way you define extra axis attributes or extra controller
-attributes.
-
-Here is an example on how to specify a host and port properties:
-
-.. code-block:: python
-
- class SpringfieldMotorController(MotorController):
-
- ctrl_properties = \
- {
- "host" : {
- Type : str,
- Description : "host name"
- },
- "port" : {
- Type : int,
- Description : "port number",
- DefaultValue: springfieldlib.SpringfieldMotorHW.DefaultPort
- },
- }
-
- def __init__(self, inst, props, *args, **kwargs):
- super(SpringfieldMotorController, self).__init__(inst, props, *args, **kwargs)
-
- host = self.host
- port = self.port
-
- # initialize hardware communication
- self.springfield = springfieldlib.SpringfieldMotorHW(host=host, port=port)
-
- # do some initialization
- self._motors = {}
-
-As you can see from lines 15 and 16, to access your controller properties
-simply use ``self.<property name>``. Sardana assures that every property has a
-value. In our case, when a SpringfieldMotorController is created, if port
-property is not specified by the user (example: using the ``defctrl`` macro in
-spock), sardana assignes the default value
-``springfieldlib.SpringfieldMotorHW.DefaultPort``. On the other hand, since host
-has no default value, if it is not specified by the user, sardana will complain
-and fail to create and instance of SpringfieldMotorController.
-
-
-.. _pool-motorcontroller-howto-define-position:
-
-Define a position
-~~~~~~~~~~~~~~~~~
-
-Sometimes it is useful to reset the current position to a certain value.
-Imagine you are writting a controller for a hardware controller which handles
-stepper motors. When the hardware is asked for a motor position it will
-probably answer some value from an internal register which is
-incremented/decremented each time the motor goes up/down a step. Probably this
-value as physical meaning so the usual procedure is to move the motor to a known
-position (home switch, for example) and once there, set a meaningful position to
-the current position. Some motor controllers support reseting the internal
-register to the desired value. If your motor controller can do this the
-implementation is as easy as writting the
-:meth:`~sardana.pool.controller.MotorController.DefinePosition` and call the
-proper code of your hardware library to do it:
-
-.. code-block:: python
-
- class SpringfieldMotorController(MotorController):
-
- def DefinePosition(self, axis, position):
- self.springfield.setCurrentPosition(axis, position)
-
-.. seealso::
-
- :ref:`pool-motorcontroller-whattodo`
-
- What to do when your hardware motor controller doesn't support
- defining the position
-
-.. _pool-motorcontroller-howto-handle-errors:
-
-Handle errors
-~~~~~~~~~~~~~
-
-When you write a controller it is important to properly handle errors
-(example: motor power overload, hit a limit switch, lost of communication with
-the hardware).
-
-These are the two basic sardana rules you should have in mind:
-
-#. The exceptions which are not handled by the controller are handled by sardana,
- usually by re-raising the exception (when sardana runs as a Tango_ DS a
- translation is done from the Python_ exception to a Tango_ exception).
- The :meth:`~sardana.pool.controller.Controller.StateOne` method is handled a
- little differently: the state is set to ``Fault`` and the status will contain
- the exception information.
-
-#. When the methods which are supposed to return a value (like
- :meth:`~sardana.pool.controller.Controller.GetAxisPar`) don't return a value
- compatible with the expected data type (including :obj:`None`) a
- :exc:`TypeError` exception is thrown.
-
-In every method you should carefully choose how to do handle the possible
-exceptions/errors.
-
-Usually, catch and handle is the best technique since it is the code of your
-controller which knows exactly the workings of the hardware. You can
-discriminate errors and decide a proper handle for each. Essencially, this
-technique consists of:
-
-#. catching the error (if an exception: with :keyword: try ... :keyword:except
- clause, if an expected return of a function: with a keyword:`if` ...
- :keyword:`elif` ... :keyword:`else` statement, etc)
-
-#. raise a proper exception (could be the same exception that has been catched)
- or, if in :meth:`~sardana.pool.controller.Controller.StateOne`, return the
- apropriate error state (``Fault``, ``Alarm``) and a descriptive status.
-
-Here is an example: if the documentation of the underlying library says that:
-
- `reading the motor closeloop raises CommunicationFailed if it is not
- possible to communicate with the Springfield hardware`
-
- `reading the motor state raises MotorPowerOverload if the motors
- has a power overload or a MotorTempTooHigh when the motor
- temperature is too high`
-
-then you should handle the exception in the controller and return a proper
-state information::
-
- def getCloseLoop(self, axis):
- # Here the "proper exception" to raise in case of error is actually the
- # one that is raised from the springfield library so handling the
- # exception is transparent. Nice!
- return self.springfield.isCloseLoopActive(axis)
-
- def StateOne(self, axis):
- springfield = self.springfield
-
- try:
- state = self.StateMap[ springfield.getState(axis) ]
- status = springfield.getStatus(axis)
- except springfieldlib.MotorPowerOverload:
- state = State.Fault
- status = "Motor has a power overload"
- except springfieldlib.MotorTempTooHigh:
- temp = springfield.getTemperature(axis)
- state = State.Alarm
- status = "Motor temperature is too high (%f degrees)" % temp
-
- limit_switches = MotorController.NoLimitSwitch
- hw_limit_switches = springfield.getLimits(axis)
- if hw_limit_switches[0]:
- limit_switches |= MotorController.HomeLimitSwitch
- if hw_limit_switches[1]:
- limit_switches |= MotorController.UpperLimitSwitch
- if hw_limit_switches[2]:
- limit_switches |= MotorController.LowerLimitSwitch
- return state, status, limit_switches
-
-Hiding the exception is usually a **BAD** technique since it prevents the user
-from finding what was the cause of the problem. You should only use it in
-extreme cases (example: if there is a bug in sardana which crashes the server
-if you try to properly raise an exception, then you can **temporarely** use
-this technique until the bug is solved).
-
-Example::
-
- def getCloseLoop(self, axis):
- # BAD error handling technique
- try:
- return self.springfield.isCloseLoopActive(axis)
- except:
- pass
-
-.. _pool-motorcontroller-whattodo:
-
-What to do when...
-~~~~~~~~~~~~~~~~~~
-
-This chapter describes common difficult situations you may face when writting
-a motor controller in sardana, and possible solutions to solve them.
-
-*my controller doesn't support steps per unit*
- Many (probably, most) hardware motor controllers don't support steps per
- unit at the hardware level. This means that your sardana controller should
- be able to emulate steps per unit at the software level.
- This can be easily done, but it requires you to make some changes in your
- code.
-
- We will assume now that the Springfield motor controller doesn't support
- steps per unit feature. The first that needs to be done is to modify the
- :meth:`~sardana.pool.controller.Controller.AddDevice` method so it is able to
- to store the resulting conversion factor between the hardware read position
- and the position the should be returned (the *step_per_unit*).
- The :meth:`~sardana.pool.controller.Readable.ReadOne` also needs to be
- rewritten to make the proper calculation.
- Finally :meth:`~sardana.pool.controller.Controller.GetAxisPar` /
- :meth:`~sardana.pool.controller.Controller.SetAxisPar` methods need to
- be rewritten to properly get/set the step per unit value:
-
- .. code-block:: python
-
- class SpringfieldMotorController(MotorController):
-
- def AddDevice(self, axis):
- self._motor[axis] = dict(step_per_unit=1.0)
-
- def ReadOne(self, axis):
- step_per_unit = self._motor[axis]["step_per_unit"]
- position = self.springfield.getPosition(axis)
- return position / step_per_unit
-
- def GetAxisPar(self, axis, name):
- springfield = self.springfield
- name = name.lower()
- if name == "acceleration":
- v = springfield.getAccelerationTime(axis)
- elif name == "deceleration":
- v = springfield.getDecelerationTime(axis)
- elif name == "base_rate":
- v = springfield.getMinVelocity(axis)
- elif name == "velocity":
- v = springfield.getMaxVelocity(axis)
- elif name == "step_per_unit":
- v = self._motor[axis]["step_per_unit"]
- return v
-
- def SetAxisPar(self, axis, name, value):
- springfield = self.springfield
- name = name.lower()
- if name == "acceleration":
- springfield.setAccelerationTime(axis, value)
- elif name == "deceleration":
- springfield.setDecelerationTime(axis, value)
- elif name == "base_rate":
- springfield.setMinVelocity(axis, value)
- elif name == "velocity":
- springfield.setMaxVelocity(axis, value)
- elif name == "step_per_unit":
- self._motor[axis]["step_per_unit"] = value
-
-*my controller doesn't support defining the position*
- Some controllers may not be able to reset the position to a different value.
- In these cases, your controller code should be able to emulate such a
- feature.
- This can be easily done, but it requires you to make some changes in your
- code.
-
- We will now assume that the Springfield motor controller doesn't support
- steps per unit feature. The first that needs to be done is to modify the
- :meth:`~sardana.pool.controller.Controller.AddDevice` method so it is able
- to store the resulting offset between the hardware read position and the
- position the should be returned (the *define_position_offset*).
- The :meth:`~sardana.pool.controller.Readable.ReadOne` also needs to be
- rewritten to take the *define_position_offset* into account.
- Finally :meth:`~sardana.pool.controller.MotorController.DefinePosition`
- needs to be written to update the *define_position_offset* to the desired
- value:
-
- .. code-block:: python
-
- class SpringfieldMotorController(MotorController):
-
- def AddDevice(self, axis):
- self._motor[axis] = dict(define_position_offset=0.0)
-
- def ReadOne(self, axis):
- dp_offset = self._motor[axis]["define_position_offset"]
- position = self.springfield.getPosition(axis)
- return position + dp_offset
-
- def DefinePosition(self, axis, position):
- current_position = self.springfield.getPosition(axis)
- self._motor[axis]["define_position_offset"] = position - current_position
-
-Motor controller - Advanced topics
-------------------------------------------------------------------------------
-
-This chapter describes an extended :term:`API` that allows you to better
-synchronize motions involing more than one motor, as well as optimize
-hardware communication (in case the hardware interface also supports this).
-
-Often it is the case that the experiment/procedure the user runs requires to
-move more than one motor at the same time.
-Imagine that the user requires motor at axis 1 to be moved to 100mm and motor
-axis 2 to be moved to -20mm.
-Your controller will receive two consecutive calls to
-:meth:`~sardana.pool.controller.Startable.StartOne`:
-
-.. code-block:: python
-
- StartOne(1, 100)
- StartOne(2, -20)
+.. toctree::
+ :maxdepth: 1
-and each StartOne will probably connect to the hardware (through serial line,
-socket, Tango_ or EPICS_) and ask the motor to be moved.
-This will do the job but, there will be a slight desynchronization between the
-two motors because hardware call of motor 1 will be done before hardware call
-to motor 2.
-
-Sardana provides an extended *start motion* which gives you the possibility
-to improve the syncronization (and probably reduce communications) but your
-hardware controller must somehow support this feature as well.
-
-The complete start motion :term:`API` consists of four methods:
-
- - :meth:`~sardana.pool.controller.Startable.PreStartAll`
- - :meth:`~sardana.pool.controller.Startable.PreStartOne`
- - :meth:`~sardana.pool.controller.Startable.StartOne`
- - :meth:`~sardana.pool.controller.Startable.StartAll`
-
-Except for :meth:`~sardana.pool.controller.Startable.StartOne`, the
-implemenation of all other start methods is optional and their default
-implementation does nothing (:meth:`~sardana.pool.controller.Startable.PreStartOne`
-actually returns ``True``).
-
-So, actually, the complete algorithm for motor motion in sardana is::
-
- /FOR/ Each controller(s) implied in the motion
- - Call PreStartAll()
- /END FOR/
-
- /FOR/ Each motor(s) implied in the motion
- - ret = PreStartOne(motor to move, new position)
- - /IF/ ret is not true
- /RAISE/ Cannot start. Motor PreStartOne returns False
- - /END IF/
- - Call StartOne(motor to move, new position)
- /END FOR/
-
- /FOR/ Each controller(s) implied in the motion
- - Call StartAll()
- /END FOR/
-
-So, for the example above where we move two motors, the complete sequence of
-calls to the controller is:
-
-.. code-block:: python
-
- PreStartAll()
-
- if not PreStartOne(1, 100):
- raise Exception("Cannot start. Motor(1) PreStartOne returns False")
- if not PreStartOne(2, -20):
- raise Exception("Cannot start. Motor(2) PreStartOne returns False")
-
- StartOne(1, 100)
- StartOne(2, -20)
-
- StartAll()
-
-Sardana assures that the above sequence is never interrupted by other calls,
-like a call from a different user to get motor state.
-
-Suppose the springfield library tells us in the documentation that:
-
- ... to move multiple motors at the same time use::
-
- moveMultiple(seq<pair<axis, position>>)
-
- Example::
-
- moveMultiple([[1, 100], [2, -20]])
-
-We can modify our motor controller to take profit of this hardware feature:
-
-.. code-block:: python
-
- class SpringfieldMotorController(MotorController):
-
- def PreStartAll(self):
- # clear the local motion information dictionary
- self._moveable_info = []
-
- def StartOne(self, axis, position):
- # store information about this axis motion
- motion_info = axis, position
- self._moveable_info.append(motion_info)
-
- def StartAll(self):
- self.springfield.moveMultiple(self._moveable_info)
-
-A similar principle applies when sardana asks for the state and position of
-multiple axis. The two sets of methods are, in these cases:
-
-.. hlist::
- :columns: 2
-
- - :meth:`~sardana.pool.controller.Controller.PreStateAll`
- - :meth:`~sardana.pool.controller.Controller.PreStateOne`
- - :meth:`~sardana.pool.controller.Controller.StateAll`
- - :meth:`~sardana.pool.controller.Controller.StateOne`
- - :meth:`~sardana.pool.controller.Readable.PreReadAll`
- - :meth:`~sardana.pool.controller.Readable.PreReadOne`
- - :meth:`~sardana.pool.controller.Readable.ReadAll`
- - :meth:`~sardana.pool.controller.Readable.ReadOne`
-
-The main differences between these sets of methods and the ones from start motion
-is that :meth:`~sardana.pool.controller.Controller.StateOne` /
-:meth:`~sardana.pool.controller.Readable.ReadOne` methods are called **AFTER**
-the corresponding :meth:`~sardana.pool.controller.Controller.StateAll` /
-:meth:`~sardana.pool.controller.Readable.ReadAll` counterparts and they are
-expeced to return the state/position of the requested axis.
-
-The internal sardana algorithm to read position is::
-
- /FOR/ Each controller(s) implied in the reading
- - Call PreReadAll()
- /END FOR/
-
- /FOR/ Each motor(s) implied in the reading
- - PreReadOne(motor to read)
- /END FOR/
-
- /FOR/ Each controller(s) implied in the reading
- - Call ReadAll()
- /END FOR/
-
- /FOR/ Each motor(s) implied in the reading
- - Call ReadOne(motor to read)
- /END FOR/
-
-Here is an example assuming the springfield library tells us in the
-documentation that:
-
- ... to read the position of multiple motors at the same time use::
-
- getMultiplePosition(seq<axis>) -> dict<axis, position>
-
- Example::
-
- positions = getMultiplePosition([1, 2])
-
-The new improved code could look like this::
-
- class SpringfieldMotorController(MotorController):
-
- def PreRealAll(self):
- # clear the local position information dictionary
- self._position_info = []
-
- def PreReadOne(self, axis):
- self._position_info.append(axis)
-
- def ReadAll(self):
- self._positions = self.springfield.getMultiplePosition(self._position_info)
-
- def ReadOne(self, axis):
- return self._positions[axis]
-
-.. _ALBA: http://www.cells.es/
-.. _ANKA: http://http://ankaweb.fzk.de/
-.. _ELETTRA: http://http://www.elettra.trieste.it/
-.. _ESRF: http://www.esrf.eu/
-.. _FRMII: http://www.frm2.tum.de/en/index.html
-.. _HASYLAB: http://hasylab.desy.de/
-.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
-.. _SOLEIL: http://www.synchrotron-soleil.fr/
+ howto_controller
+ howto_motorcontroller
+ howto_countertimercontroller
+ howto_0dcontroller
+ howto_1dcontroller
+ howto_2dcontroller
+ howto_ioregistercontroller
+ howto_pseudomotorcontroller
+ howto_pseudocountercontroller
-.. _Tango: http://www.tango-controls.org/
-.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
-.. _PyTango: http://packages.python.org/PyTango/
-.. _Taurus: http://packages.python.org/taurus/
-.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
-.. _Qt: http://qt.nokia.com/products/
-.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
-.. _PyQwt: http://pyqwt.sourceforge.net/
-.. _Python: http://www.python.org/
-.. _IPython: http://ipython.org/
-.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
-.. _Qub: http://www.blissgarden.org/projects/qub/
-.. _numpy: http://numpy.scipy.org/
-.. _SPEC: http://www.certif.com/
-.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/sf_ct_ctrl.py b/doc/source/devel/howto_controllers/sf_ct_ctrl.py
new file mode 100644
index 00000000..de0201e9
--- /dev/null
+++ b/doc/source/devel/howto_controllers/sf_ct_ctrl.py
@@ -0,0 +1,116 @@
+##############################################################################
+##
+## This file is part of Sardana
+##
+## http://www.tango-controls.org/static/sardana/latest/doc/html/index.html
+##
+## Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## Sardana is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Sardana is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with Sardana. If not, see <http://www.gnu.org/licenses/>.
+##
+##############################################################################
+
+"""This file contains the code for an hypothetical Springfield counter/timer
+controller used in documentation"""
+
+import springfieldlib
+
+from sardana import State
+from sardana.pool.controller import CounterTimerController
+
+class SpringfieldBaseCounterTimerController(CounterTimerController):
+ """The most basic controller intended from demonstration purposes only.
+ This is the absolute minimum you have to implement to set a proper counter
+ controller able to get a counter value, get a counter state and do an
+ acquisition.
+
+ This example is so basic that it is not even directly described in the
+ documentation"""
+
+ MaxDevice = 128
+
+ def __init__(self, inst, props, *args, **kwargs):
+ """Constructor"""
+ super(SpringfieldBaseCounterTimerController, self).__init__(inst, props, *args, **kwargs)
+ self.springfield = springfieldlib.Springfield()
+
+ def ReadOne(self, axis):
+ """Get the specified motor position"""
+ return self.springfield.getValue(axis)
+
+ def StateOne(self, axis):
+ """Get the specified motor state"""
+ springfield = self.springfield
+ state = springfield.getState(axis)
+ if state == 1:
+ return State.On, "Counter is stopped"
+ elif state == 2:
+ return State.Moving, "Counter is running"
+ elif state == 3:
+ return State.Fault, "Counter has an error"
+
+ def StartOne(self, axis, position):
+ """Move the specified motor to the specified position"""
+ self.springfield.move(axis, position)
+
+ def StopOne(self, axis):
+ """Stop the specified motor"""
+ self.springfield.stop(axis)
+
+
+from sardana import DataAccess
+from sardana.pool.controller import Type, Description, DefaultValue, Access, FGet, FSet
+
+class SpringfieldCounterTimerController(CounterTimerController):
+
+ def __init__(self, inst, props, *args, **kwargs):
+ super(SpringfieldCounterTimerController, self).__init__(inst, props, *args, **kwargs)
+
+ # initialize hardware communication
+ self.springfield = springfieldlib.SpringfieldCounterHW()
+
+ # do some initialization
+ self._counters = {}
+
+ def AddDevice(self, axis):
+ self._counters[axis] = True
+
+ def DeleteDevice(self, axis):
+ del self._counters[axis]
+
+ StateMap = {
+ 1 : State.On,
+ 2 : State.Moving,
+ 3 : State.Fault,
+ }
+
+ def StateOne(self, axis):
+ springfield = self.springfield
+ state = self.StateMap[ springfield.getState(axis) ]
+ status = springfield.getStatus(axis)
+ return state, status
+
+ def ReadOne(self, axis):
+ value = self.springfield.getValue(axis)
+ return value
+
+ def StartOne(self, axis, position):
+ self.springfield.move(axis, position)
+
+ def StopOne(self, axis):
+ self.springfield.stop(axis)
+
+ def AbortOne(self, axis):
+ self.springfield.abort(axis)
+ \ No newline at end of file
diff --git a/doc/source/devel/howto_controllers/sf_motor_ctrl.py b/doc/source/devel/howto_controllers/sf_motor_ctrl.py
index 3c91e615..de711c88 100644
--- a/doc/source/devel/howto_controllers/sf_motor_ctrl.py
+++ b/doc/source/devel/howto_controllers/sf_motor_ctrl.py
@@ -43,7 +43,7 @@ class SpringfieldBaseMotorController(MotorController):
def __init__(self, inst, props, *args, **kwargs):
"""Constructor"""
super(SpringfieldBaseMotorController, self).__init__(inst, props, *args, **kwargs)
- self.springfield = springfieldlib.Springfield()
+ self.springfield = springfieldlib.SpringfieldMotorHW()
def ReadOne(self, axis):
"""Get the specified motor position"""
@@ -92,7 +92,7 @@ class SpringfieldMotorController(MotorController):
super(SpringfieldMotorController, self).__init__(inst, props, *args, **kwargs)
# initialize hardware communication
- self.springfield = springfieldlib.Springfield()
+ self.springfield = springfieldlib.SpringfieldMotorHW()
# do some initialization
self._motors = {}
@@ -101,7 +101,7 @@ class SpringfieldMotorController(MotorController):
self._motors[axis] = True
def DeleteDevice(self, axis):
- del self._motor[axis]
+ del self._motors[axis]
StateMap = {
1 : State.On,
diff --git a/doc/source/devel/howto_macros/index.rst b/doc/source/devel/howto_macros/index.rst
index d93443de..e0bc28bc 100644
--- a/doc/source/devel/howto_macros/index.rst
+++ b/doc/source/devel/howto_macros/index.rst
@@ -1,6 +1,6 @@
.. currentmodule:: sardana.macroserver.macro
-.. _macroserver-macro-howto:
+.. _sardana-macro-howto:
================
Writting macros
diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst
index 7f24e6c6..d6ed8649 100644
--- a/doc/source/devel/howto_macros/macros_general.rst
+++ b/doc/source/devel/howto_macros/macros_general.rst
@@ -4,14 +4,14 @@
.. currentmodule:: sardana.macroserver.macro
-.. _macroserver-macros-howto:
+.. _sardana-macros-howto:
===============
Writting macros
===============
This chapter provides the necessary information to write macros in sardana. The
-complete macro :term:`API` can be found :ref:`here <macroserver-macro-api>`.
+complete macro :term:`API` can be found :ref:`here <sardana-macro-api>`.
What is a macro
---------------
@@ -144,10 +144,10 @@ called *salute*. Just type in:
.. sourcecode:: spock
LAB-01-D01 [1]: edmac hello_world salute
- Openning salute.hello_world...
+ Opening salute.hello_world...
Editing...
-This will bring your favourite editor to life with a macro function template
+This will bring your favorite editor to life with a macro function template
code for the macro *hello_world*.
.. image:: ../../_static/macro_edit.png
@@ -167,10 +167,10 @@ answer 'y'.
.. _macro_function_writting:
-Writting a macro function
--------------------------
+Writing a macro function
+------------------------
-As metioned before, macros are just simple Python_ functions which have been
+As mentioned before, macros are just simple Python_ functions which have been
*labeled* as macros. In Python_, these labels are called *decorators*. Here is
the macro function version of *Hello, World!*::
@@ -317,7 +317,7 @@ The complete list of types distributed with sardana is made up by these five
simple types: ``Integer``, ``Float``, ``Boolean``, ``String``, ``Any``, plus
all available sardana interfaces (:obj:`~sardana.sardanadefs.Interface`)
-.. _macro_context:
+.. _sardana-macro-context:
Macro context
-------------
@@ -329,7 +329,7 @@ this parameter any name but usually, by convention it is called ``self``).
``self`` provides access to an extensive catalog of functions you can use in
your macro to do all kinds of things. The complete catalog of functions can be
-found :ref:`here <macroserver-macro-api>`.
+found :ref:`here <sardana-macro-api>`.
Let's say you want to write a macro that explicitly moves a known *theta* motor
to a certain position. You could write a macro which receives the motor as
@@ -345,7 +345,7 @@ that::
th.move(position)
self.output("Motor ended at %s", moveable.getPosition())
-.. _macro_calling:
+.. _sardana-macro-calling:
Calling other macros from inside your macro
-------------------------------------------
@@ -376,7 +376,7 @@ Here is the new version of *where_moveable* ::
self.mv(moveable, position)
self.output("%s is now at %s", moveable.getName(), moveable.getPosition())
-.. _macro_environment:
+.. _sardana-macro-environment:
Accessing environment
---------------------
@@ -408,7 +408,7 @@ outputs the new ``ScanID`` value:
scan_id = self.getEnv('ScanID')
self.output("ScanID is now %d", scan_id)
-.. _macro_logging:
+.. _sardana-macro-logging:
Logging
-------
@@ -446,12 +446,14 @@ Here is an example on how to write a logging information message::
self.output("Hello, World!")
self.info("Finished to executing %s", self.getName())
-.. seealso::
+.. KEEP COMMENTED WHILE CHAPTER IS NOT WRITTEN
+.. .. seealso::
- :ref:`log configuration <ms-configuration-log>`
- The sardana log configuration.
+.. :ref:`log configuration <sardana-macroserver-configuration-log>`
+.. The sardana log configuration.
+..
-.. _macro_reporting:
+.. _sardana-macro-reporting:
Reports
-------
@@ -459,8 +461,8 @@ Reports
Once the report facility has been properly configured, report messages can be
sent to the previously configured report file.
-There are several differences between :ref:`reporting <macro_reporting>` and
-:ref:`logging <macro_logging>`. The first difference is that log messages may
+There are several differences between :ref:`reporting <sardana-macro-reporting>` and
+:ref:`logging <sardana-macro-logging>`. The first difference is that log messages may
or may not be recorded, depending on the configured filters on the target
(example: log file). A report will always be recorded.
@@ -486,18 +488,18 @@ This would generate the following report message in the report file:
INFO 2012-07-18 09:39:34,943: this is an official report of macro 'lets_report'
+.. KEEP COMMENTED WHILE CHAPTER IS NOT WRITTEN
+.. .. seealso::
-.. seealso::
-
- :ref:`Report configuration <ms-configuration-report>`
- The sardana report configuration.
+.. :ref:`Report configuration <sardana-macroserver-configuration-report>`
+.. The sardana report configuration.
-.. _advanced_macro_calling:
+.. _sardana-advanced-macro-calling:
Advanced macro calls
--------------------
-As previously explained (see :ref:`calling macros <macro_calling>`), you can use
+As previously explained (see :ref:`calling macros <sardana-macro-calling>`), you can use
the Macro :term:`API` to call other macros from inside your own macro:
.. code-block:: python
@@ -560,9 +562,9 @@ the macro using :meth:`~Macro.data`:
print len(my_scan.data)
A set of macro call examples can be found
-:ref:`here <devel-macro-call-examples>`.
+:ref:`here <sardana-devel-macro-call-examples>`.
-.. _macro_class_writting:
+.. _sardana-macro-class-writting:
Writting a macro class
----------------------
@@ -589,7 +591,7 @@ macro. So, without further delay, here is the *Hello, World!* example::
def run(self):
print "Hello, World!"
-.. _macro_add_parameters:
+.. _sardana-macro-add-parameters:
Let's say you want to pass an integer parameter to your macro. All you have to
do is declare the parameter by using the :attr:`~Macro.param_def` Macro member::
@@ -609,9 +611,9 @@ do is declare the parameter by using the :attr:`~Macro.param_def` Macro member::
modify the :meth:`~Macro.run` method to support the new paramter(s).
A set of macro parameter examples can be found
-:ref:`here <devel-macro-parameter-examples>`.
+:ref:`here <sardana-devel-macro-parameter-examples>`.
-.. _macro_preparing:
+.. _sardana-macro-preparing:
Preparing your macro for execution
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -638,7 +640,7 @@ prepare HelloWorld to run only after year 1989:
def run(self):
print "Hello, World!"
-.. _macro_plotting:
+.. _sardana-macro-plotting:
Plotting
--------
@@ -717,7 +719,7 @@ And the resulting image (interactions=20, density=512):
A set of macro plotting examples can be found
-:ref:`here <devel-macro-plotting-examples>`.
+:ref:`here <sardana-devel-macro-plotting-examples>`.
Known plotting limitations
~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -742,7 +744,7 @@ Also consider that each time you plot the complete data to be plotted is sent
from the server to the client... so please avoid plotting arrays of 10,000,000
points!
-.. _macro_input:
+.. _sardana-macro-input:
Asking for user input
---------------------
@@ -775,7 +777,7 @@ In pure Python_, to ask for user input you can use the :func:`raw_input` (Python
The Macro :term:`API` provides a much more powerful version of
:meth:`~Macro.input` since it can accept a wide variaty of options.
-Similar to what happens with :ref:`macro_plotting`, when input is requested from
+Similar to what happens with :ref:`sardana-macro-plotting`, when input is requested from
inside a macro, the question will be sent to the client (example: spock) which
ordered the macro to be executed. At this time the macro is stopped waiting for
the client to answer. The client must "ask" the user for a proper value and the
@@ -1064,7 +1066,7 @@ to show in a input spin box::
self.output("You selected a %s of %f %s", label, peak, unit)
A set of macro input examples can be found
-:ref:`here <devel-macro-input-examples>`.
+:ref:`here <sardana-devel-macro-input-examples>`.
Showing progress in long macros
-------------------------------
diff --git a/doc/source/devel/howto_macros/scan_framework.rst b/doc/source/devel/howto_macros/scan_framework.rst
index 21108e47..ae2c9b24 100644
--- a/doc/source/devel/howto_macros/scan_framework.rst
+++ b/doc/source/devel/howto_macros/scan_framework.rst
@@ -1,7 +1,7 @@
.. currentmodule:: sardana.macroserver.macro
-.. _macroserver-macros-scanframework:
+.. _sardana-macros-scanframework:
==============
Scan Framework
@@ -23,7 +23,7 @@ and :class:`~sardana.macroserver.scan.CScan` for step and continuous scans,
respectively.
Creating a scan macro consists in writing a generic macro (see
-:ref:`the generic macro writing instructions <macroserver-macros-howto>`) in
+:ref:`the generic macro writing instructions <sardana-macros-howto>`) in
which an instance of :class:`~sardana.macroserver.scan.GScan` is created
(typically in the :meth:`~Macro.prepare` method) which is then invoked in the
:meth:`~Macro.run` method.
diff --git a/doc/source/devel/index.rst b/doc/source/devel/index.rst
index 16ad4576..51c94330 100644
--- a/doc/source/devel/index.rst
+++ b/doc/source/devel/index.rst
@@ -1,4 +1,4 @@
-.. _developers-guide-index:
+.. _sardana-developers-guide-index:
=================
Developer's Guide
diff --git a/doc/source/devel/overview/index.rst b/doc/source/devel/overview/index.rst
index 90cf73ce..7b0c46be 100644
--- a/doc/source/devel/overview/index.rst
+++ b/doc/source/devel/overview/index.rst
@@ -17,5 +17,7 @@ Overview
IO register <overview_IOR>
Counter/timer <overview_countertimer>
0D experiment channel <overview_0D>
+ 1D experiment channel <overview_1D>
+ 2D experiment channel <overview_2D>
Pseudo counter <overview_pseudocounter>
diff --git a/doc/source/devel/overview/overview_0D.rst b/doc/source/devel/overview/overview_0D.rst
index 02519429..e3d65535 100644
--- a/doc/source/devel/overview/overview_0D.rst
+++ b/doc/source/devel/overview/overview_0D.rst
@@ -1,6 +1,6 @@
.. currentmodule:: sardana.pool
-.. _pool-0d-overview:
+.. _sardana-0d-overview:
=======================
0D channel overview
@@ -10,7 +10,7 @@
.. seealso::
- :ref:`pool-0d-api`
+ :ref:`sardana-0d-api`
the 0D experiment channel :term:`API`
:class:`~sardana.tango.pool.ZeroDExpChannel.ZeroDExpChannel`
diff --git a/doc/source/devel/overview/overview_1D.rst b/doc/source/devel/overview/overview_1D.rst
new file mode 100644
index 00000000..f5bb6281
--- /dev/null
+++ b/doc/source/devel/overview/overview_1D.rst
@@ -0,0 +1,17 @@
+.. currentmodule:: sardana.pool
+
+.. _sardana-1d-overview:
+
+=======================
+1D channel overview
+=======================
+
+.. todo:: document 1D experiment channel overview
+
+.. seealso::
+
+ :ref:`sardana-1d-api`
+ the 1D experiment channel :term:`API`
+
+ :class:`~sardana.tango.pool.OneDExpChannel.OneDExpChannel`
+ the 1D experiment channel tango device :term:`API`
diff --git a/doc/source/devel/overview/overview_2D.rst b/doc/source/devel/overview/overview_2D.rst
new file mode 100644
index 00000000..c1fa37a7
--- /dev/null
+++ b/doc/source/devel/overview/overview_2D.rst
@@ -0,0 +1,17 @@
+.. currentmodule:: sardana.pool
+
+.. _sardana-2d-overview:
+
+=======================
+2D channel overview
+=======================
+
+.. todo:: document 2D experiment channel overview
+
+.. seealso::
+
+ :ref:`sardana-2d-api`
+ the 2D experiment channel :term:`API`
+
+ :class:`~sardana.tango.pool.TwoDExpChannel.TwoDExpChannel`
+ the 2D experiment channel tango device :term:`API`
diff --git a/doc/source/devel/overview/overview_IOR.rst b/doc/source/devel/overview/overview_IOR.rst
index 7f25b58b..1b5b0805 100644
--- a/doc/source/devel/overview/overview_IOR.rst
+++ b/doc/source/devel/overview/overview_IOR.rst
@@ -1,6 +1,6 @@
.. currentmodule:: sardana.pool
-.. _pool-ior-overview:
+.. _sardana-ior-overview:
=======================
I/O register overview
@@ -10,7 +10,7 @@ I/O register overview
.. seealso::
- :ref:`pool-ior-api`
+ :ref:`sardana-ior-api`
the I/O register :term:`API`
:class:`~sardana.tango.pool.IORegister.IORegister`
diff --git a/doc/source/devel/overview/overview_controller.rst b/doc/source/devel/overview/overview_controller.rst
index 2eb18f7a..3062457d 100644
--- a/doc/source/devel/overview/overview_controller.rst
+++ b/doc/source/devel/overview/overview_controller.rst
@@ -1,6 +1,6 @@
.. currentmodule:: sardana.pool.controller
-.. _pool-controller-overview:
+.. _sardana-controller-overview:
===================
Controller overview
@@ -72,6 +72,18 @@ These are the different types of controllers recognized by sardana:
integration).
Example: an electrometer
+
+:class:`OneDController`
+ This controller type is designed to control a device capable of supplying
+ 1D values. It has a very similar :term:`API` to :class:`CounterTimerController`
+
+ Example: an :term:`MCA`
+
+:class:`TwoDController`
+ This controller type is designed to control a device capable of supplying
+ 2D values. It has a very similar :term:`API` to :class:`CounterTimerController`
+
+ Example: a :term:`CCD`
:class:`PseudoMotorController`
A controller designed to export *virtual motors* that represent a new view
@@ -181,10 +193,10 @@ that is able to talk to a Newport motor controller::
.. seealso::
- :ref:`pool-controller-howto`
+ :ref:`sardana-controller-howto`
How to write controller :term:`plug-in`\s in sardana
- :ref:`pool-controller-api`
+ :ref:`sardana-controller-api`
the controller :term:`API`
:class:`~sardana.tango.pool.Controller.Controller`
diff --git a/doc/source/devel/overview/overview_countertimer.rst b/doc/source/devel/overview/overview_countertimer.rst
index e5487e51..be4c8d69 100644
--- a/doc/source/devel/overview/overview_countertimer.rst
+++ b/doc/source/devel/overview/overview_countertimer.rst
@@ -1,6 +1,6 @@
.. currentmodule:: sardana.pool
-.. _pool-countertimer-overview:
+.. _sardana-countertimer-overview:
=======================
Counter/timer overview
@@ -10,7 +10,7 @@ Counter/timer overview
.. seealso::
- :ref:`pool-countertimer-api`
+ :ref:`sardana-countertimer-api`
the counter/timer :term:`API`
:class:`~sardana.tango.pool.CTExpChannel.CTExpChannel`
diff --git a/doc/source/devel/overview/overview_macroserver.rst b/doc/source/devel/overview/overview_macroserver.rst
index e697cc81..7d95979b 100644
--- a/doc/source/devel/overview/overview_macroserver.rst
+++ b/doc/source/devel/overview/overview_macroserver.rst
@@ -1,15 +1,18 @@
-.. _macroserver-overview:
+.. _sardana-macroserver-overview:
-======================
+=====================
Macro Server overview
-======================
+=====================
The Macro Server object is the sardana server object which manages all high
level sardana objects related to macro execution, namely doors, macro libraries
and macros themselves.
-The Macro Server is exposed on the sardana server as a Tango_ device.
+The main purpose of the Macro Server is to run *macros*. Macros are just pieces
+of Python_ code (functions or classes) which reside in a macro library (Python_
+file). Macros can be written by anyone with knowledge of Python_.
+The Macro Server is exposed on the sardana server as a Tango_ device.
Through configuration, the Macro Server can be told to connect to a
Pool device. This is the most common configuration.
You can, however, tell the Macro Server to connect to more than one Pool device
@@ -50,9 +53,9 @@ value::
self.output("%s is now at %s", moveable, moveable.getPosition())
Information on how to write your own sardana macros can be found
-:ref:`here <macroserver-macros-howto>`.
+:ref:`here <sardana-macros-howto>`.
-The complete macro :term:`API` can be found :ref:`here <macroserver-macro-api>`.
+The complete macro :term:`API` can be found :ref:`here <sardana-macro-api>`.
.. _ALBA: http://www.cells.es/
.. _ANKA: http://http://ankaweb.fzk.de/
diff --git a/doc/source/devel/overview/overview_motor.rst b/doc/source/devel/overview/overview_motor.rst
index 0a915a12..0f5dd812 100644
--- a/doc/source/devel/overview/overview_motor.rst
+++ b/doc/source/devel/overview/overview_motor.rst
@@ -1,4 +1,4 @@
-.. _pool-motor-overview:
+.. _sardana-motor-overview:
.. currentmodule:: sardana.pool
@@ -25,7 +25,7 @@ The *motor* object is also exposed as a Tango_ device.
.. seealso::
- :ref:`pool-motor-api`
+ :ref:`sardana-motor-api`
the motor :term:`API`
:class:`~sardana.tango.pool.Motor.Motor`
diff --git a/doc/source/devel/overview/overview_pool.rst b/doc/source/devel/overview/overview_pool.rst
index 6c5d3021..93736eda 100644
--- a/doc/source/devel/overview/overview_pool.rst
+++ b/doc/source/devel/overview/overview_pool.rst
@@ -1,5 +1,5 @@
-.. _pool-overview:
+.. _sardana-pool-overview:
==============
Pool overview
diff --git a/doc/source/devel/overview/overview_pseudocounter.rst b/doc/source/devel/overview/overview_pseudocounter.rst
index 3c74dfd3..c628ac50 100644
--- a/doc/source/devel/overview/overview_pseudocounter.rst
+++ b/doc/source/devel/overview/overview_pseudocounter.rst
@@ -1,6 +1,6 @@
.. currentmodule:: sardana.pool
-.. _pool-pseudocounter-overview:
+.. _sardana-pseudocounter-overview:
=======================
Pseudo counter overview
@@ -10,7 +10,7 @@ Pseudo counter overview
.. seealso::
- :ref:`pool-pseudocounter-api`
+ :ref:`sardana-pseudocounter-api`
the pseudo counter :term:`API`
:class:`~sardana.tango.pool.PseudoCounter.PseudoCounter`
diff --git a/doc/source/devel/overview/overview_pseudomotor.rst b/doc/source/devel/overview/overview_pseudomotor.rst
index 325d5960..500e8aea 100644
--- a/doc/source/devel/overview/overview_pseudomotor.rst
+++ b/doc/source/devel/overview/overview_pseudomotor.rst
@@ -1,6 +1,6 @@
.. currentmodule:: sardana.pool
-.. _pool-pseudomotor-overview:
+.. _sardana-pseudomotor-overview:
=======================
Pseudo motor overview
@@ -10,7 +10,7 @@ Pseudo motor overview
.. seealso::
- :ref:`pool-pseudomotor-api`
+ :ref:`sardana-pseudomotor-api`
the pseudo motor :term:`API`
:class:`~sardana.tango.pool.PseudoMotor.PseudoMotor`
diff --git a/doc/source/users/faq.rst b/doc/source/users/faq.rst
index dd19878c..7079da13 100644
--- a/doc/source/users/faq.rst
+++ b/doc/source/users/faq.rst
@@ -21,7 +21,7 @@ installed:
* The Sardana device pool, macro server and tools
The complete sardana installation instructions can be found
-:ref:`here <getting-started>`.
+:ref:`here <sardana-getting-started>`.
How to work with Taurus_ :term:`GUI`?
-------------------------------------
@@ -57,7 +57,7 @@ The execution can be started from either:
How to write procedures?
------------------------
User written procedures are central to the Sardana SCADA_ system.
-Documentation how to write macros can be found :ref:`here <macroserver-macros-howto>`.
+Documentation how to write macros can be found :ref:`here <sardana-macros-howto>`.
Macro writers might also find the following documentation interesting:
* Documentation on how to debug macros can be found here **<LINK>**
@@ -66,7 +66,7 @@ Macro writers might also find the following documentation interesting:
and use many utilities provided. The macro :term:`API` can be found
:class:`here <MacroServer.macro.Macro>`.
* Documentation how to document your macros can be found
- :ref:`here <macroserver-macros-howto>`
+ :ref:`here <sardana-macros-howto>`
How to write scan procedures?
-----------------------------
@@ -81,7 +81,7 @@ Sardana is meant to be interfaced to all types of different hardware with all
types of control systems. For every new hardware item the specific behavior
has to be programmed by writing a controller code. The documentation how to
write Sardana controllers and pseudo controllers can be found
-:ref:`here <pool-controller-howto>`.
+:ref:`here <sardana-controller-howto>`.
This documentation also includes the :term:`API` which can be used to interface
to the specific hardware item.
@@ -115,7 +115,7 @@ and example code can be found here **<LINK>**
How to write your own Taurus widget?
------------------------------------
A tutorial of how to write your own Taurus widget can be found
-:ref:`here <screenshots>`.
+:ref:`here <sardana-screenshots>`.
How to work with the graphical GUI editor?
------------------------------------------
diff --git a/doc/source/users/getting_started/index.rst b/doc/source/users/getting_started/index.rst
index 5df7b78a..0d839d13 100644
--- a/doc/source/users/getting_started/index.rst
+++ b/doc/source/users/getting_started/index.rst
@@ -1,5 +1,5 @@
-.. _getting_started:
+.. _sardana-getting-started:
===============
Getting started
diff --git a/doc/source/users/getting_started/installing.rst b/doc/source/users/getting_started/installing.rst
index dc2654a2..1fac36f4 100644
--- a/doc/source/users/getting_started/installing.rst
+++ b/doc/source/users/getting_started/installing.rst
@@ -1,5 +1,5 @@
-.. _sardana_installing:
+.. _sardana-installing:
==========
Installing
@@ -28,7 +28,7 @@ Installing
python -c "import sardana; print sardana.Release.version"
You can also work from SVN trunk checkout
-(please look :ref:`here <working-from-svn>` for instructions).
+(please look :ref:`here <sardana-working-from-svn>` for instructions).
Windows installation shortcut
@@ -53,20 +53,20 @@ necessary to run sardana on your windows machine
#. Download and install latest `taurus`_ from `Taurus downdoad page <http://pypi.python.org/pypi/taurus>`_
#. Finally download and install latest sardana from `Sardana downdoad page <http://pypi.python.org/pypi/sardana>`_
-.. _working-from-svn:
+.. _sardana-working-from-svn:
Working from SVN
----------------
You can checkout sardana from SVN from the following location::
- svn co http://tango-cs.svn.sourceforge.net/svnroot/tango-cs/share/Sardana/trunk Sardana
+ svn co http://svn.code.sf.net/p/sardana/code/trunk Sardana
You can directly execute sardana binaries (Pool, MacroServer, Sardana or spock
from the command line)::
- homer@pc001:~$ cd Sardana
- homer@pc001:~/Sardana$ scripts/Sardana
+ homer@pc001:~/workspace$ cd Sardana
+ homer@pc001:~/workspace/Sardana$ scripts/Sardana
.. rubric:: Footnotes
@@ -74,7 +74,7 @@ from the command line)::
.. [1] This command requires super user previledges on linux systems. If your
user has them you can usually prefix the command with *sudo*:
``sudo easy_install -U sardana``. Alternatively, if you don't have
- adminstrator previledges, you can install locally in your user
+ administrator priviledges, you can install locally in your user
directory with: ``easy_install --user sardana``
In this case the executables are located at <HOME_DIR>/.local/bin. Make
sure the PATH is pointing there or you execute from there.
diff --git a/doc/source/users/getting_started/running_cli.rst b/doc/source/users/getting_started/running_cli.rst
index c962df7e..1a5ff09a 100644
--- a/doc/source/users/getting_started/running_cli.rst
+++ b/doc/source/users/getting_started/running_cli.rst
@@ -1,4 +1,4 @@
-.. _getting-started-running-cli:
+.. _sardana-getting-started-running-cli:
Running the client
----------------------------
@@ -52,14 +52,14 @@ sardana *macros*, hence from here on we will use the term *macro*). A *macro*
is basically a piece of code. You can write macros using the `Python`_ language
to do all sorts of things. The sky is the limit here!
-Sardana comes with a :ref:`catalog of macros<standard-macro-catalog>` that help
+Sardana comes with a :ref:`catalog of macros<sardana-standard-macro-catalog>` that help
users in a laboratory to run their experiments. Most of these *macros*
involve interaction with sardana elements like motors and experimental channels.
Therefore, the first step in a new sardana demo is to populate your system with
some elements. Fortunately, sardana comes with a *macro* called *sar_demo* that
does just that. To execute this *macro* just type on the command line
:class:`~sardana.macroserver.macros.demo.sar_demo`.
-You should get an ouput like this:
+You should get an output like this:
.. sourcecode:: spock
diff --git a/doc/source/users/getting_started/running_server.rst b/doc/source/users/getting_started/running_server.rst
index c02d035a..50382d84 100644
--- a/doc/source/users/getting_started/running_server.rst
+++ b/doc/source/users/getting_started/running_server.rst
@@ -1,4 +1,4 @@
-.. _getting-started-running-server:
+.. _sardana-getting-started-running-server:
Running Sardana as a tango server
---------------------------------
@@ -7,7 +7,7 @@ Running Sardana as a tango server
if you have Tango <= 7.2.6 without all patches applied, Sardana server
will not work due to a known bug. Please follow the instructions from
- :ref:`getting-started-running-servers-separately` instead.
+ :ref:`sardana-getting-started-running-servers-separately` instead.
Sardana is based on a client-server architecture. On the server part, sardana
can be setup with many different configurations. Advanced details on sardana
@@ -33,14 +33,14 @@ started. You should get an output like this::
DServer/Sardana/Lab-01 has no event channel defined in the database - creating it
That't it! You now have a running sardana server. Not very impressive, is it?
-The :ref:`getting-started-running-cli` chapter describes how to start up a
+The :ref:`sardana-getting-started-running-cli` chapter describes how to start up a
:term:`CLI` application called *spock* which connects to the sardana server you
have just started through an object of type *Door* called *Door_lab-01_1*.
You can therefore skip the next chapter and go directly to
-:ref:`getting-started-running-cli`.
+:ref:`sardana-getting-started-running-cli`.
-.. _getting-started-running-servers-separately:
+.. _sardana-getting-started-running-servers-separately:
Running Pool and MacroServer tango servers separately
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -49,7 +49,7 @@ Running Pool and MacroServer tango servers separately
You should only read this chapter if you are if you have Tango <= 7.2.6
without all patches applied. If you do, please follow in instructions from
- :ref:`getting-started-running-server` instead.
+ :ref:`sardana-getting-started-running-server` instead.
It is possible to separate sardana server into two different servers (in the
first sardana versions, this was actually the only way start the sardana
diff --git a/doc/source/users/index.rst b/doc/source/users/index.rst
index 7e817015..a137e8a0 100644
--- a/doc/source/users/index.rst
+++ b/doc/source/users/index.rst
@@ -1,4 +1,4 @@
-.. _users-guide-index:
+.. _sardana-users-guide-index:
============
User's Guide
diff --git a/doc/source/users/overview.rst b/doc/source/users/overview.rst
index 685248b1..53f983fa 100644
--- a/doc/source/users/overview.rst
+++ b/doc/source/users/overview.rst
@@ -109,7 +109,7 @@ this approach of *take what you need* has been implemented to foster the widest
range of collaborations. Almost all applications in the ALBA_ machine control
system have been created with this toolkit. Creating the applications out of
standard components has been proven to be extremely powerful. In the
-:ref:`screenshots_guis` chapter you can see some of the graphical user
+:ref:`sardana-screenshots-guis` chapter you can see some of the graphical user
interfaces used.
Configure – don’t program
diff --git a/doc/source/users/scan.rst b/doc/source/users/scan.rst
index 5d0248af..abaa35d2 100644
--- a/doc/source/users/scan.rst
+++ b/doc/source/users/scan.rst
@@ -8,10 +8,10 @@ Scans
=====
Perhaps the most used type of macro is the scan macros. In general terms, we
-call *scan* to a macro that moves one or more :ref:`motors <pool-motor-api>`
+call *scan* to a macro that moves one or more :ref:`motors <sardana-motor-api>`
and acquires data along the path of the motor(s).
-.. note:: Sardana provides a :ref:`Scan Framework <macroserver-macros-scanframework>`
+.. note:: Sardana provides a :ref:`Scan Framework <sardana-macros-scanframework>`
for developing scan macros so that the scan macros behave in a consistent way.
Unless otherwise specified, the following discussion applies to scan macros
based on such framework.
@@ -101,7 +101,7 @@ issues that should be considered.
In order to address the first two issues, the
-:ref:`scan framework <macroserver-macros-scanframework>` attempts the following:
+:ref:`scan framework <sardana-macros-scanframework>` attempts the following:
* If the motors support changing their velocity, Sardana will adjust the
velocities of the motors so that they all start and finish the required path
@@ -151,5 +151,5 @@ Some examples of continuous scan macros are:
.. seealso:: For more information about the implementation details of the scan
macros in Sardana, see
- :ref:`scan framework <macroserver-macros-scanframework>`
+ :ref:`scan framework <sardana-macros-scanframework>`
diff --git a/doc/source/users/screenshots.rst b/doc/source/users/screenshots.rst
index 94740a75..ef10d8a4 100644
--- a/doc/source/users/screenshots.rst
+++ b/doc/source/users/screenshots.rst
@@ -2,7 +2,7 @@
.. highlight:: python
:linenothreshold: 4
-.. _screenshots:
+.. _sardana-screenshots:
============
Screenshots
@@ -37,7 +37,7 @@ Sardana oriented graphical user interfaces
TaurusGUI with synoptic and macro panel
-.. _screenshots_guis:
+.. _sardana-screenshots-guis:
Graphical user interface screen shots
-------------------------------------
diff --git a/doc/source/users/standard_macro_catalog.rst b/doc/source/users/standard_macro_catalog.rst
index 4635deb1..b64fc623 100644
--- a/doc/source/users/standard_macro_catalog.rst
+++ b/doc/source/users/standard_macro_catalog.rst
@@ -1,5 +1,5 @@
-.. _standard-macro-catalog:
+.. _sardana-standard-macro-catalog:
=======================
Standard macro catalog