class LogTools::Converter

Attributes

converters[R]
from[RW]
keep_registry[RW]
logger[RW]
output_folder[RW]
post_fix[RW]
pre_fix[RW]
streams[RW]
time_offset[RW]
to[RW]
use_sample_time[RW]

Public Class Methods

new() click to toggle source
# File lib/log_tools/converter.rb, line 147
def initialize
    @current_converter = nil
    @post_fix =""
    @pre_fix =""
    @from = nil
    @to = nil
    @streams = []
    @use_sample_time = false
    @output_folder = "updated"
    @time_offset = 0
    @keep_registry = false
    reload_converter
end
register(*parameter,&block) click to toggle source

method to register custom converters it is allowed to use #deep_cast insight the converter to convert subfields

# File lib/log_tools/converter.rb, line 142
def self.register(*parameter,&block)
    @converters << TypeConverter.new(*parameter,&block)
    @converters.sort!{|a,b| a.time_to <=> b.time_to}
end

Public Instance Methods

clear() click to toggle source
# File lib/log_tools/converter.rb, line 286
def clear
    @converters.clear
end
convert(*logfiles) click to toggle source

converts logfiles to a new version if the last parameter is a Time object the logfiles are converted to a version which was valid at given time. The current Orocos.registry must have the same type version !!!

# File lib/log_tools/converter.rb, line 188
def convert(*logfiles)
    if @use_sample_time && !@use_sample_time.respond_to?(:to_sym)
        @use_sample_time = :time
    end

    #create folder if given
    if output_folder && !File.directory?(output_folder)
        Dir.mkdir(output_folder)
    end

    logfiles.flatten!      

    #check last parameters
    final_registry = nil
    if logfiles.last.is_a? Typelib::Registry
        final_registry = logfiles.pop
    else
        final_registry = Orocos.registry
    end

    @current_registry = final_registry # this has to be removed later
    time_to=Time.now
    if logfiles.last.is_a? Time
        time_to = logfiles.pop
    end

    logfiles.each do |logfile|
        Converter.info "converting #{logfile}"

        file = Pocolog::Logfiles.open(logfile)
        #we have to create the log file manually because we do not want to
        #use the automatically applied file name logic
        output = Pocolog::Logfiles.new(Typelib::Registry.new)
        output.new_file(new_file_path(logfile))
        
        time = Time.now
        file.streams.each do |stream|
            if !streams.empty? && !streams.include?(stream.name)
                #ignore all streams which are not listed if a filter is given
                Converter.info "ignoring stream #{stream.name} (#{stream.size} samples)"
                next
            end

            Converter.info " converting stream #{stream.name} (#{stream.size} samples)" + 
                (@use_sample_time ? " using :#{@use_sample_time} field as time source" : "")
            stream_output = nil
            index = 1
            last_ignore = nil
            wrote_warning = !@use_sample_time
            final_registry = stream.registry if keep_registry
            stream.samples.each do |rt,lg,sample|
                ignore = (from && lg < from) || (to && lg > to)
                if last_ignore != ignore
                    Converter.info "### ignoring samples enabled  ###" if ignore
                    Converter.info "### ignoring samples disabled ###" if !ignore
                    last_ignore = ignore
                end

                if (Time.now-time).to_f < 1
                    Converter.debug "    #{stream.name}.sample #{index}/#{stream.size}"
                else
                    time = Time.now
                    Converter.info "    #{stream.name}.sample #{index}/#{stream.size}"
                end
                if !ignore
                    # Undo any custom convertions that typelib might have applied
                    sample = Typelib.from_ruby(sample, stream.type)
                    begin
                        new_sample = convert_type(sample,rt,time_to,final_registry)
                    rescue Orocos::TypekitTypeNotFound => e
                        Converter.warn "skipping stream #{stream.name} due to a missing type definition #{sample.class.name} in the orocos registry."
                        break
                    end

                    new_sample_class = new_sample.class
                    #use type_name of the old stream if we have for example a fixnum
                    new_sample_class = stream.type_name unless new_sample_class.respond_to? :registry
                    stream_output ||= output.create_stream(stream.name,new_sample_class,stream.metadata)
                    if(@use_sample_time && (new_sample.respond_to? @use_sample_time))
                        sample_time = new_sample.get_field(@use_sample_time)
                        stream_output.write(rt,sample_time+@time_offset,new_sample)
                    else
                        if(@use_sample_time && !wrote_warning)
                            Converter.warn "stream #{stream.name} has no field '#{@use_sample_time}' falling back to the logfile time"
                            wrote_warning = true
                        end
                        stream_output.write(rt,lg+@time_offset,new_sample)
                    end
                end
                index += 1
            end
            Converter.info "### ignoring samples disabled ###" if last_ignore
            Converter.info "    done!"
        end
        output.close
    end
