world-o-techno/gps/gps/receiver.rb

112 lines
3.1 KiB
Ruby

# Represents a provider of GPS fixes and a dispatcher of event callbacks for applications needing
# such fixes.
module Gps
class Receiver
include Fix
def initialize(options = {})
super
@last_latitude = @last_longitude = 0
@position_change_threshold = 0
@last_speed = 0
@last_course = 0
@last_altitude = 0
@last_satellites = 0
end
# Factory for creating a +Receiver+.
# Accepts an implementation and a hash of options, both optional. If no
# implementation is provided, the first is used by default. Implementations are in
# the module +Gps::Receivers+.
def self.create(arg = nil, args = {})
implementation = arg.respond_to?(:capitalize)? Receivers.const_get(arg.capitalize): Receivers.const_get(Receivers.constants[0])
options = arg.kind_of?(Hash)? arg: args
implementation.new(options)
end
# Sets the position from an array of the form [latitude, longitude], calling the
# _on_position_change_ callback if necessary.
def position=(value)
@latitude = value[0]
@longitude = value[1]
call_position_change_if_necessary
end
# Called on position change, but only if the change is greater than +threshold+ degrees.
# The block receives the amount of change in degrees.
def on_position_change(threshold = 0, &block)
@position_change_threshold = threshold
@on_position_change = block
end
# Called on speed change.
def on_speed_change(&block)
@on_speed_change = block
end
# Called on course change.
def on_course_change(&block)
@on_course_change = block
end
# Called when the altitude changes.
def on_altitude_change(&block)
@on_altitude_change = block
end
# Called when the number of visible satellites changes.
def on_satellites_change(&block)
@on_satellites_change = block
end
# Override this in children. Opens the connection, device, etc.
def start
@thread = Thread.new do
while true
update
end
end
end
# Override this in children. Closes the device, connection, etc. and stops updating.
def stop
@thread.kill if @thread
@thread = nil
end
# Returns _true_ if started, _false_ otherwise.
def started?
!@thread.nil? && @thread.alive?
end
# Override this in children, setting fix variables from the GPS receiver.
# Here we dispatch to callbacks if necessary.
def update
call_position_change_if_necessary
@on_speed_change.call if @on_speed_change and @speed != @last_speed
@last_speed = @speed
@on_course_change.call if @on_course_change and @course != @last_course
@last_course = @course
@on_altitude_change.call if @on_altitude_change and @altitude != @last_altitude
@last_altitude = @altitude
@on_satellites_change.call if @on_satellites_change and @satellites != @last_satellites
@last_satellites = @satellites
end
private
def call_position_change_if_necessary
if position_change > @position_change_threshold
@on_position_change.call(position_change) if @on_position_change
@last_latitude = @latitude
@last_longitude = @longitude
end
end
def position_change
(@latitude-@last_latitude).abs+(@longitude-@last_longitude).abs
end
end
module Receivers
end
end