class RamperIOC(PVGroup):
    """
    An IOC for executing ramps of pv_setpoints

    """
    pv_sp = pvproperty(
        value=25.0,
        doc='pv setpoint',
    )

    pv_sp_rate = pvproperty(
        value=0.0,
        doc='pv setpoint change rate',
    )

    go = pvproperty(
        value=0,
        doc='flag indicating whether ramping is actually taking place')

    time_elapsed = pvproperty(
        value=0.0,
        doc=
        'timer for measuring the elapsed time since the beginning of the program'
    )

    pause = pvproperty(value=0,
                       doc='flag indicating whether ramping is paused')

    time_paused = pvproperty(value=0.0,
                             doc='timer for measuring the paused time')

    tprog = pvproperty(value=[0.0, 60.0],
                       doc='time array of the ramp program',
                       max_length=25)

    pvprog = pvproperty(value=[25.0, 25.0],
                        doc='pv setpoint array of the ramp program',
                        max_length=25)

    dwell = pvproperty(value=0.05, doc="dwell time for the pv setpoint update")

    safety_timer = pvproperty(
        value=0.0,
        doc='timer for stopping the program in case if ipython session dies')

    safety_thresh = pvproperty(value=10.0,
                               doc='time threshold for turning the heater off')

    pid_enable_name = pvproperty(value='',
                                 dtype=ChannelType.STRING,
                                 doc='pv name for pid enable')

    pid_output_name = pvproperty(
        value='',
        dtype=ChannelType.STRING,
        # dtype=_LongStringChannelType.LONG_STRING,
        doc='pv name for pid output')

    # pid_output_name_ext = pvproperty(
    #     value='',
    #     dtype=ChannelType.STRING,
    #     # dtype=_LongStringChannelType.LONG_STRING,
    #     doc='pv name for pid output (extension)'
    # )

    pv_test = pvproperty(value=0, doc='pv for output testing')
    _previous_elapsed_time = None
    time_start = None
    pid_enable = None
    pid_output = None

    @pv_sp.startup
    async def pv_sp(self, instance, async_lib):
        """This is a startup hook which periodically updates the value."""
        rate = 0
        while True:
            await self.pv_sp_rate.write(rate)
            await async_lib.sleep(self.dwell.value)
            if self.go.value == 1:
                if self.time_start is None:
                    self.time_start = ttime.time()

                if self.pause.value == 0:

                    await self.time_elapsed.write(ttime.time() -
                                                  self.time_start)
                    dt = self.time_elapsed.value - self.time_paused.value

                    if dt < np.max(self.tprog.value):
                        pv_sp = np.interp(dt, self.tprog.value,
                                          self.pvprog.value)
                    else:
                        pv_sp = self.pvprog.value[-1]

                    if self._previous_elapsed_time is not None:
                        rate = (pv_sp - self.pv_sp.value) / (
                            dt - self._previous_elapsed_time) * 60

                    self._previous_elapsed_time = dt
                    await instance.write(value=pv_sp)
                else:
                    rate = 0

            else:
                self.time_start = None
                await self.time_elapsed.write(0.0)
                await self.time_paused.write(0.0)
                rate = 0

    @pid_enable_name.startup
    async def pid_enable_name(self, instance, async_lib):
        while self.pid_enable_name.value == '':
            await async_lib.sleep(1)

        self.pid_enable = EpicsSignal(self.pid_enable_name.value,
                                      name='pid_enable')

        def subscription(value, **kwargs):
            if value == 0:
                if self.pid_output is not None:
                    if self.pid_output.get() != 0:
                        self.pid_output.put(0)

        self.pid_enable.subscribe(subscription)

    @pid_output_name.startup
    async def pid_output_name(self, instance, async_lib):
        while (self.pid_output_name.value == ''):
            await async_lib.sleep(1)

        self.pid_output = EpicsSignal(self.pid_output_name.value,
                                      name='pid_output')

        def subscription(value, **kwargs):
            if value != 0:
                if self.pid_enable is not None:
                    if self.pid_enable.get() == 0:
                        self.pid_output.put(0)

        self.pid_output.subscribe(subscription)

    @safety_timer.startup
    async def safety_timer(self, instance, async_lib):
        while self.safety_timer.value < self.safety_thresh.value:
            safety_timer = self.safety_timer.value + 1
            await instance.write(value=safety_timer)
            await async_lib.sleep(1)
        if self.pid_enable is not None:
            self.pid_enable.put(0)

    @time_paused.startup
    async def time_paused(self, instance, async_lib):
        while True:
            cur_time = ttime.time()
            if self.pause.value == 1:
                while True:
                    if self.pause.value == 0:
                        break
                    await async_lib.sleep(self.dwell.value / 2)
                time_paused = self.time_paused.value + (ttime.time() -
                                                        cur_time)
                await instance.write(value=time_paused)

            await async_lib.sleep(self.dwell.value)
예제 #2
0
from ophyd import (EpicsSignal, Signal)
from ophyd.utils.epics_pvs import record_field


def callback(sub_type=None, timestamp=None, value=None, **kwargs):
    logger.info('[callback] [%s] (type=%s) value=%s', timestamp, sub_type,
                value)

    # Test that the monitor dispatcher works (you cannot use channel access in
    # callbacks without it)
    logger.info('[callback] caget=%s', rw_signal.get())

logger = config.logger

motor_record = config.motor_recs[0]
val = record_field(motor_record, 'VAL')
rbv = record_field(motor_record, 'RBV')

rw_signal = EpicsSignal(rbv, write_pv=val)
rw_signal.subscribe(callback, event_type=rw_signal.SUB_VALUE)
rw_signal.subscribe(callback, event_type=rw_signal.SUB_SETPOINT)

rw_signal.value = 2
time.sleep(1.)
rw_signal.value = 1
time.sleep(1.)

# You can also create a Python Signal:
sig = Signal(name='testing', value=10)
logger.info('Python signal: %s', sig)