end
convert_type(sample,time_from,time_to=Time.now,final_registry=Orocos.registry) click to toggle source

convertes sample to a new type which was valid at time_to the final_registry must have a compatible version!!!

# File lib/log_tools/converter.rb, line 292
def convert_type(sample,time_from,time_to=Time.now,final_registry=Orocos.registry)
    if(sample.is_a?(Fixnum)||sample.is_a?(Float))
        return sample
    end

    raise 'No time periode is given!!!' unless time_from && time_to
    _converters = @converters.map{|c|(c.time_to>=time_from && c.time_to <= time_to) ? c : nil }
    _converters.compact!
    sample_was_converted = false
    if !_converters.empty?
        _converters.each_with_index do |c,index|
            @current_converter = c
            #update current_registry
            if @current_converter.convert?(sample)
                Converter.debug "     Using Converter: #{c.name}" 
                @current_registry = @current_converter.new_registry
                new_sample = @current_converter.new_sample_for sample
                deep_cast(new_sample,sample)
                sample = new_sample
                sample = Typelib.from_ruby(sample, sample.class)
                sample_was_converted = true
            end
        end
    end

    if !sample_was_converted
        #this can be removed later if typelib is supporting daisy chain
        @current_registry = nil         # we have to convert it via deep_cast
    end

    #this is needed to be sure that the version is compatible to the
    #final registry
    if @current_registry != final_registry
        @current_converter = nil
        @current_registry = final_registry
        new_sample = nil
        begin
            new_sample = @current_registry.get(sample.class.name).new
        rescue Typelib::NotFound => e
            Orocos.load_typekit_for sample.class.name, false 
            new_sample = @current_registry.get(sample.class.name).new
        end
        deep_cast(new_sample,sample)
        sample = new_sample
    end
    sample
end
copy_vector(to,from) click to toggle source

copies a vector

# File lib/log_tools/converter.rb, line 341
def copy_vector(to,from)
    if to.respond_to?(:data)
        from.data.to_a.each_with_index do |data,i|
            to.data[i] = data 
        end
    else
        from.data.to_a.each_with_index do |data,i|
            to[i] = data 
        end
    end
end
deep_cast(dest,src,*excluded_fields) click to toggle source

converts src Typelib::Type int dest Typelib::Type uses converters to convert fields and sub fields which have changed

