class Crubyflie::TOC
A Table Of Contents It is a hash that stores a group index. Each group is a Hash indexed by element ID that stores TOC
element
Attributes
Public Class Methods
Initializes the hash @param cache_folder [String] where is the cache for this toc stored @param element_class [Class] the class type we should instantiate
TOC elements to, when fetching them from the crazyflie
# File lib/crubyflie/crazyflie/toc.rb, line 52 def initialize(cache_folder=nil, element_class=TOCElement) @toc = {} @cache = TOCCache.new(cache_folder) @element_class = element_class end
Public Instance Methods
Get a TOC
element @param name_or_id [String,Symbol] name or ident of the element @param mode [Symbol] get it :by_name, :by_id, :both @return [TocElement, nil] the element or nil if not found
# File lib/crubyflie/crazyflie/toc.rb, line 62 def [](name_or_id, mode=:both) by_name_element = nil by_id_element = nil # Find by name if [:both, :by_name].include?(mode) group = name = nil if name_or_id.is_a?(String) group, name = name_or_id.split(".", 2) end if name.nil? name = group group = nil end if group gr = @toc[group] by_name_element = gr[name] if gr else @toc.each do |group_name, group| candidate = group[name] by_name_element = candidate if candidate break if candidate end end end if [:both, :by_id].include?(mode) @toc.each do |group_name, group| group.each do |name, element| by_id_element = element if element.ident == name_or_id break if by_id_element end end end return by_name_element || by_id_element end
Saves this TOC
into cache
# File lib/crubyflie/crazyflie/toc.rb, line 112 def export_to_cache(crc) @cache.insert(crc, @toc) end
Fetches a TOC
from crazyflie in a synchronous way Instead of a TOCFetcher (as in the python library), we just found easier to take advantage of the facility queues and read them (and block when there is nothing to read) to initialize the TOC
. Doing it this way not only saves to have to register and chain callbacks unrelated places (as Crazyflie
class), but also to reorder incoming TOCElement
packages if they come unordered (we just requeue them). This might happen if a package needs to be resent and the answer for the next one comes earlier.
This function should be preferably called before starting any other activities (send/receive threads) in the relevant facilities. @param crazyflie [Crazyflie] used to send packages @param port [Integer] the port to send the packages @param in_queue [Integer] a queue on which the responses to the
sent packages are queued
# File lib/crubyflie/crazyflie/toc.rb, line 150 def fetch_from_crazyflie(crazyflie, port, in_queue) # http://wiki.bitcraze.se/projects:crazyflie:firmware:comm_protocol # #table_of_content_access packet = CRTPPacket.new(0, [CMD_TOC_INFO]) packet.modify_header(nil, port, TOC_CHANNEL) in_queue.clear() crazyflie.send_packet(packet, true) response = in_queue.pop() # we block here if none :) while response.channel != TOC_CHANNEL do in_queue << response logger.debug "Got a non-TOC packet. Requeueing..." Thread.pass # @todo timeout response = in_queue.pop() end data = response.data # command = data[0] # Repack the payload payload = response.data_repack[1..-1] # get rid of byte 0 # The crc comes in an unsigned int (L) in little endian (<) total_toc_items, crc = payload[0..5].unpack('CL<') hex_crc = crc.to_s(16) logger.debug "TOC crc #{hex_crc}, #{total_toc_items} items" import_from_cache(hex_crc) if !@toc.nil? # in cache so we can stop here logger.debug "TOC found in cache" return end logger.debug "Not in cache" @toc = {} # We proceed to request all the TOC elements requested_item = 0 while requested_item < total_toc_items do wait = WAIT_PACKET_TIMEOUT request_toc_element(crazyflie, requested_item, port) begin response = timeout(wait, WaitTimeoutException) do response = in_queue.pop() # block here end rescue retries ||= 0 retries += 1 retry if retries < 2 logger.error("Timeout reached waiting for TOC element") raise $! end if response.channel != TOC_CHANNEL # Requeue in_queue << response mesg = "Got a non-TOC packet on #{response.channel}." mesg << " Requeueing..." logger.debug(mesg) Thread.pass next end payload = response.data_repack()[1..-1] # leave byte 0 out toc_elem = @element_class.new(payload) if (a = requested_item) != (b = toc_elem.ident()) logger.debug "#{port}: Expected #{a}, but got #{b}" if b > a logger.debug "Requeing" # this way we are ordering items in_queue << response end next end insert(toc_elem) logger.debug("Added #{toc_elem.ident} to TOC") requested_item += 1 end export_to_cache(hex_crc) end
Retrieves this TOC
from the cache
# File lib/crubyflie/crazyflie/toc.rb, line 117 def import_from_cache(crc) @toc = @cache.fetch(crc) end
Insert a TOC
element in the TOC
@param element [TocElement] the name of the element group
# File lib/crubyflie/crazyflie/toc.rb, line 103 def insert(element) group = element.group name = element.name @toc[group] = {} if @toc[group].nil? @toc[group][name] = element end
Produce a simple string representation of the TOC
@return [String] a pretty string
# File lib/crubyflie/crazyflie/toc.rb, line 123 def to_s s = "" @toc.each do |group,v| s << "- #{group}\n" v.each do |name, elem| s << " * #{name} (#{elem.ctype}/##{elem.type_id})\n" end end return s end
Private Instance Methods
# File lib/crubyflie/crazyflie/toc.rb, line 230 def request_toc_element(crazyflie, index, port) packet = CRTPPacket.new(0, [CMD_TOC_ELEMENT, index]) packet.modify_header(nil, port, TOC_CHANNEL) crazyflie.send_packet(packet, true) end