Source code for crappy.blocks.generator

# coding: utf-8

from time import time, sleep

from .block import Block
from . import generator_path
from .._global import CrappyStop


[docs]class Generator(Block): """This block is used to generate a signal. It can be used to drive a machine. This block can take inputs, and each path can use these inputs to take decisions. """
[docs] def __init__(self, path: list = None, freq: float = 200, cmd_label: str = 'cmd', cycle_label: str = 'cycle', cmd: float = 0, repeat: bool = False, trig_link: str = None, spam: bool = False, verbose: bool = False, end_delay: float = 2) -> None: """Sets the args and initializes parent class. Args: path (:obj:`list`, optional): It must be a :obj:`list` of :obj:`dict`, each dict providing the parameters to generate the path. Each dict MUST have a key ``type``. Note: The Generator will then instantiate a :ref:`generator path` with all the other keys as `kwargs`, adding the current ``cmd`` and the time. On each round, it will call :meth:`Path.get_cmd` method, passing data until it raise :exc:`StopIteration`. It will then skip to the next path. When all paths are over, it will stop Crappy by raising :exc:`CrappyStop` unless ``repeat`` is set to :obj:`True`. If so, it will start over indefinitely. freq (:obj:`float`, optional): The frequency of the block. If set and positive, the generator will try to send the command at this frequency (in `Hz`). Else, it will go as fast as possible. It relies on the :ref:`Block` `freq` control scheme. cmd_label (:obj:`str`, optional): The label of the command to send in the links cycle_label (:obj:`str`, optional): cmd (:obj:`float`, optional): The first value of the command. repeat (:obj:`bool`, optional): Loop over the paths or stop when done ? trig_link (:obj:`str`, optional): If given, the block will wait until data is received through the input link with this label. If :obj:`None`, it will try loop at ``freq``. spam (:obj:`bool`, optional): If :obj:`True`, the value will be sent on each loop. Else, it will only send it if it was updated or we reached a new step. verbose (:obj:`bool`, optional): if :obj:`True`, displays a message when switching to the next path. end_delay (:obj:`float`, optional): The delay to wait for before raising the :exc:`CrappyStop` exception at the end of the path. This is meant to let enough time to the other blocks to properly terminate. """ Block.__init__(self) self.niceness = -5 self.freq = freq self.cmd_label = cmd_label self.cycle_label = cycle_label self.cmd = cmd self.repeat = repeat self.trig_link = trig_link self.spam = spam self.verbose = verbose self.end_delay = end_delay if path is None: path = [] self.path = path assert all([hasattr(generator_path, d['type']) for d in self.path]), \ "Invalid path in signal generator:" + \ str(filter(lambda s: not hasattr(generator_path, s['type']), self.path)) self.labels = ['t(s)', self.cmd_label, self.cycle_label]
[docs] def prepare(self) -> None: self.path_id = -1 # Will be incremented to 0 on first next_path if self.trig_link is not None: self.to_get = list(range(len(self.inputs))) self.to_get.remove(self.trig_link) self.last_t = time() self.last_path = -1 self.next_path()
def next_path(self) -> None: self.path_id += 1 if self.path_id >= len(self.path): if self.repeat: self.path_id = 0 else: print("Signal generator terminated!") sleep(self.end_delay) # Block.stop_all() raise CrappyStop("Signal Generator terminated") if self.verbose: print("[Signal Generator] Next step({}):".format(self.path_id), self.path[self.path_id]) kwargs = {'cmd': self.cmd, 'time': self.last_t} kwargs.update(self.path[self.path_id]) del kwargs['type'] name = self.path[self.path_id]['type'].capitalize() # Instantiating the new path class for the next step self.current_path = getattr(generator_path, name)(**kwargs)
[docs] def begin(self) -> None: self.send([self.last_t - self.t0, self.cmd, self.path_id]) self.current_path.t0 = self.t0
def loop(self) -> None: if self.trig_link is not None: da = self.inputs[self.trig_link].recv_chunk() data = self.get_all_last(self.to_get) data.update(da) else: data = self.get_all_last() data[self.cmd_label] = [self.cmd] # Add my own cmd to the dict try: cmd = self.current_path.get_cmd(data) except StopIteration: self.next_path() return # If next_path returns None, do not update cmd if cmd is not None and cmd is not self.cmd: self.cmd = cmd self.send([self.last_t - self.t0, self.cmd, self.path_id]) self.last_path = self.path_id elif self.last_path != self.path_id: self.send([self.last_t - self.t0, self.cmd, self.path_id]) self.last_path = self.path_id elif self.spam: self.send([self.last_t - self.t0, self.cmd, self.path_id]) self.last_t = time()