# File lib/log_tools/converter.rb, line 355
def deep_cast(dest,src,*excluded_fields)
    @@message = false if !defined? @@message

    excluded_fields.flatten!

    if !dest.is_a?(Typelib::Type) || !src.is_a?(Typelib::Type)
        raise "Cannot convert #{src.class.name} into #{dest.class.name}. "+
            "Register a converter which does the conversion"
    end

    do_not_cast_self = excluded_fields.include?(:self) ? true : false
    excluded_fields.delete :self if do_not_cast_self

    src_type  = src.class
    dest_type = dest.class

    if @current_converter && @current_converter.convert?(src.class.name) && !do_not_cast_self
        Converter.debug "convert for #{dest_type}"
        @current_converter.convert(dest,src,nil,self)
    else
        if(dest_type.casts_to?(src_type) && !do_not_cast_self &&(!@current_converter||!@current_converter.convert_field_from?(src)))
            Converter.debug "copy for #{dest_type}" #if @@message
            Typelib.copy(dest, src)
        elsif src_type < Typelib::ContainerType
            Converter.debug "deep cast for #{src_type}"
            dest.clear
            element_type = dest_type.deference
            src.each do |src_element|
                dst_element = element_type.new
                if src_element.is_a? Typelib::Type
                    deep_cast(dst_element, src_element)
                else
                    dst_element = src_element
                end
                dest.push dst_element
            end
        elsif src_type < Typelib::CompoundType
            Converter.debug "deep cast2 for #{src_type}" if @@message

            dest_fields = dest_type.get_fields.
                map { |field_name, _| field_name }.
                to_set

            src_type.each_field do |field_name, src_field_type|
                next if excluded_fields.include? field_name
                next if !dest_fields.include?(field_name)

                dest_field_type = dest_type[field_name]
                src_value = src.raw_get_field(field_name)

                if src_value.is_a? NilClass
                    Log.warn "field #{field_name} has an undefined value"
                    next
                end
                if src_value.is_a? Typelib::Type 
                    if @current_converter && @current_converter.convert?(src_field_type.name)
                        dest.raw_set_field(field_name,@current_converter.new_sample_for(src_field_type.name))
                    end
                    excluded_fields2 = excluded_fields.map{|field| field.to_s.match("#{field_name}\.(.*)");$1}.compact
                    deep_cast(dest.raw_get_field(field_name), src_value,excluded_fields2)
                else
                    #check if the value has to be converted
                    if(@current_converter && @current_converter.convert?(src_field_type.name))
                        Converter.debug "convert2 for #{src_field_type.name}" if @@message
                        #be carefull string, symbol etc are no reference
                        dest_temp = @current_converter.new_sample_for src_field_type.name
                        dest_temp = @current_converter.convert(dest_temp,src.raw_get_field(field_name),src_field_type.name,self)
                        dest.raw_set_field(field_name,dest_temp)
                    else
                        dest.raw_set_field(field_name,src.raw_get_field(field_name))
                    end
                end
            end
        elsif src.respond_to? :each_with_index
            src.each_with_index do |sample,index|
                deep_cast(dest[index],sample)
            end
        elsif src.kind_of?(Typelib::NumericType) && dest.kind_of?(Typelib::NumericType)
            # at the moment typelib cannot handle the conversion therefore
            # convert to and from ruby to do the conversion
            Typelib::copy(dest,Typelib::from_ruby(src.to_ruby,dest.class))
        else
            raise ArgumentError, "cannot deep cast #{src_type} into #{dest_type}"
        end
    end
    dest
rescue SystemStackError => e
    Converter.error "Stack level to deep. Have you called deep_cast from your converter #{@current_converter.name} for type #{dest.class.name} and forgot to exclude :self?"
    exit(1)
end
new_file_path(old_file_path) click to toggle source

creates a file path for a new file based on the old file path

# File lib/log_tools/converter.rb, line 175
def new_file_path(old_file_path)
    if File.directory?(output_folder)
        File.join(output_folder,pre_fix+File.basename(old_file_path,".log")+post_fix+".log")
    else
        File.join(File.dirname(old_file_path),pre_fix+File.basename(old_file_path,".log")+post_fix+".log")
    end
end
register(*parameter,&block) click to toggle source
# File lib/log_tools/converter.rb, line 169
def register(*parameter,&block)
    @converters << TypeConverter.new(*parameter,&block)
    @converters.sort!{|a,b| a.time_to <=> b.time_to}
end
reload_converter() click to toggle source
# File lib/log_tools/converter.rb, line 161
def reload_converter
    @converters = Converter.converters.clone
end
streams=(streams) click to toggle source
# File lib/log_tools/converter.rb, line 165
def streams=(streams)
    @streams = Array(streams)
end