Ravn::BDE::

DeviceManager class

The actor wrapper around the Ravn::HAL::Manager used for device-side messaging.

Constants

GPS_MESSAGE_PREFIX

pattern used to find GPS messages

GPS_SPOOFING_INTERVAL

interval to send sys.gps* messages in seconds

GPS_SPOOF_DISTANCE

Distance away from provided latitude and longitude coordinates to randomly move away from. Roughly equivalent to 111 meters, is multiplied by a number from 0 to 5. www.usna.edu/Users/oceano/pguth/md_help/html/approx_equivalents.htm

Attributes

gps_spoofing_timer R

The Concurrent::TimerTask responsible for generating periodic position events if spoofing GPS.

random R

PRNG for GPS spoofing

spoofed_gps_coordinates RW

The calculated spoofed gps coordinates with an added randomized splay from the ones provided by the mission config. both are used by dependency injection for testing

Public Class Methods

new( * )

Set up instance data

# File lib/ravn/bde/device_manager.rb, line 35
def initialize( * )
        @random = Random.new
        @gps_spoofing_timer = self.make_gps_spoofing_timer
        @spoofed_gps_coordinates = self.get_spoofed_gps_coordinates

        super
end

Public Instance Methods

create_spoofed_gps_position_message()

Return a spoofed gps position message for use in GPS spoofing

# File lib/ravn/bde/device_manager.rb, line 187
def create_spoofed_gps_position_message
        gps_data = {
                pos: self.spoofed_gps_coordinates,
                hae: 0.0, # height above ellipsoid, altitude
                ce: 15.0 # lock level
        }

        return Ravn::HAL::Message.new( 'sys.gps.position', data: gps_data )
end
filter_up( message )

Reflect messages coming up the tree back down.

# File lib/ravn/bde/device_manager.rb, line 89
def filter_up( message )
        message.audit {}
        self.reflect_message( message )

        super
end
get_spoofed_gps_coordinates()

Return coordinates for GPS spoofing if it’s configured in the mission.

# File lib/ravn/bde/device_manager.rb, line 152
def get_spoofed_gps_coordinates
        coordinates = Ravn::BDE.mission[ :spoof_gps_coordinates ] or return nil

        # randomize a distance from those provided
        lat = self.randomize_coordinate( coordinates[0] )
        lon = self.randomize_coordinate( coordinates[1] )

        self.log.warn "Setting up GPS spoofing at: lat = %0.3f, lng = %0.3f" % [ lat, lon ]
        return [ lat, lon ]
end
handle_reset_device( *args )

Allow for resetting a device via a :reset_device message.

# File lib/ravn/bde/device_manager.rb, line 98
def handle_reset_device( *args )
        device, * = *args

        unless device.is_a?( Ravn::HAL::Device )
                raise ArgumentError, "expected a Ravn::HAL::Device to reset, got %p" % [ device ]
        end

        self.log.info "Pausing %p for a reset" % [ device ]
        device.reference.ask!( :pause! )
        self.log.warn "Resetting %p" % [ device ]
        device.reference.ask!( :reset! )
end
handle_spoof_gps( * )

Event handler for spoofed GPS timer message

# File lib/ravn/bde/device_manager.rb, line 173
def handle_spoof_gps( * )
        self.send_spoofed_gps_message
end
make_gps_spoofing_timer()

Return a Concurrent::TimerTask that will send a spoofed GPS message at the GPS_SPOOFING_INTERVAL.

# File lib/ravn/bde/device_manager.rb, line 200
def make_gps_spoofing_timer
        timer = Concurrent::TimerTask.new { self.tell(spoof_gps: true) }
        timer.execution_interval = GPS_SPOOFING_INTERVAL
        timer.add_observer( Ravn::LoggingTaskObserver.new(:spoofed_gps) )

        return timer
end
randomize_coordinate( coordinate )

Given an input coordinate, add or subtract a random distance from it the minimum should be 0 * 111m and the maximum should be 5 * 111m

# File lib/ravn/bde/device_manager.rb, line 166
def randomize_coordinate( coordinate )
        splay = GPS_SPOOF_DISTANCE * (5.0 - self.random.rand( 10.0 ))
        return coordinate.to_f + splay
end
route_ravn_message( message )

Route the given message; overridden to discard GPS messages if the manager is spoofing them.

# File lib/ravn/bde/device_manager.rb, line 114
def route_ravn_message( message )
        if self.spoofing_gps? && message.type&.start_with?( GPS_MESSAGE_PREFIX )
                self.log.warn "Skipping %p: spoofing GPS" % [ message ]
                return
        end

        self.sync_system_time( message ) if message.type == 'sys.gps.time'

        super
end
send_spoofed_gps_message( * )

Create and send a sys.gps.position message up and down the actor chain

# File lib/ravn/bde/device_manager.rb, line 179
def send_spoofed_gps_message( * )
        self.log.warn "Sending spoofed GPS: %p" % [ self.spoofed_gps_coordinates ]
        message = self.create_spoofed_gps_position_message
        self.filter_up( message )
end
spoofing_gps?()

Returns true if the manager is configured to generate spoofed GPS events.

# File lib/ravn/bde/device_manager.rb, line 146
def spoofing_gps?
        return self.spoofed_gps_coordinates ? true : false
end
start()

Start the DeviceManager actor.

# File lib/ravn/bde/device_manager.rb, line 65
def start
        state_manager = Ravn::Actor[ :state_manager ] or
                raise "Unable to get a state manager reference."

        self.log.info "Starting %d devices" % [ Ravn::HAL.devices.length ]
        Ravn::HAL.devices.each do |device_type|
                self.log.info "Starting %p" % [ device_type ]
                state_future = state_manager.ask( get_proxy: device_type )
                device_class = Ravn::HAL::Device.get_subclass( device_type )

                device_class.spawn!( device_type.to_sym, state_future )
        end
        self.log.debug "Done with device startup."

        if self.spoofing_gps?
                self.log.info "Starting GPS spoofing timer."
                self.gps_spoofing_timer.execute
        end

        super
end
sync_system_time( gps_time_message )

If the system clock is different than the GPS time, and it’s not an adjustment greater than the allowable_clock_drift setting, tell the Executor to correct it.

# File lib/ravn/bde/device_manager.rb, line 129
def sync_system_time( gps_time_message )
        timestamp = gps_time_message.data[ :time ] or return
        drift = ( Time.now - Time.at(timestamp) ).abs

        return unless drift >= Ravn::BDE.allowable_clock_drift
        self.log.debug "System clock +/- GPS source drift: %0.6f secs" % [ drift ]

        if Ravn::BDE.sync_system_clock?
                self.log.warn "Synchronizing system time: %p" % [ timestamp ]
                Ravn::Executor.exec( :set_date, timestamp.to_i )
        else
                self.log.debug "Cowardly refusing to sync system time. (Option not enabled.)"
        end
end