class Temperature(Actor): """ Measure temperature. Takes the period of measurements, in seconds, as input. Outputs: centigrade : temperature, in centigrade """ @manage(['period', 'timer', 'temperature']) def init(self, period): self.period = period self.temperature = calvinsys.open(self, "io.temperature") self.timer = calvinsys.open(self, "sys.timer.once", period=0) @stateguard(lambda self: calvinsys.can_read(self.temperature) and calvinsys .can_write(self.timer)) @condition([], ['centigrade']) def read_measurement(self): value = calvinsys.read(self.temperature) # reset timer calvinsys.write(self.timer, self.period) return (value, ) @stateguard(lambda self: calvinsys.can_read(self.timer) and calvinsys. can_write(self.temperature)) @condition([], []) def start_measurement(self): # ack timer calvinsys.read(self.timer) # start measurement calvinsys.write(self.temperature, True) action_priority = (read_measurement, start_measurement) requires = ['io.temperature', 'sys.timer.once']
class Distance(Actor): """ Measure distance. Takes the frequency of measurements, in Hz, as input. Outputs: meters : distance, in meters """ @manage(['frequency']) def init(self, frequency): self.frequency = frequency self.setup() def setup(self): _log.info("setup") self._distance = calvinsys.open(self, "io.distance") self._timer = calvinsys.open(self, "sys.timer.repeating") calvinsys.write(self._timer, 1.0/self.frequency) def will_migrate(self): calvinsys.close(self._distance) calvinsys.close(self._timer) self._distance = None self._timer = None def did_migrate(self): self.setup() def will_end(self): if self._distance: calvinsys.close(self._distance) if self._timer : calvinsys.close(self._timer) @stateguard(lambda self: calvinsys.can_read(self._distance)) @condition([], ['meters']) def read_measurement(self): distance = calvinsys.read(self._distance) return (distance,) @stateguard(lambda self: calvinsys.can_read(self._timer) and calvinsys.can_write(self._distance)) @condition([], []) def start_measurement(self): calvinsys.read(self._timer) calvinsys.write(self._distance, True) action_priority = (read_measurement, start_measurement) requires = ['io.distance', 'sys.timer.repeating']
class Knob(Actor): """ Read a knob to see which way it turned. Outputs: direction: clockwise or anti-clockwise """ @manage([]) def init(self): self.setup() def setup(self): self._knob = calvinsys.open(self, "io.knob") def will_migrate(self): calvinsys.close(self._knob) self._knob = None def will_end(self): if self._knob: calvinsys.close(self._knob) def did_migrate(self): self.setup() @stateguard(lambda self: calvinsys.can_read(self._knob)) @condition([], ["direction"]) def trigger(self): return (calvinsys.read(self._knob), ) action_priority = (trigger, ) requires = ['io.knob'] test_calvinsys = {'io.knob': {'read': [-1, 1, 0, 1]}} test_set = [{'outports': {'direction': [-1, 1, 0, 1]}}]
class Accelerometer(Actor): """ Measure the acceleration. Takes the period of measurements, in microseconds, as input. Outputs: acceleration : Acceleration as a dict with the x,y, and z directions. """ @manage(['level', 'period']) def init(self, period): self.period = period self.level = calvinsys.open(self, "io.accelerometer", period=self.period) @stateguard(lambda self: calvinsys.can_read(self.level)) @condition([], ['acceleration']) def read_measurement(self): level = calvinsys.read(self.level) return (level, ) action_priority = (read_measurement, ) requires = ['io.accelerometer'] test_kwargs = {'period': 10} test_calvinsys = {'io.accelerometer': {'read': [10, 12, 0, 5]}} test_set = [{'outports': {'acceleration': [10, 12, 0, 5]}}]
class LightBreaker(Actor): """ React to changes in a sensor. Output: open : state true=closed, false=open """ @manage(include=[]) def init(self): self.setup() def setup(self): self.sensor = calvinsys.open(self, "io.lightbreaker") def will_migrate(self): calvinsys.close(self.sensor) self.sensor = None def will_end(self): if self.sensor: calvinsys.close(self.sensor) def did_migrate(self): self.setup() @stateguard(lambda self: calvinsys.can_read(self.sensor)) @condition([], ["open"]) def state_change(self): value = calvinsys.read(self.sensor) return (True if value else False, ) action_priority = (state_change, ) requires = ['io.lightbreaker']
class HallEffect(Actor): """ React to presence of magnetic field. Output: state : true if magnetic field present, false otherwise """ @manage(include=[]) def init(self): self.setup() def setup(self): self.sensor = calvinsys.open(self, "io.hallswitch") def will_migrate(self): calvinsys.close(self.sensor) self.sensor = None def will_end(self): if self.sensor: calvinsys.close(self.sensor) def did_migrate(self): self.setup() @stateguard(lambda self: calvinsys.can_read(self.sensor)) @condition([], ["state"]) def state_change(self): value = calvinsys.read(self.sensor) return (True if value else False, ) action_priority = (state_change, ) requires = ['io.hallswitch']
class Button(Actor): """ Handle a button and trigger on state changes. Output: state : Button state 1=pressed, 0=not pressed """ @manage(include=["text"]) def init(self, text="Button"): self.button = None self.text = text self.setup() def setup(self): self.button = calvinsys.open(self, "io.button", text=self.text) def will_migrate(self): calvinsys.close(self.button) def will_end(self): calvinsys.close(self.button) def did_migrate(self): self.setup() @stateguard(lambda self: self.button and calvinsys.can_read(self.button)) @condition([], ["state"]) def trigger(self): return (calvinsys.read(self.button), ) action_priority = (trigger, ) requires = ['io.button']
class RecTimer(Actor): """ After first token, pass on token once every 'delay' seconds. *Deprecated* This actor is identical to ClassicDelay. Input : token: anything Outputs: token: anything """ @manage(['timer', 'delay', 'started']) def init(self, delay): self.delay = delay self.timer = calvinsys.open(self, "sys.timer.repeating") self.started = False @stateguard(lambda self: not self.started) @condition(['token'], ['token']) def start_timer(self, token): self.started = True calvinsys.write(self.timer, self.delay) return (token, ) @stateguard(lambda self: calvinsys.can_read(self.timer)) @condition(['token'], ['token']) def passthrough(self, token): calvinsys.read(self.timer) return (token, ) action_priority = (start_timer, passthrough) requires = ['sys.timer.repeating']
class SimpleUDPListener(Actor): """ Listen for UDP messages on a given port. Address is of the form "ip:port" (note: ip is ipv4) Output: data : data in packets received on the UDP port will forwarded as tokens. """ @manage(['host', 'port']) def init(self, address): self.host, self.port = address.split(':') try: self.port = int(self.port) except ValueError: self.port = 0 self.setup() def did_migrate(self): self.setup() def setup(self): self.listener = calvinsys.open(self, "network.udplistener", host=self.host, port=self.port) @stateguard( lambda self: self.listener and calvinsys.can_read(self.listener)) @condition(action_output=['data']) def receive(self): message = calvinsys.read(self.listener) return (message["data"], ) action_priority = (receive, ) requires = ['network.udplistener']
class Counter(Actor): """ Produce next integer in a sequence 1,2,3,... Outputs: integer : Integer """ @manage(['count', 'stopped', 'schedule']) def init(self): self.count = 0 self.stopped = False self.schedule = calvinsys.open(self, "sys.schedule") @stateguard(lambda self: not self.stopped and calvinsys.can_read(self.schedule)) @condition(action_output=['integer']) def cnt(self): calvinsys.read(self.schedule) # ack calvinsys.can_write(self.schedule) calvinsys.write(self.schedule, 0) #reset self.count += 1 return (self.count, ) action_priority = (cnt,) requires = ['sys.schedule'] def report(self, **kwargs): self.stopped = kwargs.get("stopped", self.stopped) return self.count NTOKENS = 10 test_calvinsys = {'sys.schedule': {'read': ["dummy_data_read"]*NTOKENS, 'write': [0]*NTOKENS}} test_set = [ {'outports': {'integer': list(range(1, NTOKENS+1))}} ]
class Source(Actor): """ Data source. { "id": "ns=2;s=/Channel/Parameter/rpa[u1,115]", "tag": "R115", "type": "Double", "value": 0.0, "serverts": "2017-03-20 15:42:41.600000", "sourcets": "2017-03-20 15:42:41.542000", "calvints": 1490021096110, "status": 0 "info": "description given for parameter" } Output: parameter : description of parameter as shown above """ @manage([]) def init(self, tags=None): if isinstance(tags, basestring): tags = [tags] self.source = calvinsys.open(self, "data.source", tags=tags) @stateguard(lambda self: calvinsys.can_read(self.source)) @condition([], ["parameter"]) def send_data(self): param = calvinsys.read(self.source) return (param, ) action_priority = (send_data, ) requires = ['data.source']
class RandomDelay(Actor): """ Sends input on after a random delay has passed. Input : token : anything Outputs: token : anything """ @manage(['timers']) def init(self): self.timers = [] def new_timer(self): timer = calvinsys.open(self, "sys.timer.once") rng = calvinlib.use("math.random") delay = rng.random_integer(lower=0, upper=2) calvinsys.write(timer, delay) return timer @condition(['token']) def token_available(self, token): self.timers.append({'token': token, 'timer': self.new_timer()}) @stateguard(lambda self: len(self.timers) > 0 and calvinsys.can_read( self.timers[0]['timer'])) @condition([], ['token']) def timeout(self): item = self.timers.pop(0) calvinsys.read(item['timer']) calvinsys.close(item['timer']) return (item['token'], ) action_priority = (timeout, token_available) requires = ['sys.timer.once', 'math.random']
class Constant(Actor): """ Send predetermined data on output. Never ending sequence. Outputs: token : given data """ @manage(['data', 'schedule']) def init(self, data): self.data = data self.schedule = calvinsys.open(self, "sys.schedule") @stateguard(lambda self: calvinsys.can_read(self.schedule)) @condition([], ['token']) def timeout(self): calvinsys.read(self.schedule) # ack calvinsys.can_write(self.schedule) calvinsys.write(self.schedule, 0) #reset return (self.data, ) action_priority = (timeout, ) requires = ['sys.schedule'] test_kwargs = {'data': "data_to_forward"} NTOKENS = 10 test_calvinsys = { 'sys.schedule': { 'read': ["dummy_data_read"] * NTOKENS, 'write': [0] * NTOKENS } } test_set = [{'outports': {'token': ["data_to_forward"] * NTOKENS}}]
class Switch(Actor): """ Creates a on/off switch. Output: state : 0/1 according to switch state """ @manage([]) def init(self): self.switch = None self.setup() def setup(self): self.switch = calvinsys.open(self, "io.switch") def will_migrate(self): calvinsys.close(self.switch) def did_migrate(self): self.setup() def will_end(self): calvinsys.close(self.switch) @stateguard(lambda self: self.switch and calvinsys.can_read(self.switch)) @condition([], ["state"]) def action(self): state = calvinsys.read(self.switch) return (state, ) action_priority = (action, ) requires = ['io.switch']
class TiltSwitch(Actor): """ React to changes in a TiltSwitch. Output: open : state true=closed, false=open """ @manage(include=[]) def init(self): self.setup() def setup(self): self.switch = calvinsys.open(self, "io.tiltswitch") def will_migrate(self): calvinsys.close(self.switch) self.switch = None def will_end(self): if self.switch: calvinsys.close(self.switch) def did_migrate(self): self.setup() @stateguard(lambda self: calvinsys.can_read(self.switch)) @condition([], ["open"]) def state_change(self): value = calvinsys.read(self.switch) return (True if value else False, ) action_priority = (state_change, ) requires = ['io.tiltswitch']
class TriggeredTemperature(Actor): """ Measure temperature. Inputs: trigger : any token triggers meausurement Outputs: centigrade : temperature, in centigrade """ @manage(['temperature']) def init(self): self.temperature = calvinsys.open(self, "io.temperature") @stateguard(lambda self: calvinsys.can_read(self.temperature)) @condition([], ['centigrade']) def read_measurement(self): data = calvinsys.read(self.temperature) return (data, ) @stateguard(lambda self: calvinsys.can_write(self.temperature)) @condition(['trigger'], []) def trigger_measurement(self, _): calvinsys.write(self.temperature, True) action_priority = (read_measurement, trigger_measurement) requires = ['io.temperature']
class TriggeredSoilMoisture(Actor): """ Measure the moisture level in the soil. Inputs: trigger : any token triggers meausurement Outputs: level : moisture level, in percent """ @manage(exclude=['level']) def init(self): self.setup() def setup(self): self.level = calvinsys.open(self, "io.soilmoisture") def teardown(self): calvinsys.close(self.level) def will_migrate(self): self.teardown() def did_migrate(self): self.setup() def will_end(self): self.teardown() @stateguard(lambda self: calvinsys.can_write(self.level)) @condition(['trigger'], []) def trigger_measurement(self, _): calvinsys.write(self.level, True) @stateguard(lambda self: calvinsys.can_read(self.level)) @condition([], ['level']) def read_measurement(self): level = calvinsys.read(self.level) return (level, ) action_priority = (read_measurement, trigger_measurement) requires = ['io.soilmoisture'] test_calvinsys = { 'io.soilmoisture': { 'read': [50, 40], 'write': [True, True] } } test_set = [{ 'inports': { 'trigger': [True, "True"] }, 'outports': { 'level': [50, 40] } }]
class HTTPPut(Actor): """ Post data to URL Input: URL : URL to put to data : Data to put params : dictionary with query parameters (optional) headers: dictionary with headers to include in request (optional) auth : dictionary with authtype (basic/digest), username and password (optional) Output: status: HTTP status of request headers: dictionary of response headers data : body of response (only if body is non-empty) """ @manage() def init(self): self.cmd = calvinsys.open(self, "http.put") self.response = None @stateguard(lambda actor: calvinsys.can_write(actor.cmd)) @condition(action_input=['URL', 'data', 'params', 'headers', 'auth']) def new_request(self, url, data, params, headers, auth): calvinsys.write( self.cmd, { "url": url, "data": data, "params": params, "headers": headers, "auth": auth }) @stateguard(lambda actor: calvinsys.can_read(actor.cmd)) @condition() def handle_reply(self): self.response = calvinsys.read(self.cmd) @stateguard(lambda actor: actor.response and actor.response.get("body")) @condition(action_output=['status', 'headers', 'data']) def reply_with_body(self): response = self.response self.response = None return (response.get("status"), response.get("headers"), response.get("body")) @stateguard(lambda actor: actor.response and not actor.response.get("body") ) @condition(action_output=['status', 'headers']) def reply_without_body(self): response = self.response self.response = None return (response.get("status"), response.get("headers")) action_priority = (new_request, handle_reply, reply_with_body, reply_without_body) requires = ['http.put']
class LocationWeather(Actor): """ Get current weather at selected destination, given as "city,country code", "city", or ",country code" Input: location : location to fetch weather from Output: forecast: weather at given city, or null on error """ @manage([]) def init(self): self.setup() def did_migrate(self): self.setup() def setup(self): self._service = calvinsys.open(self, "weather") def teardown(self): calvinsys.close(self._service) def will_migrate(self): self.teardown() def will_end(self): self.teardown() @stateguard( lambda self: self._service and calvinsys.can_write(self._service)) @condition(action_input=['location']) def start_forecast(self, location): calvinsys.write(self._service, location) @stateguard( lambda self: self._service and calvinsys.can_read(self._service)) @condition(action_output=['forecast']) def finish_forecast(self): forecast = calvinsys.read(self._service) return (forecast, ) action_priority = ( start_forecast, finish_forecast, ) requires = ['weather'] test_calvinsys = {'weather': {'read': ["sunny"], 'write': ["Lund"]}} test_set = [{ 'inports': { 'location': ["Lund"] }, 'outports': { 'forecast': ["sunny"] } }]
def open_file(self, filename): obj = calvinsys.open(self, "io.filesize", filename=filename) if calvinsys.can_read(obj): self.filelen = calvinsys.read(obj) calvinsys.close(obj) self.file = calvinsys.open(self, "io.filereader", filename=filename) if self.file is None: self.file_not_found = True
class TriggeredDistance(Actor): """ Measure distance. Inputs: trigger : any token triggers meausurement Outputs: meters : distance, in meters """ @manage([]) def init(self): self.setup() def setup(self): self._distance = calvinsys.open(self, "io.distance") def teardown(self): if self._distance: calvinsys.close(self._distance) self._distance = None def will_migrate(self): self.teardown() def did_migrate(self): self.setup() def will_end(self): self.teardown() @stateguard(lambda self: calvinsys.can_read(self._distance)) @condition([], ['meters']) def read_measurement(self): distance = calvinsys.read(self._distance) return (distance, ) @stateguard(lambda self: calvinsys.can_write(self._distance)) @condition(['trigger'], []) def trigger_measurement(self, _): calvinsys.write(self._distance, True) action_priority = (read_measurement, trigger_measurement) requires = ['io.distance'] test_calvinsys = {'io.distance': {'read': [10, 12, 0, 5], 'write': [True]}} test_set = [{ 'inports': { 'trigger': [True] }, 'outports': { 'meters': [10, 12, 0, 5] } }]
class Distance(Actor): """ Measure distance. Takes the period of measurements, in seconds, as input. Outputs: meters : distance, in meters """ @manage(['period', 'distance', 'timer']) def init(self, period): self.period = period self.distance = calvinsys.open(self, "io.distance") self.timer = calvinsys.open(self, "sys.timer.repeating", period=period) @stateguard(lambda self: calvinsys.can_read(self.distance)) @condition([], ['meters']) def read_measurement(self): value = calvinsys.read(self.distance) return (value, ) @stateguard(lambda self: calvinsys.can_read(self.timer) and calvinsys. can_write(self.distance)) @condition([], []) def start_measurement(self): calvinsys.read(self.timer) calvinsys.write(self.distance, True) action_priority = (read_measurement, start_measurement) requires = ['io.distance', 'sys.timer.repeating'] test_kwargs = {'period': 10} test_calvinsys = { 'io.distance': { 'read': [10, 12, 0, 5], 'write': [True] }, 'sys.timer.repeating': { 'read': ['dummy'], 'write': [10] } } test_set = [{'outports': {'meters': [10, 12, 0, 5]}}]
class LocalWeather(Actor): """ Get current weather where runtime is located (or think it is located) Input: trigger : start fetching weather on any token Output: forecast: weather at preconfigured city, or null on error """ @manage([]) def init(self): self.setup() def did_migrate(self): self.setup() def setup(self): self._service = calvinsys.open(self, "weather.local") calvinsys.write(self._service, None) def teardown(self): calvinsys.close(self._service) def will_migrate(self): self.teardown() def will_end(self): self.teardown() @stateguard(lambda self: self._service and calvinsys.can_write(self._service)) @condition(action_input=['trigger']) def start_forecast(self, _): calvinsys.write(self._service, None) @stateguard(lambda self: self._service and calvinsys.can_read(self._service)) @condition(action_output=['forecast']) def finish_forecast(self): forecast = calvinsys.read(self._service) return (forecast,) action_priority = (start_forecast, finish_forecast,) requires = ['weather.local'] test_calvinsys = {'weather.local': {'read': ["sunny"], 'write': [None, None]}} test_set = [ { 'inports': {'trigger': [True]}, 'outports': {'forecast': ["sunny"]} } ]
class DelayToken(Actor): """ Sends input on after a given delay has passed. Preserves time between tokens. Input : token : anything Outputs: token : anything """ @manage(['delay', 'timers']) def init(self, delay): self.delay = delay self.timers = [] def new_timer(self): timer = calvinsys.open(self, "sys.timer.once", period=self.delay) return timer @condition(['token']) def token_available(self, token): self.timers.append({'token': token, 'timer': self.new_timer()}) @stateguard(lambda self: len(self.timers) > 0 and calvinsys.can_read( self.timers[0]['timer'])) @condition([], ['token']) def timeout(self): item = self.timers.pop(0) calvinsys.read(item['timer']) calvinsys.close(item['timer']) return (item['token'], ) action_priority = (timeout, token_available) requires = ['sys.timer.once'] test_kwargs = {'delay': 20} test_calvinsys = { 'sys.timer.once': { 'read': ["dummy", "dummy", "dummy", "dummy"], 'write': [20, 20, 20, 20] } } test_set = [{ 'inports': { 'token': ["a", "b", 1, 1] }, 'outports': { 'token': ["a", "b", 1, 1] }, }]
class TriggeredRelativeHumidity(Actor): """ Read Relative Humidity when told to. Inputs: measure: Triggers a temperature reading Outputs: percent: The measured humidity in percent """ @manage([]) def init(self): self.relhum = None self.setup() def setup(self): self.relhum = calvinsys.open(self, 'io.humidity') def did_migrate(self): self.setup() def will_end(self): calvinsys.close(self.relhum) @stateguard(lambda self: calvinsys.can_write(self.relhum)) @condition(['measure'], []) def measure(self, _): calvinsys.write(self.relhum, True) @stateguard(lambda self: calvinsys.can_read(self.relhum)) @condition([], ['percent']) def deliver(self): humidity = calvinsys.read(self.relhum) return (humidity, ) action_priority = ( deliver, measure, ) requires = ['io.humidity'] test_calvinsys = {'io.humidity': {'read': [50, 40], 'write': [True, True]}} test_set = [{ 'inports': { 'measure': [True, "True"] }, 'outports': { 'percent': [50, 40] } }]
class ObjectCounter(Actor): """ Counts objects in a base64 encoded jpg image Inputs: b64image: Image to analyze Outputs: objects: number of objects found in image """ @manage([]) def init(self): self.setup() def setup(self): self._object_counter = calvinsys.open(self, "image.objectdetection") def did_migrate(self): self.setup() @stateguard(lambda self: calvinsys.can_write(self._object_counter)) @condition(action_input=['b64image']) def analyze(self, b64image): calvinsys.write(self._object_counter, b64image) @stateguard(lambda self: calvinsys.can_read(self._object_counter)) @condition(action_output=['objects']) def report(self): objects = calvinsys.read(self._object_counter) return (objects, ) action_priority = (analyze, report) requires = ['image.objectdetection'] test_calvinsys = { 'image.objectdetection': { 'read': ["dummy_data_read"], 'write': ["dummy_data_write"] } } test_set = [{ 'inports': { 'b64image': ["dummy_data_write"] }, 'outports': { 'objects': ["dummy_data_read"] } }]
class ImageSource(Actor): """ When token on input, get an image. Inputs: trigger: anything Outputs: b64image: generated image """ @manage(exclude=["_cam"]) def init(self): self.setup() def setup(self): self._cam = calvinsys.open(self, "image.source") def did_migrate(self): self.setup() def will_end(self): calvinsys.close(self._cam) @stateguard(lambda self: calvinsys.can_read(self._cam)) @condition(action_output=['b64image']) def send_image(self): image = calvinsys.read(self._cam) return (image, ) @stateguard(lambda self: calvinsys.can_write(self._cam)) @condition(action_input=['trigger']) def fetch_image(self, trigger): calvinsys.write(self._cam, None) action_priority = (fetch_image, send_image) requires = ['image.source'] test_calvinsys = {'image.source': {'read': [1,0,1,0,0,1,0,1], 'write': [None, None, None, None]}} test_set = [ { 'inports': {'trigger': [True, 1, "a", 0]}, 'outports': {'b64image': [1,0,1,0,0,1,0,1]} } ]
class FaceFinder(Actor): """ Finds and marks faces in a base64 encoded jpg image function Inputs: b64image: Image to analyze Outputs: b64image: New image with all detected faces marked """ @manage([]) def init(self): self.setup() def setup(self): self._object_counter = calvinsys.open(self, "image.facefinding") def did_migrate(self): self.setup() @stateguard(lambda self: calvinsys.can_write(self._object_counter)) @condition(action_input=['b64image']) def analyze(self, b64image): calvinsys.write(self._object_counter, b64image) @stateguard(lambda self: calvinsys.can_read(self._object_counter)) @condition(action_output=['b64image']) def report(self): image = calvinsys.read(self._object_counter) return (image, ) action_priority = (analyze, report) requires = ['image.facefinding'] test_calvinsys = { 'image.facefinding': { 'read': ["dummy_data_read"], 'write': ["dummy_data_write"] } } test_set = [{ 'inports': { 'b64image': ["dummy_data_write"] }, 'outports': { 'b64image': ["dummy_data_read"] } }]
class StandardIn(Actor): """ Reads from Standard IN, and send each read line as a token on output port Outputs: out : Each token is a line of text, or EOSToken. """ @manage([]) def init(self): self.setup() def setup(self): self.file = calvinsys.open(self, "io.stdin") def did_migrate(self): self.setup() def will_end(self): if self.file is not None: calvinsys.close(self.file) self.file = None @stateguard(lambda self: self.file and calvinsys.can_read(self.file)) @condition([], ['out']) def read(self): line = calvinsys.read(self.file) return (line, ) action_priority = (read, ) requires = ['io.stdin'] test_calvinsys = { 'io.stdin': { 'read': [ 'the', 'quick', 'brown', 'fox', 'jumped', 'over', 'the', 'lazy', 'dog' ] } } test_set = [{ 'outports': { 'out': [ 'the', 'quick', 'brown', 'fox', 'jumped', 'over', 'the', 'lazy', 'dog' ] }, }]
class ClassicDelay(Actor): """ After first token, pass on token once every 'delay' seconds. Input : token: anything Outputs: token: anything """ @manage(['timer', 'delay', 'started']) def init(self, delay): self.delay = delay self.timer = calvinsys.open(self, "sys.timer.repeating") self.started = False @stateguard( lambda self: not self.started and calvinsys.can_write(self.timer)) @condition(['token'], ['token']) def start_timer(self, token): self.started = True calvinsys.write(self.timer, self.delay) return (token, ) @stateguard(lambda self: calvinsys.can_read(self.timer)) @condition(['token'], ['token']) def passthrough(self, token): calvinsys.read(self.timer) return (token, ) action_priority = (start_timer, passthrough) requires = ['sys.timer.repeating'] test_kwargs = {'delay': 20} test_calvinsys = { 'sys.timer.repeating': { 'read': ["d", "u", "m", "m", "y"], 'write': [20] } } test_set = [{ 'inports': { 'token': ["a", "b", 1] }, 'outports': { 'token': ["a", "b", 1] } }]