class Crubyflie::Log

The logging facility class

This class is used to read packages received in the Logging port. It maintains a list of log blocks, which are conveniently added, or removed and for which logging is started or stopped. When a packet with new information for log block comes in, the block in question unpacks the data and triggers a callback.

In Crubyflie, the Log class includes all the functionality which is to be found in the Python library LogEntry class (start logging, add block etc) and the Crazyflie class (callbacks for intialization), so interfacing with Log should be done through this class primarily.

Unlike the original Pyhton library, there are no callbacks registered somewhere else or anything and functions being called from them. In turn, the Crazyflie class will queue all the logging requests in the @in_queue while a thread in the Logging class takes care of processing them and doing the appropiate. This saves us from registering callbacks in other places and from selecting which data we are to use here.

Attributes

log_blocks[R]
toc[R]

Public Class Methods

new(crazyflie) click to toggle source

Store the crazyflie, find the incoming packet queue for this facility and initialize a new TOC @param crazyflie [Crazyflie]

# File lib/crubyflie/crazyflie/log.rb, line 175
def initialize(crazyflie)
    @log_blocks = {}
    @crazyflie = crazyflie
    @in_queue = crazyflie.crtp_queues[:logging]
    @toc = TOC.new(@crazyflie.cache_folder, LogTOCElement)
    @packet_reader_thread = nil
end

Public Instance Methods

[](block_id) click to toggle source

Finds a log block by id @param block_id [Integer] the block ID @return p

# File lib/crubyflie/crazyflie/log.rb, line 302
def [](block_id)
    @log_blocks[block_id]
end
create_log_block(log_conf) click to toggle source

Creates a log block with the information from a configuration object. @param log_conf [LogConf] Configuration for this block @return [Integer] block ID if things went well,

# File lib/crubyflie/crazyflie/log.rb, line 198
def create_log_block(log_conf)
    start_packet_reader_thread() if !@packet_reader_thread
    block = LogBlock.new(log_conf.variables,
                         {:period => log_conf.period})
    block_id = block.ident
    @log_blocks[block_id] = block
    packet = packet_factory()
    packet.data = [CMD_CREATE_BLOCK, block_id]
    log_conf.variables.each do |var|
        if var.is_toc_variable?
            packet.data << var.stored_fetch_as
            packet.data << @toc[var.name].ident
        else
            bin_stored_fetch_as = [var.stored_fetch_as].pack('C')
            bin_address = [var.address].pack('L<')
            packet.data += bin_stored_fetch_as.unpack('C*')
            packet.data += bin_address.unpack('C*')
        end
    end
    logger.debug "Adding block #{block_id}"
    @crazyflie.send_packet(packet)
    return block_id
end
delete_block(block_id) click to toggle source

Sends the DELETE_BLOCK command to the Crazyflie for a given block. It fails silently if the block does not exist. To be called after stop_logging.

# File lib/crubyflie/crazyflie/log.rb, line 259
def delete_block(block_id)
    block = @log_blocks.delete(block_id)
    return if !block
    packet = packet_factory()
    packet.data = [CMD_DELETE_BLOCK, block_id]
    @crazyflie.send_packet(packet)
end
refresh_toc() click to toggle source

Refreshes the TOC. TOC class implement this step synchronously so there is no need to provide callbacks or anything

# File lib/crubyflie/crazyflie/log.rb, line 185
def refresh_toc
    reset_packet = packet_factory()
    reset_packet.data = [CMD_RESET_LOGGING]
    port = Crazyflie::CRTP_PORTS[:logging]
    channel = TOC_CHANNEL
    @crazyflie.send_packet(reset_packet)
    @toc.fetch_from_crazyflie(@crazyflie, port, @in_queue)
end
start_logging(block_id, &data_callback) click to toggle source

Sends the START_LOGGING command for a given block. It should be called after create_toc_log_block. This call will return immediately, but the provided block will be called regularly as logging data is received, until stop_logging is issued for the same log Crazyflie. It fails silently if the block does not exist.

@param block_id [Integer] @param data_callback [Proc] a block to be called everytime

the log data is received.
# File lib/crubyflie/crazyflie/log.rb, line 232
def start_logging(block_id, &data_callback)
    block = @log_blocks[block_id]
    block.data_callback = data_callback
    return if !block
    start_packet_reader_thread() if !@packet_reader_thread
    packet = packet_factory()
    period = block.period
    packet.data = [CMD_START_LOGGING, block_id, period]
    logger.debug("Start logging on #{block_id} every #{period*10} ms")
    @crazyflie.send_packet(packet)
