Commit eadf1a3d authored by Matias Guijarro's avatar Matias Guijarro Committed by Sebastien Petitdemange
Browse files

measurement: renamed CounterBase -> SamplingCounter

parent a48b7869
......@@ -12,11 +12,11 @@ Examples::
from random import random
from bliss.common.measurement import CounterBase
from bliss.common.measurement import SamplingCounter
# Write a new counter and counting
class MyCounter(CounterBase):
class MyCounter(SamplingCounter):
def read(self):
return random()*1000.
......@@ -37,7 +37,7 @@ Examples::
# Overwriting the default measurement for your counter class
class MyCounter(CounterBase):
class MyCounter(SamplingCounter):
Measurement = SingleMeasurement
......@@ -200,108 +200,77 @@ class FullMeasurement(Measurement):
Measurement._add_value(self, value, timestamp)
self.__data.append((value, timestamp))
class CounterBase(object):
"""
Base class for counters.
When defining a new sub-class you are only obliged to overwrite the
:meth:`read` method which should return the value that was read.
If your read source also provides a timestamp (ex: tango), you can
overwrite the :meth:`read_timestamp` method instead. It should
return a tuple with a value and a timestamp.
By default, counting uses the :class:`Measurement` class which will read
read as fast as it can. The measurement value obtained from a :meth:`count`
will then be an average of all values.
You can override the default behavior for your own class by pointing
`Measurement` to your desired class (the measurement class must be able
to be constructed without arguments).
class GroupedReadMixin(object):
def __init__(self, controller):
self.__controller_ref = weakref.ref(controller)
@property
def controller(self):
return self.__controller_ref()
@property
def id(self):
return id(self.controller)
You can also override the behavior of a specific :meth:`count` call
by providing a measurement argument.
"""
def prepare(self, *counters):
pass
#: default measurement class
Measurement = Measurement
def start(self, *counters):
pass
class ReadAllHandler(object):
def name(self):
"""
Should return a human readable name
"""
raise NotImplementedError
def id(self) :
"""
Should return a unique id to be able to group Counters per ReadAllHandler
"""
raise NotImplementedError
def read_all(self,*counter_name):
"""
this method should return a list of reads values in the same order
as the counter_name
"""
raise NotImplementedError
def end(self, *counters):
pass
def __init__(self, controller, name):
class Counter(object):
def __init__(self,name,controller,default_read_all_handler = None):
self.__name = name
self.__controller = weakref.proxy(controller) if controller is not None else None
if hasattr(controller,'read_all') and default_read_all_handler:
self.__default_read_all_handler = default_read_all_handler(controller)
else:
self.__default_read_all_handler = None
@property
def name(self):
return self.__name
@property
def controller(self):
return self.__controller
return self.__controller_ref() if self.__controller_ref is not None else None
def read_all_handler(self):
"""
Should return a handler which is has the interface of CounterBase.ReadAllHandler.
Should return a handler which is has the interface of SamplingCounter.ReadAllHandler.
This Handler will be used to group counters to read all values at once.
"""
if hasattr(self.__controller,'read_all'):
return DefaultReadAllHandler(self.__controller)
if self.__default_read_all_handler:
return self.__default_read_all_handler
raise NotImplementedError
def read(self):
"""Overwrite in your class to provide a useful counter class"""
raise NotImplementedError
def read_timestamp(self):
"""
Read the value and timestamp. Default implementation calls
:meth:`read` and a timestamp just after the read.
"""
value = self.read()
return value, time.time()
class SamplingCounter(Counter):
class GroupedReadHandler(GroupedReadMixin):
def read(self, *counters):
"""
this method should return a list of reads values in the same order
as counters
"""
raise NotImplementedError
def count(self, time=None, measurement=None):
"""
Count for the specified time.
def __init__(self, name, controller):
Counter.__init__(self,name,controller,DefaultSamplingReadAllHandler)
def read(self):
handler = self.read_all_handler()
try:
handler.prepare(self)
return handler.read_all(self)[0]
finally:
handler.end(self)
:return: a measurement object representing the count that was made
:rtype: :class:`MeasurementBase`
"""
meas = measurement or self.Measurement()
for reading in meas(time):
reading.value, reading.timestamp = self.read_timestamp()
return meas
class DefaultReadAllHandler(CounterBase.ReadAllHandler):
class DefaultSamplingCounterGroupedReadHandler(SamplingCounter.GroupedReadHandler):
"""
Default read all handler for controller which have read_all method
"""
def __init__(self,controller):
if isinstance(controller,weakref.ProxyType):
self.__controller = controller
else:
self.__controller = weakref.proxy(controller)
@property
def name(self):
return self.__controller.name
def id(self):
return id(self.__controller)
def read_all(self,*counter_name):
return self.__controller.read_all(*counter_name)
def read(self, *counters):
return self.controller.read_all(*counters)
......@@ -26,8 +26,9 @@ from bliss.common.axis import MotionEstimation
from bliss.common.temperature import Input, Output, TempControllerCounter
from bliss.common.task_utils import *
from bliss.common.motor_group import Group
from bliss.common.measurement import CounterBase
from bliss.common.measurement import SamplingCounter
from bliss.scanning.acquisition.counter import CounterAcqDevice
from bliss.scanning.chain import AcquisitionChain
from bliss.scanning import scan as scan_module
from bliss.scanning.acquisition.timer import SoftwareTimerMaster
......@@ -93,7 +94,7 @@ def default_chain(chain, scan_pars):
if isinstance(cnt, (Input, Output)):
cnt = TempControllerCounter(cnt.name, cnt)
if isinstance(cnt, CounterBase):
if isinstance(cnt, SamplingCounter):
try:
read_all_handler = cnt.read_all_handler()
except NotImplementedError:
......
......@@ -14,16 +14,16 @@ import gevent
import gevent.event
import math
from bliss.common import log
from bliss.common.measurement import CounterBase
from bliss.common.measurement import SamplingCounter
from bliss.common.utils import with_custom_members
class TempControllerCounter(CounterBase):
class TempControllerCounter(SamplingCounter):
""" Implements access to counter object for
Input and Output type objects
"""
def __init__(self, name, parent):
CounterBase.__init__(self, parent, name)
SamplingCounter.__init__(self, name, parent)
self.parent = parent
def read(self):
......
......@@ -85,7 +85,7 @@ import collections
import numpy
import gevent
from bliss.common.measurement import CounterBase
from bliss.common.measurement import SamplingCounter
from bliss.comm.util import get_interface
from bliss.config.settings import HashSetting
from bliss.comm.exceptions import CommunicationError
......@@ -121,11 +121,11 @@ class KeithleySCPI(BaseDeviceSCPI):
super(KeithleySCPI, self).__init__(*args, **kwargs)
class Sensor(CounterBase):
class Sensor(SamplingCounter):
def __init__(self, config, controller):
name = config['name']
CounterBase.__init__(self, controller, name)
SamplingCounter.__init__(self, name, controller)
self.config = config
self.address = int(config['address'])
self.index = self.address - 1
......
......@@ -72,7 +72,7 @@ import collections
import gevent.lock
from bliss.comm.util import get_comm
from bliss.common.measurement import CounterBase
from bliss.common.measurement import SamplingCounter
BROADCAST_ADDR = 0
......@@ -326,10 +326,11 @@ PT_PPRINT_TEMPLATE = """\
status: {pt.init_info.status}"""
class Counter(CounterBase):
class KellerCounter(SamplingCounter):
def __init__(self, controller, name, channel, unit=None):
CounterBase.__init__(self, controller, name)
def __init__(self, name, controller, channel, unit=None):
SamplingCounter.__init__(self, name, controller)
self.controller = controller
self.channel = channel
self.unit = unit
......@@ -433,7 +434,7 @@ class PressureTransmitter(object):
def __create_counter(self, name, channel='P1'):
cname, unit = self._CHANNEL_MAP[channel.upper()]
return Counter(self, name, cname, unit=unit)
return KellerCounter(name, self, cname, unit=unit)
def pprint(self):
print(PT_PPRINT_TEMPLATE.format(pt=self))
......
......@@ -6,15 +6,15 @@
# Distributed under the GNU LGPLv3. See LICENSE for more info.
from bliss.common.task_utils import cleanup, error_cleanup, task
from bliss.common.measurement import CounterBase, AverageMeasurement
from bliss.common.measurement import SamplingCounter, AverageMeasurement
from bliss.common.greenlet_utils import protect_from_kill
import time
import gevent
import socket
class LSCounter(CounterBase):
def __init__(self, parent, name, index):
CounterBase.__init__(self, parent, parent.name+'.'+name)
class LSCounter(SamplingCounter):
def __init__(self, name, parent, index):
SamplingCounter.__init__(self, parent.name+'.'+name, parent)
self.parent = parent
self.index = index
......@@ -53,11 +53,11 @@ class ls335(object):
@property
def A(self):
return LSCounter(self, "A", 0)
return LSCounter("A", self, 0)
@property
def B(self):
return LSCounter(self, "B", 1)
return LSCounter("B", self, 1)
def _read(self, acq_time=None):
self.acquisition_event.clear()
......
......@@ -6,15 +6,15 @@
# Distributed under the GNU LGPLv3. See LICENSE for more info.
from bliss.common.task_utils import cleanup, error_cleanup, task
from bliss.common.measurement import CounterBase
from bliss.common.measurement import SamplingCounter
from bliss.common import Actuator
from bliss.comm.Exporter import *
import time
import numpy
class md3photodiode(CounterBase, Actuator):
class md3photodiode(SamplingCounter, Actuator):
def __init__(self, name, config):
CounterBase.__init__(self, None, name)
SamplingCounter.__init__(self, name, None)
Actuator.__init__(self)
self.host, self.port = config.get("exporter_address").split(":")
......
......@@ -5,13 +5,13 @@
# Copyright (c) 2016 Beamline Control Unit, ESRF
# Distributed under the GNU LGPLv3. See LICENSE for more info.
from bliss.common.measurement import CounterBase
from bliss.common.measurement import SamplingCounter
import random
from gevent import sleep
class simulation_diode(CounterBase):
class simulation_diode(SamplingCounter):
def __init__(self, name, config):
CounterBase.__init__(self, None, name)
SamplingCounter.__init__(self, name, None)
def read(self):
sleep(0.01) # simulate hw reading
......
......@@ -6,13 +6,13 @@
# Distributed under the GNU LGPLv3. See LICENSE for more info.
from bliss.common.task_utils import cleanup, error_cleanup, task
from bliss.common.measurement import CounterBase
from bliss.common.measurement import SamplingCounter
import PyTango.gevent
import time
class tango_attr_as_counter(CounterBase):
class tango_attr_as_counter(SamplingCounter):
def __init__(self, name, config):
CounterBase.__init__(self, None, name)
SamplingCounter.__init__(self, name, None)
tango_uri = config.get("uri")
self.__control = PyTango.gevent.DeviceProxy(tango_uri)
self.attribute = config.get("attr_name")
......
......@@ -7,17 +7,15 @@
from bliss.common.task_utils import cleanup, error_cleanup, task
from bliss.common.utils import add_property
from bliss.common.measurement import CounterBase
from bliss.common.measurement import SamplingDevice
from bliss.common import Actuator
import gevent
from gevent import event
import PyTango.gevent
import numpy
class BpmCounter(CounterBase):
def __init__(self, parent, name, index):
CounterBase.__init__(self, parent, parent.name+'.'+name)
self.parent = parent
def __init__(self, name, controller, index):
SamplingDevice.__init__(self, controller.name+'.'+name, controller)
self.index = index
def read(self):
......@@ -71,7 +69,7 @@ class tango_bpm(object):
self.__control.LedOff,
lambda: self.__control.LedStatus > 0)
def diode_current(*args):
return BpmCounter(self, "diode_current", "_read_diode_current")
return BpmCounter("diode_current", self, "_read_diode_current")
add_property(self, "diode_current", diode_current)
def diode_actuator(*args):
return self.__diode_actuator
......@@ -92,23 +90,23 @@ class tango_bpm(object):
@property
def x(self):
return BpmCounter(self, "x", 1)
return BpmCounter("x", self, 1)
@property
def y(self):
return BpmCounter(self, "y", 2)
return BpmCounter("y", self, 2)
@property
def intensity(self):
return BpmCounter(self, "intensity", 3)
return BpmCounter("intensity", self, 3)
@property
def fwhm_x(self):
return BpmCounter(self, "fwhm_x", 4)
return BpmCounter("fwhm_x", self, 4)
@property
def fwhm_y(self):
return BpmCounter(self, "fwhm_y", 5)
return BpmCounter("fwhm_y", self, 5)
@property
def last_acq(self):
......
......@@ -6,16 +6,16 @@
# Distributed under the GNU LGPLv3. See LICENSE for more info.
from bliss.common.task_utils import cleanup, error_cleanup, task
from bliss.common.measurement import CounterBase, SingleMeasurement
from bliss.common.measurement import SamplingCounter, SingleMeasurement
import PyTango.gevent
import time
class tango_fe(CounterBase):
class tango_fe(SamplingCounter):
Measurement = SingleMeasurement
def __init__(self, name, config):
CounterBase.__init__(self, None, name)
SamplingCounter.__init__(self, name, None)
tango_uri = config.get("uri")
self.__control = PyTango.gevent.DeviceProxy(tango_uri)
self.attribute = config.get("attr_name")
......
......@@ -6,14 +6,14 @@
# Distributed under the GNU LGPLv3. See LICENSE for more info.
from bliss.common.task_utils import cleanup, error_cleanup, task
from bliss.common.measurement import CounterBase
from bliss.common.measurement import SamplingCounter
import PyTango.gevent
import time
import numpy
class tango_keithley(CounterBase):
class tango_keithley(SamplingCounter):
def __init__(self, name, config):
CounterBase.__init__(self, None, name)
SamplingCounter.__init__(self, name, None)
tango_uri = config["uri"]
self.__control = PyTango.gevent.DeviceProxy(tango_uri)
......
......@@ -10,7 +10,7 @@ import ctypes
import sys
import struct
import socket
from bliss.common.measurement import CounterBase
from bliss.common.measurement import SamplingCounter
from bliss.common.utils import add_property
from bliss.comm.modbus import ModbusTcp
......@@ -464,13 +464,13 @@ class _WagoController:
else:
print 'Module %d' % (m)
class WagoCounter(CounterBase):
def __init__(self, parent, name, index=None):
class WagoCounter(SamplingCounter):
def __init__(self, name, parent, index=None):
if index is None:
CounterBase.__init__(self, parent, name)
SamplingCounter.__init__(self, name, parent)
else:
CounterBase.__init__(self, parent, parent.name+'.'+name)
SamplingCounter.__init__(self, parent.name+'.'+name, parent)
self.index = index
self.parent = parent
self.cntname = name
......@@ -534,7 +534,7 @@ class wago(object):
else:
for i, name in enumerate(self.cnt_names):
self.cnt_dict[name] = i
add_property(self, name, WagoCounter(self, name, i))
add_property(self, name, WagoCounter(name, self, i))
def connect(self):
self.controller = WagoController(self.wago_ip)
......@@ -568,7 +568,7 @@ class wago(object):
else:
return self.get(*self.cnt_names)
def read_all(self,*counter_name):
cnt_name = [n.replace(self.name + '.','') for n in counter_name]
result = self.get(*cnt_name)
def read_all(self,*counters):
cnt_names = [cnt.name.replace(self.name + '.','') for cnt in counters]
result = self.get(*cnt_names)
return result if isinstance(result,list) else [result]
......@@ -10,7 +10,7 @@ import time
from gevent import event,sleep
from bliss.common.event import dispatcher
from ..chain import AcquisitionDevice,AcquisitionChannel
from bliss.common.measurement import CounterBase
from bliss.common.measurement import SamplingCounter
class CounterAcqDevice(AcquisitionDevice):
SIMPLE_AVERAGE,TIME_AVERAGE,INTEGRATE = range(3)
......@@ -39,7 +39,7 @@ class CounterAcqDevice(AcquisitionDevice):
start_once=start_once,
**keys)
self._count_time = count_time
if not isinstance(counter,CounterBase.ReadAllHandler):
if not isinstance(counter,SamplingCounter.ReadAllHandler):
self.channels.append(AcquisitionChannel(counter.name,numpy.double, (1,)))
self._nb_acq_points = 0
self._event = event.Event()
......@@ -47,6 +47,7 @@ class CounterAcqDevice(AcquisitionDevice):
self._ready_event = event.Event()
self._ready_flag = True
self.__mode = mode
self.__counters_list = list()
@property
def mode(self):
......@@ -56,6 +57,7 @@ class CounterAcqDevice(AcquisitionDevice):
self.__mode = value
def add_counter_to_read(self,counter):
self.__counters_list.append(counter)
self.channels.append(AcquisitionChannel(counter.name,numpy.double, (1,)))
def prepare(self):
......@@ -86,9 +88,9 @@ class CounterAcqDevice(AcquisitionDevice):
def reading(self):
counter_name = [x.name for x in self.channels]
if isinstance(self.device,CounterBase.ReadAllHandler):
if isinstance(self.device, SamplingCounter.GroupedReadHandler):
def read():
return numpy.array(self.device.read_all(*counter_name),
return numpy.array(self.device.read(*self.__counters_list),
dtype=numpy.double)
else: # read_all
def read():
......
......@@ -223,7 +223,7 @@ def get_object_type(obj):
return "motor"
# is it a counter?
if isinstance(obj, measurement.CounterBase):
if isinstance(obj, measurement.SamplingCounter):
return "counter"
# has it in/out capability?
......@@ -250,7 +250,7 @@ def get_objects_by_type(objects_dict):
motors[name]=obj
# is it a counter?
if isinstance(obj, measurement.CounterBase):
if isinstance(obj, measurement.SamplingCounter):
counters[name]=obj
else:
if not inspect.ismodule(obj):
......@@ -260,7 +260,7 @@ def get_objects_by_type(objects_dict):
pass
else:
for member_name, member in obj_dict.iteritems():
if isinstance(member, measurement.CounterBase):
if isinstance(member, measurement.SamplingCounter):
counters["%s.%s" % (name, member_name)]=member
# has it in/out capability?
......
......@@ -12,14 +12,14 @@ import unittest
import gevent
from bliss.common.measurement import CounterBase
from bliss.common.measurement import SamplingCounter
from bliss.common.measurement import SingleMeasurement, FullMeasurement
class RandomCounter(CounterBase):
class RandomCounter(SamplingCounter):
def __init__(self, name, range=(0., 1000.), nap=1E-3):
CounterBase.__init__(self, None, name)
SamplingCounter.__init__(self, None, name)
self.range = range
self.nb_reads = 0
self.nap = nap
......