class ClockedLink(object): """Support for implementing an EventLink which runs on an internal clock.""" def __init__(self, *args, clock_start=0.0, **kwargs): """Initialize members.""" super().__init__(*args, **kwargs) self.clock = Clock(time=clock_start) self.next_clock_request_timer = TimeoutTimer(clock=self.clock) # Public interface def update_clock(self, time): """Update the clock of the link and do any necessary processing.""" # print('{}: updating clock to {}!'.format(self, time)) self.to_receive(LinkClockTime(time, instance=self)) self.send(LinkClockTime(time, instance=self)) @property def next_clock_request(self): """Determine the next requested clock update.""" if not self.next_clock_request_timer.running: return None return LinkClockRequest(self.next_clock_request_timer.timeout_time, context={'time': self.clock.time}, instance=self) # Internal methods for implementers def make_timer(self, delay): """Make a timer on the processor clock.""" return TimeoutTimer(timeout=delay, clock=self.clock) def get_clock_time(self, event): """Extract any provided clock time from the event.""" if isinstance(event, LinkClockTime): return event.clock_time return None # No clock time provided def update_clock_time(self, event): """Return the new clock time, updated with any clock time in the event.""" clock_time = self.get_clock_time(event) if clock_time is None: return # print('Updating clock to: {}'.format(clock_time)) self.clock.update(clock_time) if self.next_clock_request_timer.timed_out: self.next_clock_request_timer.reset_and_stop() def make_clock_request(self, time, context={}, previous=None): """Return a LinkClockRequest if time is different from the last request.""" if (self.next_clock_request_timer.running and math.isclose( self.next_clock_request_timer.timeout_time, time)): return None self.next_clock_request_timer.start(timeout=time - self.clock.time) return LinkClockRequest(time, context={ 'time': self.clock.time, **context }, instance=self, previous=previous)
def __init__(self, ping_name=b'ping', pong_name=b'pong'): """Initialize members.""" self.ping_name = ping_name self.pong_name = pong_name self.ping_counter = 0 self.active = False super().__init__() self.pong_timer = TimeoutTimer(clock=self.clock)
def __init__( self, timer=None, event_type='events', time_unit='second', report_interval=None, logger_name='Counter', logger_indentation=0 ): """Initialize members.""" if timer is None: timer = TimeoutTimer() self.timer = timer self.count = 0 self.event_type = event_type self.report_interval = report_interval self.time_unit = time_unit self.logger = IndentedLogger(logging.getLogger(logger_name), { 'class': self.__class__.__qualname__, 'indentation': logger_indentation })
class PingPongHandler(EndpointHandler, ClockedLink): """Handler for playing ping-pong in the background.""" def __init__(self, ping_name=b'ping', pong_name=b'pong'): """Initialize members.""" self.ping_name = ping_name self.pong_name = pong_name self.ping_counter = 0 self.active = False super().__init__() self.pong_timer = TimeoutTimer(clock=self.clock) def make_ping(self): """Make a ping.""" self.ping_counter += 1 logger.info('Ping-pong sending ping {}'.format(self.ping_counter)) return (self.ping_name, self.ping_counter) # Implement DataUnitLink def on_internal_data(self, parse_result, event): """Implement DataUnitLink.on_internal_data.""" self.update_clock_time(event) if self.pong_timer.timed_out: self.pong_timer.reset_and_stop() self.directly_to_send_data(self.make_ping()) # Implement EndpointHandler def match_receiver(self, endpoint_name): """Implement EndpointHandler.match_receiver.""" return endpoint_name == self.pong_name def on_receiver_event(self, endpoint_name, data, source_event): """Implement EndpointHandler.on_receiver_event.""" if endpoint_name == self.pong_name: logger.info('Ping-pong received pong {}'.format(data)) self.pong_timer.start() clock_request = self.make_clock_request(self.pong_timer.timeout_time) if clock_request is not None: yield clock_request def on_sender_event(self, send_data): """Implement EndpointHandler.on_sender_event.""" if send_data: logger.info('Starting ping-pong with interval of {} sec!'.format(send_data)) self.pong_timer.timeout = send_data yield self.make_ping() else: logger.info('Stopping ping-pong.') self.pong_timer.reset_and_stop()
def make_timer(self, timeout=None): """Make a timer on the clock.""" if timeout is None: timeout = self.send_timeout return TimeoutTimer(timeout=timeout, clock=self.clock)
def test_timer_external(): """Test externally-clocked timer functionality.""" timer = TimeoutTimer(timeout=0.2, clock=Clock(time=0.0)) assert timer.timeout_time is None assert timer.elapsed is None assert_timer_stopped(timer) # Basic test timer.clock.update(1.0) timer.start() assert repr(timer) == 'TimeoutTimer(running from 1.0, timeout=0.2)' assert timer.timeout_time == 1.2 timer.clock.update(1.1) assert_timer_halfway(timer) timer.clock.update(1.2) assert_timer_finished(timer) timer.clock.update(1.3) assert_timer_finished(timer) timer.clock.update(0.0) timer.reset() timer.clock.update(0.1) assert_timer_halfway(timer) timer.clock.update(0.2) assert_timer_finished(timer) # Shared-clock test timer.clock.update(1.0) timer.reset() timer_slow = TimeoutTimer(timeout=0.4, clock=timer.clock) timer_slow.start() timer.clock.update(1.1) assert_timer_halfway(timer) timer.clock.update(1.2) assert_timer_finished(timer) assert_timer_halfway(timer_slow) timer.clock.update(1.4) assert_timer_finished(timer) assert_timer_finished(timer_slow)
def test_timer_realtime(): """Test real-time timer functionality.""" timer = TimeoutTimer(timeout=0.2) assert timer.timeout_time is None assert timer.elapsed is None timer.enabled = True assert timer.elapsed is None # no start time was set due to invalid state change timer.enabled = False assert_timer_stopped(timer) # Basic test timer.start() assert_timer_running_realtime(timer) # Stop-and-start test timer.reset_and_stop() assert_timer_stopped(timer) timer.reset() assert_timer_stopped(timer) timer.start() assert_timer_running_realtime(timer) # Reset test timer.reset() assert_timer_running_realtime(timer) timer.reset() assert_timer_running_realtime(timer) # Start test timer.start(timeout=0.1) assert_timer_running_realtime(timer) timer.reset() assert_timer_running_realtime(timer) timer.start() assert_timer_running_realtime(timer) # Externally-clocked mode-switching test timer.clock.reset(0.0) timer.start(timeout=0.2) timer.clock.update(0.1) assert_timer_halfway(timer) timer.clock.update(0.2) assert_timer_finished(timer)
def make_timer(self): """Make a timer on the clock.""" return TimeoutTimer(timeout=self.delay, clock=self.clock)
def make_timer(self, delay): """Make a timer on the processor clock.""" return TimeoutTimer(timeout=delay, clock=self.clock)
def __init__(self, *args, clock_start=0.0, **kwargs): """Initialize members.""" super().__init__(*args, **kwargs) self.clock = Clock(time=clock_start) self.next_clock_request_timer = TimeoutTimer(clock=self.clock)