end
start_packet_reader_thread() click to toggle source

A thread that processes the queue of packets intended for this facility. Recommended to start it after TOC has been refreshed.

# File lib/crubyflie/crazyflie/log.rb, line 269
def start_packet_reader_thread
    stop_packet_reader_thread()
    @packet_reader_thread = Thread.new do
        Thread.current.priority = -4
        loop do
            packet = @in_queue.pop() # block here if nothing is up
            # @todo align these two
            case packet.channel()
            when LOG_SETTINGS_CHANNEL
                handle_settings_packet(packet)
            when LOG_DATA_CHANNEL
                handle_logdata_packet(packet)
            when TOC_CHANNEL
                # We are refreshing TOC probably
                @in_queue << packet
                sleep 0.2
            else
                logger.debug("Log on #{packet.channel}. Cannot handle")
                ## in_queue << packet
            end
        end
    end
end
stop_logging(block_id) click to toggle source

Sends the STOP_LOGGING command to the crazyflie for a given block. It fails silently if the block does not exist. @param block_id [Integer]

# File lib/crubyflie/crazyflie/log.rb, line 247
def stop_logging(block_id)
    block = @log_blocks[block_id]
    return if !block
    packet = packet_factory()
    packet.data = [CMD_STOP_LOGGING, block_id]
    logger.debug("Stop logging on #{block_id}")
    @crazyflie.send_packet(packet)
end
stop_packet_reader_thread() click to toggle source

Stop the facility’s packet processing

# File lib/crubyflie/crazyflie/log.rb, line 294
def stop_packet_reader_thread
    @packet_reader_thread.kill() if @packet_reader_thread
    @packet_reader_thread = nil
end

Private Instance Methods

handle_logdata_packet(packet) click to toggle source
# File lib/crubyflie/crazyflie/log.rb, line 358
def handle_logdata_packet(packet)
    block_id = packet.data[0]
    #logger.debug("Handling log data for block #{block_id}")
    #timestamp = packet.data[1..3] . pack and re unpack as 4 bytes
    logdata = packet.data_repack()[4..-1]
    block = @log_blocks[block_id]
    if block
        block.unpack_log_data(logdata)
    else
        logger.error "No entry for logdata for block #{block_id}"
    end
end
handle_settings_packet(packet) click to toggle source

Processes an incoming settings packet. Sort of a callback @param packet [CRTPPacket] the packet on the settings channel

# File lib/crubyflie/crazyflie/log.rb, line 308
def handle_settings_packet(packet)
    cmd = packet.data[0] # byte 0 of data
    payload = packet.data_repack()[1..-1] # the rest of data

    block_id = payload[0].ord()
    #See projects:crazyflie:firmware:comm_protocol#list_of_return_codes
    # @todo write down error codes in some constant
    error_st = payload[1].ord() # 0 is no error

    case cmd
    when CMD_CREATE_BLOCK
        if !@log_blocks[block_id]
            logger.error "No log entry for #{block_id}"
            return
        end
        if error_st != 0
            hex_error = error_st.to_s(16)
            mesg = "Error creating block #{block_id}: #{hex_error}"
            logger.error(mesg)
            return
        end
        # Block was created, let's start logging
        logger.debug "Log block #{block_id} created"
        # We do not start logging right away do we?
    when CMD_APPEND_BLOCK
        logger.debug "Received log settings with APPEND_LOG"
    when CMD_DELETE_BLOCK
        logger.debug "Received log settings with DELETE_LOG"
    when CMD_START_LOGGING
        if error_st != 0
            hex_error = error_st.to_s(16)
            mesg = "Error starting to log #{block_id}: #{hex_error}"
            logger.error(mesg)
        else
            logger.debug "Logging started for #{block_id}"
        end
    when CMD_STOP_LOGGING
        # @todo
        logger.debug "Received log settings with STOP_LOGGING"
    when CMD_RESET_LOGGING
        # @todo
        logger.debug "Received log settings with RESET_LOGGING"
    else
        mesg = "Received log settings with #{cmd}. Dont now what to do"
        logger.warn(mesg)
    end

end
packet_factory() click to toggle source
# File lib/crubyflie/crazyflie/log.rb, line 372
def packet_factory
    packet = CRTPPacket.new()
    packet.modify_header(nil,
                         CRTP_PORTS[:logging],
                         LOG_SETTINGS_CHANNEL)
    return packet
end