Ravn::BDE::
DeviceManager
class
The actor wrapper around the Ravn::HAL::Manager used for device-side messaging.
- 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
- 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
Set up instance data
def initialize( * )
@random = Random.new
@gps_spoofing_timer = self.make_gps_spoofing_timer
@spoofed_gps_coordinates = self.get_spoofed_gps_coordinates
super
end
create_spoofed_gps_position_message()
Return a spoofed gps position message for use in GPS spoofing
def create_spoofed_gps_position_message
gps_data = {
pos: self.spoofed_gps_coordinates,
hae: 0.0,
ce: 15.0
}
return Ravn::HAL::Message.new( 'sys.gps.position', data: gps_data )
end
Reflect messages coming up the tree back down.
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.
def get_spoofed_gps_coordinates
coordinates = Ravn::BDE.mission[ :spoof_gps_coordinates ] or return nil
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.
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
Event handler for spoofed GPS timer message
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
.
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
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.
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
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
Returns true
if the manager is configured to generate spoofed GPS events.
def spoofing_gps?
return self.spoofed_gps_coordinates ? true : false
end
Start the DeviceManager
actor.
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.
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