/usr/lib/python2.7/dist-packages/sardana/tango/pool/Motor.py is in python-sardana 1.2.0-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 | #!/usr/bin/env python
##############################################################################
##
## 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/>.
##
##############################################################################
"""The sardana tango motor module"""
__all__ = ["Motor", "MotorClass"]
__docformat__ = 'restructuredtext'
import sys
import time
from PyTango import DevFailed, Except, DevVoid, DevShort, \
DevLong, DevDouble, DevBoolean, DispLevel, DevState, AttrQuality, \
READ, READ_WRITE, SCALAR, SPECTRUM
from taurus.core.util import DebugIt
from sardana import State, SardanaServer
from sardana.sardanautils import str_to_value
from sardana.sardanaattribute import SardanaAttribute
from sardana.pool.poolexception import PoolException
from sardana.tango.core.util import memorize_write_attribute, exception_str, \
to_tango_type_format, throw_sardana_exception
from PoolDevice import PoolElementDevice, PoolElementDeviceClass
class Motor(PoolElementDevice):
"""The tango motor device class. This class exposes through a tango device
the sardana motor (:class:`~sardana.pool.poolmotor.PoolMotor`).
.. rubric:: The states
The motor interface knows five states which are ON, MOVING, ALARM,
FAULT and UNKNOWN. A motor device is in MOVING state when it is
moving! It is in ALARM state when it has reached one of the limit
switches and is in FAULT if its controller software is not available
(impossible to load it) or if a fault is reported from the hardware
controller. The motor is in the UNKNOWN state if an exception occurs
during the communication between the pool and the hardware controller.
When the motor is in ALARM state, its status will indicate which limit
switches is active.
.. rubric:: The commands
The motor interface supports 3 commands on top of the Tango classical
Init, State and Status commands. These commands are summarized in the
following table:
============== ================ ================
Command name Input data type Output data type
============== ================ ================
Stop void void
Abort void void
DefinePosition Tango::DevDouble void
SaveConfig void void
============== ================ ================
- **Stop** : It stops a running motion. This command does not have input or
output argument.
- **Abort** : It aborts a running motion. This command does not have input or
output argument.
- **DefinePosition** : Loads a position into controller. It has one input
argument which is the new position value (a double). It is allowed only in
the ON or ALARM states. The unit used for the command input value is the
physical unit: millimeters or milli-radians. It is always an absolute
position.
- **SaveConfig** : Write some of the motor parameters in database. Today, it
writes the motor acceleration, deceleration, base_rate and velocity into
database as motor device properties. It is allowed only in the ON or ALARM
states
The classical Tango Init command destroys the motor and re-create it.
.. rubric:: The attributes
The motor interface supports several attributes which are summarized
in the following table:
============== ================= =========== ======== ========= ===============
Name Data type Data format Writable Memorized Operator/Expert
============== ================= =========== ======== ========= ===============
Position Tango::DevDouble Scalar R/W No * Operator
DialPosition Tango::DevDouble Scalar R No Expert
Offset Tango::DevDouble Scalar R/W Yes Expert
Acceleration Tango::DevDouble Scalar R/W No Expert
Base_rate Tango::DevDouble Scalar R/W No Expert
Deceleration Tango::DevDouble Scalar R/W No Expert
Velocity Tango::DevDouble Scalar R/W No Expert
Limit_Switches Tango::DevBoolean Spectrum R No Expert
SimulationMode Tango::DevBoolean Scalar R No Expert
Step_per_unit Tango::DevDouble Scalar R/W Yes Expert
Backlash Tango::DevLong Scalar R/W Yes Expert
============== ================= =========== ======== ========= ===============
- **Position** : This is read-write scalar double attribute. With the classical
Tango min and max_value attribute properties, it is easy to define
authorized limit for this attribute. See the definition of the
DialPosition and Offset attributes to get a precise definition of the
meaning of this attribute. It is not allowed to read or write this
attribute when the motor is in FAULT or UNKNOWN state. It is also not
possible to write this attribute when the motor is already MOVING.
The unit used for this attribute is the physical unit: millimeters or
milli-radian. It is always an **absolute position** .
- **DialPosition** : This attribute is the motor dial position. The following
formula links together the Position, DialPosition, Sign and Offset attributes:
Position = Sign * DialPosition + Offset
This allows to have the motor position centered around any position
defined by the Offset attribute (classically the X ray beam position).
It is a read only attribute. To set the motor position, the user has
to use the Position attribute. It is not allowed to read this
attribute when the motor is in FAULT or UNKNOWN mode. The unit used
for this attribute is the physical unit: millimeters or milli-radian.
It is also always an **absolute** position.
- **Offset** : The offset to be applied in the motor position computation. By
default set to 0. It is a memorized attribute. It is not allowed to
read or write this attribute when the motor is in FAULT, MOVING or
UNKNOWN mode.
- **Acceleration** : This is an expert read-write scalar double attribute.
This parameter value is written in database when the SaveConfig command is
executed. It is not allowed to read or write this attribute when the motor is
in FAULT or UNKNOWN state.
- **Deceleration** : This is an expert read-write scalar double attribute.
This parameter value is written in database when the SaveConfig command is
executed. It is not allowed to read or write this attribute when the motor is
in FAULT or UNKNOWN state.
- **Base_rate** : This is an expert read-write scalar double attribute. This
parameter value is written in database when the SaveConfig command is executed.
It is not allowed to read or write this attribute when the motor is in
FAULT or UNKNOWN state.
- **Velocity** : This is an expert read-write scalar double attribute.
This parameter value is written in database when the SaveConfig command is
executed. It is not allowed to read or write this attribute when the motor is
in FAULT or UNKNOWN state.
- **Limit_Switches** : Three limit switches are managed by this attribute.
Each of the switch are represented by a boolean value: False means inactive
while True means active. It is a read only attribute. It is not possible to
read this attribute when the motor is in UNKNOWN mode. It is a
spectrum attribute with 3 values which are:
- Data[0] : The Home switch value
- Data[1] : The Upper switch value
- Data[2] : The Lower switch value
- **SimulationMode** : This is a read only scalar boolean attribute. When set,
all motion requests are not forwarded to the software controller and then to
the hardware. When set, the motor position is simulated and is immediately
set to the value written by the user. To set this attribute, the user
has to used the pool device Tango interface. The value of the
position, acceleration, deceleration, base_rate, velocity and offset
attributes are memorized at the moment this attribute is set. When
this mode is turned off, if the value of any of the previously
memorized attributes has changed, it is reapplied to the memorized
value. It is not allowed to read this attribute when the motor is in
FAULT or UNKNOWN states.
- **Step_per_unit** : This is the number of motor step per millimeter or per
degree. It is a memorized attribute. It is not allowed to read or write this
attribute when the motor is in FAULT or UNKNOWN mode. It is also not
allowed to write this attribute when the motor is MOVING. The default
value is 1.
- **Backlash** : If this attribute is defined to something different than 0,
the motor will always stop the motion coming from the same mechanical
direction. This means that it could be possible to ask the motor to go
a little bit after the desired position and then to return to the
desired position. The attribute value is the number of steps the motor
will pass the desired position if it arrives from the "wrong"
direction. This is a signed value. If the sign is positive, this means
that the authorized direction to stop the motion is the increasing
motor position direction. If the sign is negative, this means that the
authorized direction to stop the motion is the decreasing motor
position direction. It is a memorized attribute. It is not allowed to
read or write this attribute when the motor is in FAULT or UNKNOWN
mode. It is also not allowed to write this attribute when the motor is
MOVING. Some hardware motor controllers are able to manage this
backlash feature. If it is not the case, the motor interface will
implement this behavior.
All the motor devices will have the already described attributes but
some hardware motor controller supports other features which are not
covered by this list of pre-defined attributes. Using Tango dynamic
attribute creation, a motor device may have extra attributes used to
get/set the motor hardware controller specific features. These are the
attributes specified on the controller with
:attr:`~sardana.pool.controller.Controller.axis_attribues`.
.. rubric:: The properties
- **Sleep_before_last_read** : This property exposes the motor
*instability time*. It defines the time in milli-second that the software
managing a motor movement will wait between it detects the end of the
motion and the last motor position reading.
.. rubric:: Getting motor state and limit switches using event
The simplest way to know if a motor is moving is to survey its state.
If the motor is moving, its state will be MOVING. When the motion is
over, its state will be back to ON (or ALARM if a limit switch has
been reached). The pool motor interface allows client interested by
motor state or motor limit switches value to use the Tango event
system subscribing to motor state change event. As soon as a motor
starts a motion, its state is changed to MOVING and an event is sent.
As soon as the motion is over, the motor state is updated ans another
event is sent. In the same way, as soon as a change in the limit
switches value is detected, a change event is sent to client(s) which
have subscribed to change event on the Limit_Switches attribute.
.. rubric:: Reading the motor position attribute
For each motor, the key attribute is its position. Special care has
been taken on this attribute management. When the motor is not moving,
reading the Position attribute will generate calls to the controller
and therefore hardware access. When the motor is moving, its position
is automatically read every 100 milli-seconds and stored in the Tango
polling buffer. This means that a client reading motor Position
attribute while the motor is moving will get the position from the
Tango polling buffer and will not generate extra controller calls. It
is also possible to get a motor position using the Tango event system.
When the motor is moving, an event is sent to the registered clients
when the change event criterion is true. By default, this change event
criterion is set to be a difference in position of 5. It is tunable on
a motor basis using the classical motor Position attribute abs_change
property or at the pool device basis using its DefaultMotPos_AbsChange
property. Anyway, not more than 10 events could be sent by second.
Once the motion is over, the motor position is made unavailable from
the Tango polling buffer and is read a last time after a tunable
waiting time (Sleep_bef_last_read property). A forced change event
with this value is sent to clients using events.
"""
def __init__(self, dclass, name):
"""Constructor"""
self.in_write_position = False
PoolElementDevice.__init__(self, dclass, name)
def init(self, name):
PoolElementDevice.init(self, name)
def _is_allowed(self, req_type):
return PoolElementDevice._is_allowed(self, req_type)
def get_motor(self):
return self.element
def set_motor(self, motor):
self.element = motor
motor = property(get_motor, set_motor)
def set_write_dial_position_to_db(self):
dial = self.motor.get_dial_position_attribute()
if dial.has_write_value():
data = dict(DialPosition=dict(__value=dial.w_value, __value_ts=dial.w_timestamp))
db = self.get_database()
db.put_device_attribute_property(self.get_name(), data)
def get_write_dial_position_from_db(self):
name = 'DialPosition'
db = self.get_database()
pos_props = db.get_device_attribute_property(self.get_name(), name)[name]
w_pos = pos_props["__value"][0]
_, _, attr_info = self.get_dynamic_attributes()[0][name]
w_pos = str_to_value(w_pos, attr_info.dtype, attr_info.dformat)
w_pos, w_ts = float(pos_props["__value"][0]), None
if "__value_ts" in pos_props:
w_ts = float(pos_props["__value_ts"][0])
return w_pos, w_ts
@DebugIt()
def delete_device(self):
PoolElementDevice.delete_device(self)
motor = self.motor
if motor is not None:
motor.remove_listener(self.on_motor_changed)
@DebugIt()
def init_device(self):
PoolElementDevice.init_device(self)
motor = self.motor
if motor is None:
full_name = self.get_full_name()
name = self.alias or full_name
self.motor = motor = \
self.pool.create_element(type="Motor", name=name,
full_name=full_name, id=self.Id, axis=self.Axis,
ctrl_id=self.Ctrl_id)
if self.instrument is not None:
motor.set_instrument(self.instrument)
# if in constructor, for all memorized no init attributes (position)
# let poolmotor know their write values
if self.in_constructor:
try:
w_pos, w_ts = self.get_write_dial_position_from_db()
self.in_write_position = True
try:
motor.set_write_position(w_pos, timestamp=w_ts)
finally:
self.in_write_position = False
except KeyError:
pass
if self.Sleep_bef_last_read > 0:
motor.set_instability_time(self.Sleep_bef_last_read / 1000.0)
motor.add_listener(self.on_motor_changed)
self.set_state(DevState.ON)
def on_motor_changed(self, event_source, event_type, event_value):
try:
self._on_motor_changed(event_source, event_type, event_value)
except not DevFailed:
msg = 'Error occurred "on_motor_changed(%s.%s): %s"'
exc_info = sys.exc_info()
self.error(msg, self.motor.name, event_type.name,
exception_str(*exc_info[:2]))
self.debug("Details", exc_info=exc_info)
def _on_motor_changed(self, event_source, event_type, event_value):
# during server startup and shutdown avoid processing element
# creation events
if SardanaServer.server_state != State.Running:
return
timestamp = time.time()
name = event_type.name.lower()
if name == "w_position" and not self.in_write_position:
self.debug("Storing dial set point: %s", self.motor.dial_position.w_value)
self.set_write_dial_position_to_db()
return
try:
attr = self.get_attribute_by_name(name)
except DevFailed:
return
quality = AttrQuality.ATTR_VALID
priority = event_type.priority
value, w_value, error = None, None, None
if name == "state":
value = self.calculate_tango_state(event_value)
elif name == "status":
value = self.calculate_tango_status(event_value)
else:
if isinstance(event_value, SardanaAttribute):
if event_value.error:
error = Except.to_dev_failed(*event_value.exc_info)
else:
value = event_value.value
timestamp = event_value.timestamp
else:
value = event_value
state = self.motor.get_state(propagate=0)
if name == "position":
w_value = event_source.get_position_attribute().w_value
if state == State.Moving:
quality = AttrQuality.ATTR_CHANGING
elif name == "dialposition" and state == State.Moving:
quality = AttrQuality.ATTR_CHANGING
self.set_attribute(attr, value=value, w_value=w_value,
timestamp=timestamp, quality=quality,
priority=priority, error=error, synch=False)
def always_executed_hook(self):
pass
def read_attr_hardware(self, data):
pass
def get_dynamic_attributes(self):
cache_built = hasattr(self, "_dynamic_attributes_cache")
std_attrs, dyn_attrs = \
PoolElementDevice.get_dynamic_attributes(self)
if not cache_built:
# For position attribute, listen to what the controller says for data
# type (between long and float)
pos = std_attrs.get('position')
if pos is not None:
_, data_info, attr_info = pos
ttype, _ = to_tango_type_format(attr_info.dtype)
data_info[0][0] = ttype
return std_attrs, dyn_attrs
def initialize_dynamic_attributes(self):
attrs = PoolElementDevice.initialize_dynamic_attributes(self)
detect_evts = "position", "dialposition",
non_detect_evts = "limit_switches", "step_per_unit", "offset", \
"sign", "velocity", "acceleration", "deceleration", "base_rate", \
"backlash"
for attr_name in detect_evts:
if attr_name in attrs:
self.set_change_event(attr_name, True, True)
for attr_name in non_detect_evts:
if attr_name in attrs:
self.set_change_event(attr_name, True, False)
def read_Position(self, attr):
motor = self.motor
use_cache = motor.is_in_operation() and not self.Force_HW_Read
state = motor.get_state(cache=use_cache, propagate=0)
position = motor.get_position(cache=use_cache, propagate=0)
if position.error:
Except.throw_python_exception(*position.exc_info)
quality = None
if state == State.Moving:
quality = AttrQuality.ATTR_CHANGING
self.set_attribute(attr, value=position.value, w_value=position.w_value,
quality=quality, priority=0,
timestamp=position.timestamp)
def write_Position(self, attr):
self.in_write_position = True
position = attr.get_write_value()
try:
self.info("write_Position(%s)", position)
try:
self.wait_for_operation()
except:
raise Exception("Cannot move: already in motion")
try:
self.motor.position = position
except PoolException, pe:
throw_sardana_exception(pe)
# manually store write dial position in the database
self.set_write_dial_position_to_db()
finally:
self.in_write_position = False
def read_Acceleration(self, attr):
attr.set_value(self.motor.get_acceleration(cache=False))
@memorize_write_attribute
def write_Acceleration(self, attr):
self.motor.acceleration = attr.get_write_value()
def read_Deceleration(self, attr):
attr.set_value(self.motor.get_deceleration(cache=False))
@memorize_write_attribute
def write_Deceleration(self, attr):
self.motor.deceleration = attr.get_write_value()
def read_Base_rate(self, attr):
attr.set_value(self.motor.get_base_rate(cache=False))
@memorize_write_attribute
def write_Base_rate(self, attr):
self.motor.base_rate = attr.get_write_value()
def read_Velocity(self, attr):
attr.set_value(self.motor.get_velocity(cache=False))
@memorize_write_attribute
def write_Velocity(self, attr):
self.motor.velocity = attr.get_write_value()
def read_Offset(self, attr):
attr.set_value(self.motor.get_offset(cache=False).value)
@memorize_write_attribute
def write_Offset(self, attr):
self.motor.offset = attr.get_write_value()
def read_DialPosition(self, attr):
motor = self.motor
use_cache = motor.is_in_operation() and not self.Force_HW_Read
state = motor.get_state(cache=use_cache, propagate=0)
dial_position = motor.get_dial_position(cache=use_cache, propagate=0)
if dial_position.error:
Except.throw_python_exception(*dial_position.exc_info)
quality = None
if state == State.Moving:
quality = AttrQuality.ATTR_CHANGING
self.set_attribute(attr, value=dial_position.value, quality=quality,
priority=0, timestamp=dial_position.timestamp)
def read_Step_per_unit(self, attr):
attr.set_value(self.motor.get_step_per_unit(cache=False))
@memorize_write_attribute
def write_Step_per_unit(self, attr):
step_per_unit = attr.get_write_value()
self.motor.step_per_unit = step_per_unit
def read_Backlash(self, attr):
attr.set_value(self.motor.get_backlash(cache=False))
@memorize_write_attribute
def write_Backlash(self, attr):
self.motor.backlash = attr.get_write_value()
def read_Sign(self, attr):
sign = self.motor.get_sign(cache=False).value
attr.set_value(sign)
@memorize_write_attribute
def write_Sign(self, attr):
self.motor.sign = attr.get_write_value()
def read_Limit_switches(self, attr):
motor = self.motor
use_cache = motor.is_in_operation() and not self.Force_HW_Read
limit_switches = motor.get_limit_switches(cache=use_cache)
self.set_attribute(attr, value=limit_switches.value, priority=0,
timestamp=limit_switches.timestamp)
def DefinePosition(self, argin):
self.motor.define_position(argin)
# update write value of position attribute
pos_attr = self.get_wattribute_by_name("position")
pos_attr.set_write_value(argin)
def is_DefinePosition_allowed(self):
if self.get_state() in (DevState.FAULT, DevState.MOVING,
DevState.UNKNOWN):
return False
return True
def SaveConfig(self):
raise NotImplementedError
def is_SaveConfig_allowed(self):
if self.get_state() in (DevState.FAULT, DevState.MOVING,
DevState.UNKNOWN):
return False
return True
def MoveRelative(self, argin):
raise NotImplementedError
def is_MoveRelative_allowed(self):
if self.get_state() in (DevState.FAULT, DevState.MOVING,
DevState.UNKNOWN):
return False
return True
def get_attributes_to_restore(self):
"""Make sure position is the last attribute to restore"""
restore_attributes = PoolElementDevice.get_attributes_to_restore(self)
try:
restore_attributes.remove('Position')
restore_attributes.append('Position')
except ValueError:
pass
return restore_attributes
is_Position_allowed = _is_allowed
is_Acceleration_allowed = _is_allowed
is_Deceleration_allowed = _is_allowed
is_Base_rate_allowed = _is_allowed
is_Velocity_allowed = _is_allowed
is_Offset_allowed = _is_allowed
is_DialPosition_allowed = _is_allowed
is_Step_per_unit_allowed = _is_allowed
is_Backlash_allowed = _is_allowed
is_Sign_allowed = _is_allowed
is_Limit_switches_allowed = _is_allowed
class MotorClass(PoolElementDeviceClass):
# Class Properties
class_property_list = {
}
# Device Properties
device_property_list = {
'Sleep_bef_last_read' : [DevLong,
"Number of mS to sleep before the last read during a motor "
"movement", 0],
'_Acceleration' : [DevDouble, "", -1],
'_Deceleration' : [DevDouble, "", -1],
'_Velocity' : [DevDouble, "", -1],
'_Base_rate' : [DevDouble, "", -1],
}
device_property_list.update(PoolElementDeviceClass.device_property_list)
# Command definitions
cmd_list = {
'DefinePosition' : [ [DevDouble, "New position"], [DevVoid, ""] ],
'SaveConfig' : [ [DevVoid, ""], [DevVoid, ""] ],
'MoveRelative' : [ [DevDouble, "amount to move"], [DevVoid, ""] ],
}
cmd_list.update(PoolElementDeviceClass.cmd_list)
# Attribute definitions
attr_list = {}
attr_list.update(PoolElementDeviceClass.attr_list)
standard_attr_list = {
'Position' : [ [ DevDouble, SCALAR, READ_WRITE ],
{ 'abs_change' : '1.0', } ],
'Acceleration' : [ [ DevDouble, SCALAR, READ_WRITE ],
{ 'Memorized' : "true", } ],
'Deceleration' : [ [ DevDouble, SCALAR, READ_WRITE ],
{ 'Memorized' : "true", } ],
'Base_rate' : [ [ DevDouble, SCALAR, READ_WRITE ],
{ 'Memorized' : "true",
'label' : 'Base rate', } ],
'Velocity' : [ [ DevDouble, SCALAR, READ_WRITE ],
{ 'Memorized' : "true", } ],
'Offset' : [ [ DevDouble, SCALAR, READ_WRITE ],
{ 'Memorized' : "true",
'Display level' : DispLevel.EXPERT } ],
'DialPosition' : [ [ DevDouble, SCALAR, READ ],
{ 'label' : "Dial position",
'Display level' : DispLevel.EXPERT } ],
'Step_per_unit': [ [ DevDouble, SCALAR, READ_WRITE],
{ 'Memorized' : "true",
'label' : "Steps p/ unit",
'Display level' : DispLevel.EXPERT } ],
'Backlash' : [ [ DevLong, SCALAR, READ_WRITE],
{ 'Memorized' : "true",
'Display level' : DispLevel.EXPERT } ],
'Sign' : [ [ DevShort, SCALAR, READ_WRITE],
{ 'Memorized' : "true",
'Display level' : DispLevel.EXPERT } ],
'Limit_switches': [ [ DevBoolean, SPECTRUM, READ, 3],
{ 'label' : "Limit switches (H,U,L)",
'description' : "This attribute is the motor "\
"limit switches state. It's an array with 3 \n"\
"elements which are:\n"\
"0 - The home switch\n"\
"1 - The upper limit switch\n"\
"2 - The lower limit switch\n"\
"False means not active. True means active" } ],
}
standard_attr_list.update(PoolElementDeviceClass.standard_attr_list)
def _get_class_properties(self):
ret = PoolElementDeviceClass._get_class_properties(self)
ret['Description'] = "Motor device class"
ret['InheritedFrom'].insert(0, 'PoolElementDevice')
return ret
|