class Orocos::Log::Replay

Class for loading and replaying pocolog (Rock) log files.

This class creates objects whose API is compatible with {Orocos::TaskContext} and {Orocos::OutputPort}, using the log data.

By default, all tasks that are present in the log files provided to {open} can be resolved using the orocos name service. If this behaviour is unwanted, call {#deregister_tasks} after {.open} or {#load} was called. To do it on a task-by-task basis, do the following after the call to {.open} or {#load}

replay.name_service.deregister 'task_name'

Attributes

log_config_file[RW]
actual_speed[R]

The actual replay speed

This is updated during replay, and reflects the actual replay speed

@return [Float]

annotations[R]

array of stream annotations

current_sample[R]

last replayed sample

log_config_file[RW]

name of the log file which holds the logged properties is converted into Regexp

name_service[RW]

@return [Orocos::Local] a local nameservice on which the log tasks

are registered. It is added to the global name service with
{#register_tasks} and removed with {#unregister_tasks}
name_service_async[RW]

@return [Orocos::Async::Local] a local async nameservice on which the log tasks

are registered. It is added to the global name service with
{#register_tasks} and removed with {#unregister_tasks}
out_of_sync_delta[R]

Measure of time synchronization during replay

This is updated during replay to reflect how fast the replay actually is. This is the difference (in seconds) between the replay time that we should have and the replay time that we actually have

In practice, negative values mean that the replayed samples are behind the simulated times, and positive values mean that the replayed samples are replayed to fast

@return [Float]

process_qt_events[RW]

set it to true if processing of qt events is needed during synced replay

replayed_annotations[RW]

array of all replayed annotaions this array is filled after {align} was called

replayed_ports[RW]

array of all replayed ports

this array is filled after {align} was called

replayed_properties[RW]

array of all replayed properties this array is filled after {align} was called

speed[RW]

desired replay speed = 1 –> record time

timestamps[R]

@return [Hash<String,#call>] a mapping from a typelib type name to

an object that allows to extract the timestamp from a value of
that type

@see {timestamp}

use_sample_time[RW]

If true, the alignment algorithm is going to use the sample time for alignment. Otherwise, it uses the time at which the sample got written on disk (logical time)

See also time_source

used_streams[R]

The streams that are actually replayed

@return [Array<Pocolog::DataStream>]

Public Class Methods

new(*path) click to toggle source

Creates a new instance of Replay

If a path is givien load is called after creation to load the log files.

# File lib/orocos/log/replay.rb, line 190
def initialize(*path)
    if !path.empty?
        raise ArgumentError, "Replay.new(*path) is deprecated, use Replay.open(*path) to create and load files at the same time"
    end

    @default_timestamp = nil
    @timestamps = Hash.new
    @tasks = Hash.new
    @annotations = Array.new
    @current_annotations = Hash.new
    @speed = 1
    @replayed_ports = Array.new
    @replayed_properties = Array.new
    @replayed_objects = Array.new
    @used_streams = Array.new
    @stream = nil
    @current_sample = nil
    @process_qt_events = false
    @log_config_file = Replay::log_config_file
    @namespace = ''
    reset_time_sync
    time_sync
end
open(*path) click to toggle source
# File lib/orocos/log/replay.rb, line 174
def self.open(*path)
    replay = new
    replay.load(*path)
    replay
rescue ArgumentError => e
    Orocos.error "Cannot load logfiles"
    raise e 
rescue Pocolog::Logfiles::MissingPrologue => e
    Orocos.error "Wrong log format"
    raise e
end

Public Instance Methods

add_intervals_as_log_markers(intervals,comment) click to toggle source

Adds the given time intervals as LogMarkers

@param [Array<Array<Time>>] intervals The intervals @param [String] comment Comment of the log markers

# File lib/orocos/log/replay.rb, line 772
def add_intervals_as_log_markers(intervals,comment)
    markers = log_markers # fill @markers from log file
    intervals.each do |interval|
        markers << LogMarker.new(interval.first,:start,-1,comment)
        markers << LogMarker.new(interval.last,:stop,-1,comment)
    end
    markers.sort! do |a,b|
        a.time <=> b.time 
    end
    markers
end
advance() click to toggle source
# File lib/orocos/log/replay.rb, line 457
def advance
    if(@stream)
        return @stream.advance
    else
        throw "Stream is not initialized yet"
    end
end
align( time_source = self.time_source ) click to toggle source

Aligns all streams which have at least:

  • one reader

  • or one connections

  • or track set to true.

After calling this method no more ports can be tracked.

#time_source is passed through to the StreamAligner. It can be used to override the global time_source parameter. See time_source for available values.

# File lib/orocos/log/replay.rb, line 400
def align( time_source = self.time_source )
    @replayed_ports = Array.new
    @used_streams = Array.new
    @replayed_annotations = Array.new

    if !replay?
        Log.warn "No ports are selected. Assuming that all ports shall be replayed."
        Log.warn "Connect port(s) or set their track flag to true to get rid of this message."
        track(true)
    end

    #get all properties which shall be replayed
    each_task do |task|
        if task.used?
            task.port("state").tracked=true if task.has_port?("state")
            task.properties.values.each do |property|
                property.tracked = true
                next if property.stream.empty?
                @replayed_properties << property
            end
        end
    end

    #get all streams which shall be replayed
    each_port do |port|
        if port.used?
            next if port.stream.empty?
            @replayed_ports << port
        end
    end

    Log.info "Aligning streams --> all ports which are unused will not be loaded!!!"
    if @replayed_properties.empty? && @replayed_ports.empty?
        raise "No log data are replayed. All selected streams are empty."
    end

    # If we do have something to replay, then add the annotations as
    # well
    annotations.each do |annotation|
        next if annotation.stream.empty?
        @replayed_annotations << annotation
    end

    @replayed_objects = @replayed_properties + @replayed_ports + @replayed_annotations
    @used_streams = @replayed_objects.map(&:stream)

    Log.info "Replayed Ports:"
    @replayed_ports.each {|port| Log.info PP.pp(port,"")}

    #join streams
    @stream = Pocolog::StreamAligner.new(time_source, *@used_streams)
    @stream.rewind

    reset_time_sync
    return step
end
aligned?() click to toggle source
# File lib/orocos/log/replay.rb, line 513
def aligned?
    return @stream != nil
end
calc_statistics(time = current_time) click to toggle source
# File lib/orocos/log/replay.rb, line 588
def calc_statistics(time = current_time)
    time = current_time

    @base_time ||= time
    @start_time ||= Time.now

    required_delta = (time - @base_time)/@speed
    actual_delta   = Time.now - @start_time
    @out_of_sync_delta = @time_sync_proc.call(time,actual_delta,required_delta)
    @actual_speed = required_delta/actual_delta*@speed
end
clear_reader_buffers() click to toggle source

Clears all reader buffers. This is usefull if you are changing the replay direction.

# File lib/orocos/log/replay.rb, line 1036
def clear_reader_buffers
    @tasks.each_value do |task|
        task.clear_reader_buffers
    end
end
close() click to toggle source

close the log file, deregister from name service and also close all available streams

# File lib/orocos/log/replay.rb, line 494
def close
    deregister_tasks
    # TODO close all streams
end
connect_to(task,port_mappings = Hash.new ,port_policies = Hash.new,ports_ignored = Array.new) click to toggle source

Tries to connect all input ports of the OROCOS task to simulated OutputPorts

Parameter:

*task => task to connect to
*port_mappings => hash to define port mappings {src_port_name => dst_port_name}
*ports_ignored => array of port names which shall be ignored
# File lib/orocos/log/replay.rb, line 326
def connect_to(task,port_mappings = Hash.new ,port_policies = Hash.new,ports_ignored = Array.new)
    #convenience block to do connect_to(task,:auto_ignore)
    if port_mappings == :auto_ignore
        ports_ignored = port_mappings
        port_mappings = Hash.new
    end
    ports_ignored = Array.new(ports_ignored)

    #start task if necessary
    if task.state == :PRE_OPERATIONAL
        task.configure
    end
    if task.state == :STOPPED
        task.start
    end

    #to have a better user interface the hash is inverted
    #port1 connect_to port2 is written as ('port1' => 'port2')
    port_mappings = port_mappings.invert

    task.each_port do |port|
        if port.to_orocos_port.kind_of?(Orocos::InputPort) && !ports_ignored.include?(port.name)
            target_port = find_port(port.type_name,port_mappings[port.name]||port.name)
            if target_port
                target_port.connect_to(port,port_policies[port.name])
            elsif !ports_ignored.include? :auto_ignore
                raise ArgumentError, "cannot find an output port for #{port.name}"
            else
                Log.warn "No input port can be found for output port #{port.full_name}."
            end
        end
    end
end
current_annotations() click to toggle source

The current annotations

This is an aggregated version of annotations, where the value for each key is the last value known (i.e. the value from the last annotation with that key that has a timestamp lower than the current time)

# File lib/orocos/log/replay.rb, line 142
def current_annotations
    annotations.inject(Hash.new) do |current, ann|
        current.merge(ann.current_state)
    end
end
current_port() click to toggle source

returns the last port which recieved data

# File lib/orocos/log/replay.rb, line 684
def current_port
    if @current_sample
        stream_idx = @current_sample[0]
        replayed_ports[stream_idx]
    end
end
current_sample_data() click to toggle source

returns the current data of the current sample

# File lib/orocos/log/replay.rb, line 692
def current_sample_data
    if @current_sample
        sample_info = @current_sample[2]
        sample_info[0].read_one_raw_data_sample(sample_info[1])
    end
end
current_time() click to toggle source
# File lib/orocos/log/replay.rb, line 576
def current_time
    stream_idx, time, sample_info = @current_sample
    return if !time

    stream_type = @stream.stream_by_index(stream_idx).type
    if getter = (timestamps[stream_type.name] || default_timestamp)
        data = sample_info[0].read_one_raw_data_sample(sample_info[1])
        getter[data]
    else time
    end
end
default_timestamp(&block) click to toggle source

Sets a code block to calculate the default timestamp duricng replay.

# File lib/orocos/log/replay.rb, line 279
def default_timestamp(&block)
    if block_given? then @default_timestamp = block
    else @default_timestamp
    end
end
deregister_tasks() click to toggle source

deregister the local name service again

# File lib/orocos/log/replay.rb, line 486
def deregister_tasks
    if @name_service 
        Orocos::name_service.delete @name_service
    end
end
duration() click to toggle source

The total duration of the replayed data, in seconds

@return [Float]

# File lib/orocos/log/replay.rb, line 520
def duration
    intervals = used_streams.map { |s| s.info.interval_lg }
    min = intervals.map(&:first).min
    max = intervals.map(&:last).max
    if min && max
        max - min
    else 0
    end
end
each_port(&block) click to toggle source

Iterates through all simulated ports.

# File lib/orocos/log/replay.rb, line 816
def each_port(&block)
    @tasks.each_value do |task|
        task.each_port(&block)
    end
end
each_task() { |task| ... } click to toggle source

Iterates through all simulated tasks

# File lib/orocos/log/replay.rb, line 854
def each_task (&block)
    @tasks.each_value do |task|
        yield(task) if block_given?
    end
end
eof?() click to toggle source

Returns true if the end of file is reached.

# File lib/orocos/log/replay.rb, line 876
def eof?
    return @stream.eof?
end
export_to_file(file,start_index=0,end_index=0,&block) click to toggle source

exports all aligned stream to a new log file if no start and end index is given all data are exported otherwise the data are truncated according to the given global indexes the block is called for each sample to update a progress bar

# File lib/orocos/log/replay.rb, line 1046
def export_to_file(file,start_index=0,end_index=0,&block)
    @stream.export_to_file(file,start_index,end_index,&block)
end
extract_intervals(start_time=nil,end_time=nil, min_val=0.8,kernel_size=5.0,&block) click to toggle source

Extracts time intervals from the log file where the given code block returns true.

For each sample the given code block is called with the current port and sample as parameter. After all samples were replayed the generated result vector (true is interpreted as 1) is filtered with a box filter of the given size. The returned intervals are these intervals where the filtered result vector is equal or bigger than min_val

@param [Time] start_time Start time of the interval which is replayed (nil = start of the log file) @param [Time] end_time End time of the interval which is replayed (nil = end of the log file) @param [Float] min_val Min value of the filtered result vector to be regarded as inlayer @param [Float] kernel_size Filter kernel size of the box filter in seconds @yield [reader,sample] @yieldparam reader the data reader of the port from which the

sample has been read

@yieldparam sample the data sample @yieldreturn [Boolean]

@return [Array<Array<Time>>] extracted intervals

# File lib/orocos/log/replay.rb, line 720
def extract_intervals(start_time=nil,end_time=nil, min_val=0.8,kernel_size=5.0,&block)
    #replay given intervals and collect results of the code block
    result,times = [],[]
    start_time ||= begin
                  rewind
                  time
              end
    seek(start_time)
    begin
        if block.call(current_port,current_sample_data)
            result << 1
        else
            result << 0
        end
        times << time
    end while(step && (!end_time || time <= end_time))

    #filter result vector
    idx,sum,size = 0,0,0
    filtered = result.map do |e|
        while times[idx+size] - times[idx] < kernel_size && idx+size < times.size-1
            size += 1
            sum += result[idx+size]
        end
        val = if size > 0
                sum/size
              else
                  0
              end
        sum -= result[idx]
        idx += 1
        size -= 1
        val
    end

    #extract intervals
    intervals,start = [],nil
    filtered.each_with_index do |e,i|
        if e >= min_val
            start ||= times[i]
        elsif start
            intervals << [start,times[i]] if times[i]-start >= kernel_size
            start = nil
        end
    end
    intervals
end
first_sample_pos(stream) click to toggle source
# File lib/orocos/log/replay.rb, line 465
def first_sample_pos(stream)
    @stream.first_sample_pos(stream)
end
full_name(name) click to toggle source

returns the full name of a task reachable under the given name

# File lib/orocos/log/replay.rb, line 361
def full_name(name)
    # use full name
    name = name.to_s
    return name if @tasks.has_key?(name)

    # use namespace of replay
    name2 = map_to_namespace(name)
    return name2 if @tasks.has_key?(name2)

    # use all namespaces
    t = @tasks.find do |key,task|
        task.basename == name
    end
    t.first if t
end
generate_log_markers(comment,min_val=0.8,kernel_size=5.0,&block) click to toggle source

Extracts time intervals from the log file where the given code block returns true and adds these interval as log markers to the log replay instance.

@param [String] comment Comment of the log markers @param [Float] min_val Min value of the filtered result vector to be regarded as inlayer @param [Float] kernel_size Filter kernel size of the box filter in seconds @yield [reader,sample] @yieldparam reader the data reader of the port from which the

sample has been read

@yieldparam sample the data sample @yieldreturn [Boolean]

@return [Array<Array<Time>>] extracted intervals @see #extract_intervals @see #add_intervals_as_log_markers

# File lib/orocos/log/replay.rb, line 800
def generate_log_markers(comment,min_val=0.8,kernel_size=5.0,&block)
    intervals = extract_intervals(nil,nil, min_val,kernel_size,&block)
    add_intervals_as_log_markers(intervals,comment)
    rewind
    intervals
end
has_task?(name) click to toggle source
# File lib/orocos/log/replay.rb, line 848
def has_task?(name)
    name = map_to_namespace name
    @tasks.has_key?(name.to_s)
end
last_sample_pos(stream) click to toggle source
# File lib/orocos/log/replay.rb, line 469
def last_sample_pos(stream)
    @stream.last_sample_pos(stream)
end
load(*paths) click to toggle source

Loads a log files and creates TaskContexts which simulates the recorded tasks. You can either specify a single file or a hole directory. If you want to load more than one directory or file simultaneously you can use an array.

Logs that share the same basename, will be joined such that the streams within the logs appear continous.

a collection of files/directories can be given as arguments, followed by a typelib registry and/or an options hash. The options can be given as:

:registry - same as providing the registry directly
:multifile - set to :last if you don't want merging of logs with the same
             basename
# File lib/orocos/log/replay.rb, line 972
def load(*paths)
    paths.flatten!
    raise ArgumentError, "No log file was given" if paths.empty?

    logreg = nil
    if paths.last.kind_of?(Typelib::Registry)
        logreg = paths.pop
    end
    opts = {}
    if paths.last.kind_of?(Hash)
        opts = paths.pop
        logreg = opts[:registry] if opts[:registry]
    end

    paths.each do |path| 
        #check if path is a directory
        path = File.expand_path(path)
        if File.directory?(path)
            all_files = Dir.enum_for(:glob, File.join(path, '*.*.log'))
            by_basename = all_files.inject(Hash.new) do |h, path|
                split = path.match(/^(.*)\.(\d+)\.log$/)
                if split
                    basename, number = split[1], Integer(split[2])
                    h[basename] ||= Array.new
                    h[basename][number] = path
                    h
                else
                    Orocos.warn "invalid log file name #{path}. Expecting: /^(.*)\.(\d+)\.log$/"
                    h
                end
            end
            if by_basename.empty?
                Orocos.warn "empty directory: #{path}"
                next
            end

            by_basename.each_value do |files|
                if opts[:multifile] == :last 
                    files = files[-1,1]
                end
                args = files.compact.map do |path|
                    File.open(path)
                end

                args << logreg

                logfile = Pocolog::Logfiles.new(*args.compact)
                load_log_file(logfile, files.first)
            end
        elsif File.file?(path)
            file = Pocolog::Logfiles.open(path, logreg)
            load_log_file(file, path)
        else
            raise ArgumentError, "Can not load log file: #{path} is neither a directory nor a file"
        end
    end
    raise ArgumentError, "Nothing was loaded from the following log files #{paths.join("; ")}" if @tasks.empty?

    #register task on the local name server
    register_tasks
end
load_log_file(file, path) click to toggle source

Loads all the streams defined in the provided log file

# File lib/orocos/log/replay.rb, line 947
def load_log_file(file, path)
    Log.info "  loading log file #{path}"
    file.streams.each do |s|
        if s.metadata["rock_stream_type"] == "annotations"
            @annotations << Annotations.new(path,s)
            next
        end
        load_task_from_stream(s,path)
    end
end
load_task_from_stream(stream,path) click to toggle source
# File lib/orocos/log/replay.rb, line 904
def load_task_from_stream(stream,path)
    #get the name of the task which was logged into the stream
    task_name = if stream.metadata.has_key? "rock_task_name"
                    begin
                        namespace, _ = Namespace.split_name(stream.metadata["rock_task_name"])
                        Namespace.validate_namespace_name(namespace)
                    rescue ArgumentError => e
                        Orocos.warn "invalid metadata rock_task_name:'#{stream.metadata["rock_task_name"]}' for stream #{stream.name}: #{e}"
                        stream.metadata.delete("rock_task_name")
                        return load_task_from_stream(stream,path)
                    end
                    stream.metadata["rock_task_name"]
                else
                    result = stream.name.to_s.match(/^(.*)\./)
                    result[1] if result
                end
    if task_name == nil
        task_name = "unknown"
        Log.warn "Stream name (#{stream.name}) does not follow the convention TASKNAME.PORTNAME and has no metadata, assuming as TASKNAME \"#{task_name}\""
    end

    #check if there is a namespace
    task_name = if task_name == basename(task_name)
                    map_to_namespace(task_name)
                else
                    task_name
                end

    task = @tasks[task_name]
    if !task
        task = @tasks[task_name]= TaskContext.new(self,task_name, path,@log_config_file)
    end

    begin
        task.add_stream(path,stream)
        Log.info "    loading stream #{stream.name} (#{stream.type_name})"
    rescue InitializePortError => error
        Log.warn "    loading stream #{stream.name} (#{stream.type_name}) failed. Call the port for an error message."
    end
    task
end
log_markers() click to toggle source

returns an array of #log_markers

# File lib/orocos/log/replay.rb, line 832
def log_markers
    @markers ||= Array.new
    return @markers if !@markers.empty?

    annotations.each do |annotation|
        #check if this is the right type
        if annotation.stream.type_name == "/logger/Annotations"
            @markers.concat LogMarker::parse(annotation.samples)
        end
    end
    @markers.sort! do |a,b|
        a.time <=> b.time 
    end
    @markers
end
port_for(type_name, port_name, precise=true) click to toggle source

Tries to find a OutputPort for a specefic data type. For port_name Regexp is allowed. If precise is set to true an error will be raised if more than one port is matching type_name and port_name.

# File lib/orocos/log/replay.rb, line 311
def port_for(type_name, port_name, precise=true)
    Log.warn "#port_for is deprecated. Use either #find_all_ports or #find_port"
    if precise
        find_port(type_name, port_name)
    else find_all_ports(type_name, port_name)
    end
end
ports() click to toggle source

Returns an array of all simulated ports

# File lib/orocos/log/replay.rb, line 823
def ports
    result = Array.new
    each_port do |port|
        result << port
    end
    result
end
pretty_print(pp) click to toggle source

pretty print for Replay

# File lib/orocos/log/replay.rb, line 238
def pretty_print(pp)
    pp.text "Orocos::Log::Replay"
    pp.nest(2) do
        pp.breakable
        pp.text "replay speed = #{@speed}"
        pp.breakable
        pp.text "Markers = #{@markers}"
        pp.breakable
        @tasks.each_value do |task|
            pp.breakable
            task.pretty_print(pp)
        end
        pp.breakable
        pp.text "Stream Annotations:"
        @annotations.each do |a|
            pp.breakable
            a.pretty_print(pp)
        end
    end
end
push_sample(stream_idx, sample_info) { |log_output,to_ruby| ... } click to toggle source
# File lib/orocos/log/replay.rb, line 652
def push_sample(stream_idx, sample_info)
    #write sample to simulated ports or properties
    log_output = @replayed_objects[stream_idx]
    log_output.update(sample_info)
    if block_given?
        data = sample_info[0].read_one_raw_data_sample(sample_info[1])
        yield(log_output,Typelib.to_ruby(data))
    end
    return *@current_sample[0, 2]
end
refresh() click to toggle source

replays the last sample to the log port

# File lib/orocos/log/replay.rb, line 899
def refresh
    index, _, sample_info = @current_sample
    @replayed_objects[index].update(sample_info)
end
register_tasks() click to toggle source

registers all replayed log tasks on the local name server

# File lib/orocos/log/replay.rb, line 474
def register_tasks
    @name_service ||= Local::NameService.new
    @name_service_async ||= Orocos::Async::Local::NameService.new :tasks => @tasks.values if defined?(Orocos::Async)
    @tasks.each_pair do |name,task|
        @name_service.register task
        @name_service_async.register task if @name_service_async
    end
    Orocos::name_service.add @name_service
    Orocos::Async.name_service.add @name_service_async if @name_service_async
end
replay?() click to toggle source

returns false if no ports are or will be replayed

# File lib/orocos/log/replay.rb, line 225
def replay? 
    #check if stream was initialized
    if @stream
        return true
    else
        each_task do |task|
            return true if task.used?
        end
    end
    return false
end
reset_time_sync() click to toggle source

Resets the simulated time. This should be called after the replay was paused.

# File lib/orocos/log/replay.rb, line 532
def reset_time_sync
    @start_time = nil 
    @base_time  = nil
    @actual_speed = 0
    @out_of_sync_delta = 0
end
rewind() click to toggle source

Rewinds all streams and replays the first sample.

# File lib/orocos/log/replay.rb, line 678
def rewind()
    @stream.rewind
    step
end
run(time_sync = false,speed=1,&block) click to toggle source

Runs through the log files until the end is reached.

# File lib/orocos/log/replay.rb, line 808
def run(time_sync = false,speed=1,&block)
    reset_time_sync
    @speed = speed
    while step(time_sync,&block) do
    end
end
sample_index() click to toggle source
# File lib/orocos/log/replay.rb, line 267
def sample_index()
    return @stream.sample_index if @stream
    return nil
end
sample_index_for_time(time) click to toggle source
# File lib/orocos/log/replay.rb, line 259
def sample_index_for_time(time)
    prev_pos = sample_index
    seek(time)
    target_sample_pos = sample_index
    seek(prev_pos)
    return target_sample_pos
end
seek(pos) click to toggle source

Seeks to the given position

# File lib/orocos/log/replay.rb, line 881
def seek(pos)
    #check if stream was generated otherwise call align
    align if @stream == nil
    @current_sample = @stream.seek(pos)
    if !@current_sample
        return
    end
    @current_sample[2] = @stream.sample_info(@current_sample[0])

    #write all data to the ports
    @stream.streams.length.times do |stream_idx|
        if info = @stream.sample_info(stream_idx)
            @replayed_objects[stream_idx].update(info)
        end
    end
end
single_data(id) click to toggle source
# File lib/orocos/log/replay.rb, line 272
def single_data(id)
    if @stream
        return @stream.single_data(id)
    end
end
size() click to toggle source

Returns the number of samples.

# File lib/orocos/log/replay.rb, line 866
def size
    return @stream.size
end
step(time_sync=false,&block) click to toggle source

Gets the next sample, writes it to the ports which are connected to the OutputPort and updates all its readers.

If a block is given it is called this the name of the replayed port.

@param [Boolean] #time_sync if true, the method will sleep as much

time as required to match the time delta in the file

@yield [reader,sample] @yieldparam reader the data reader of the port from which the

sample has been read

@yieldparam sample the data sample

# File lib/orocos/log/replay.rb, line 613
def step(time_sync=false,&block)
    #check if stream was generated otherwise call align
    if @stream == nil
        return align
    end
    stream_idx, time = @stream.advance
    if !stream_idx
        @current_sample = nil
        return
    end
    sample_info = @stream.sample_info(stream_idx)
    @current_sample = [stream_idx, time, sample_info]
    calc_statistics(time)

    #wait if replay is faster than the desired speed and time_sync is set to true
    if time_sync && @out_of_sync_delta > 0.001
        if @process_qt_events == true
            start_wait = Time.now
            while true
                if $qApp
                    $qApp.processEvents()
                end
                break if !@start_time                           #break if start_time was reseted throuh processEvents
                wait = @out_of_sync_delta -(Time.now - start_wait)
                if wait > 0.001
                    sleep [0.01,wait].min
                else
                    break
                end
                calc_statistics(time)
            end
        else
            sleep(@out_of_sync_delta)
        end
    end

    push_sample(stream_idx, sample_info)
end
step_back(time_sync=false,&block) click to toggle source

Gets the previous sample and writes it to the ports which are connected to the OutputPort and updated its readers (see step).

# File lib/orocos/log/replay.rb, line 665
def step_back(time_sync=false,&block)
    #check if stream was generated otherwise call start
    if !@stream
        align
        return
    end
    @current_sample = @stream.step_back
    return if !@current_sample
    @current_sample[2] = @stream.sample_info(@current_sample[0])
    push_sample(@current_sample[0], @current_sample[2])
end
stream_index_for_name(name) click to toggle source
# File lib/orocos/log/replay.rb, line 499
def stream_index_for_name(name)
    if @stream
        return @stream.stream_index_for_name(name)
    end
    throw "Stream is not initialized yet"
end
stream_index_for_type(name) click to toggle source
# File lib/orocos/log/replay.rb, line 506
def stream_index_for_type(name)
    if @stream
        return @stream.stream_index_for_type(name)
    end
    throw "Stream is not initialized yet"
end
sync_step?() click to toggle source

returns ture if the next sample must be replayed to meet synchronous replay

# File lib/orocos/log/replay.rb, line 567
def sync_step?
    calc_statistics
    if @out_of_sync_delta > 0.001
        false
    else
        true
    end
end
task(name) click to toggle source

Returns the simulated task with the given namen.

# File lib/orocos/log/replay.rb, line 383
def task(name)
    name2 = full_name(name)
    raise "cannot find TaskContext called #{name}" if !name2
    return @tasks[name2]
end
task?(name) click to toggle source

returns true if a task with the given name exists

# File lib/orocos/log/replay.rb, line 378
def task?(name)
    !!full_name(name)
end
tasks() click to toggle source

returns an array of all simulated tasks

# File lib/orocos/log/replay.rb, line 215
def tasks
    @tasks.values
end
time() click to toggle source

returns the time of the current sample replayed

# File lib/orocos/log/replay.rb, line 220
def time
    @base_time
end
time_source() click to toggle source

Returns where from the time used for alignment should be taken. It can be one of

false

use the time at which the logger received the data (“logical time”)

:use_sample_time

for streams whose data contains a field called “time” of type base/Time (from Rock's base/types package), use the time contained in that field. Otherwise, use the logical time.

See use_sample_time, use_sample_time=

# File lib/orocos/log/replay.rb, line 160
def time_source
    if use_sample_time
        return :use_sample_time
    else return false
    end
end
time_sync(&block) click to toggle source

this can be used to set a different time sync logic the code block has three parameters time = current sample time actual_delta = time between start of replay and now required_delta = time which should have elapsed between start and now to replay at the desired speed the code block must return the number of seconds which the replay shall wait before the sample is repalyed

Do not block the program otherwise qt events are no longer processed!!!

Example #time_sync do |time,actual_delta,required_delta|

my_object.busy? ? 1 : 0

end

# File lib/orocos/log/replay.rb, line 555
def time_sync(&block)
    if block_given?
        @time_sync_proc = block
    else
        @time_sync_proc = Proc.new do |time,actual_delta,required_delta|
            required_delta - actual_delta
        end
    end
end
timestamp(type_name, &block) click to toggle source

Declares how the timestamp can be extracted out of values of a given type

@example use the 'time' field in /base/samples/RigidBodyState as timestamp

replay.timestamp '/base/samples/RigidBodyState' do |rbs|
  rbs.time
end
# File lib/orocos/log/replay.rb, line 292
def timestamp(type_name, &block)
    timestamps[type_name] = block
end
track(value,filter=Hash.new) click to toggle source

If set to true all ports are replayed and are not filtered out by the filter otherwise only ports are replayed which have a reader or a connection to an other port

# File lib/orocos/log/replay.rb, line 300
def track(value,filter=Hash.new)
    options, filter = Kernel::filter_options(filter,[:tasks])
    @tasks.each_value do |task|
        task.track(value,filter) if !options.has_key?(:tasks) || task.name =~ options[:tasks]
    end
end