hybridgroup-argus 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 61222b712f9c3d858153e12e2a386aa03e8e06a1
4
- data.tar.gz: a0c4785df6cde5776eb45c997382b96f5de4e656
3
+ metadata.gz: 43c7894a41a1033f29b7da584853f6652165ed9c
4
+ data.tar.gz: 1d8496bc4cb2f4139d62b1e63ddbde9389f9be46
5
5
  SHA512:
6
- metadata.gz: 7f306362aafe950603de3dba9d6efefbaa834a23b4fa27c6e655f85d146b702b115543665dc6d7ea1c273ace9cadbc5a4aec7f68fe3280a763ddbf2c3580d29d
7
- data.tar.gz: 028aa4c216e1ebec8a6756635b54221ba87f6bfa6c6d34fb9d0f9ebd8226e464911048d2b9c954dbbb7d84cd46f19cbc138f163b76a9fdec3c480e20ea68e8c0
6
+ metadata.gz: 3ad023f7f146c1dcd8457734fdeb532f3462439bf24fb1da9872732c05c27d505be576bdd88e0204e5ffac9cdc154e237bda84278fadce24db96d8f4f48496a1
7
+ data.tar.gz: f162db2640775556506541e8ca6485a337b55d354bd2edd3705be92120d899830839a19492be7344c764497c94c54a3a03c35e8076927612f346cdfad5aa95a2
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 Jim Weirich
1
+ Copyright (c) 2012, 2013 Jim Weirich
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  ## Example
11
11
 
12
- <pre>
12
+ ```ruby
13
13
  require 'argus'
14
14
 
15
15
  drone = Argus::Drone.new
@@ -24,4 +24,30 @@
24
24
  drone.hover.land
25
25
  sleep 5
26
26
  drone.stop
27
- </pre>
27
+ ```
28
+
29
+ ## Using with external socket
30
+
31
+ You can also use Argus by providing an externally created socket. For example, if you are using Artoo (http://artoo.io), which makes use of celluloid-io (https://github.com/celluloid/celluloid-io). Normally in this use case, you would want to NOT use the automatic navigation callbacks, as they are not guaranteed to be thread safe within Celluloid.
32
+
33
+ ```ruby
34
+ require 'argus'
35
+ require 'celluloid/io'
36
+
37
+ include Celluloid::IO
38
+
39
+ socket = UDPSocket.new
40
+ drone = Argus::Drone.new(socket: socket)
41
+ drone.start(false) # do not auto-notify on nav callbacks
42
+
43
+ drone.take_off
44
+ sleep 5
45
+ drone.turn_right(1.0)
46
+ sleep 5
47
+ drone.turn_left(1.0)
48
+ sleep 5
49
+ drone.hover.land
50
+ sleep 5
51
+ drone.stop
52
+ ```
53
+
data/Rakefile CHANGED
@@ -7,3 +7,7 @@ task :default => :specs
7
7
  task :specs do
8
8
  sh "rspec spec"
9
9
  end
10
+
11
+ task :land do
12
+ ruby "-Ilib examples/land.rb"
13
+ end
data/lib/argus/cfields.rb CHANGED
@@ -3,8 +3,6 @@ require 'argus/float_encoding'
3
3
  module Argus
4
4
 
5
5
  module CFields
6
- include FloatEncoding
7
-
8
6
  def self.included(base)
9
7
  base.send :extend, ClassMethods
10
8
  end
@@ -44,29 +42,13 @@ module Argus
44
42
  def define_scaler_field(name, format, width, transform)
45
43
  index = allot(width)
46
44
  format_string << (width==1 ? format : "#{format}#{width}")
47
- if transform
48
- ivar = "@#{name}".to_sym
49
- define_method(name) {
50
- instance_variable_get(ivar) ||
51
- instance_variable_set(ivar, transform.call(@data[index]))
52
- }
53
- else
54
- define_method(name) { @data[index] }
55
- end
45
+ define_method(name) { @data[index] }
56
46
  end
57
47
 
58
48
  def define_array_field(name, size, format, width, transform)
59
49
  index = allot(width*size)
60
50
  format_string << "#{format}#{width*size}"
61
- if transform
62
- ivar = "@#{name}".to_sym
63
- define_method(name) {
64
- instance_variable_get(ivar) ||
65
- instance_variable_set(ivar, @data[index, size].map(&transform))
66
- }
67
- else
68
- define_method(name) { @data[index, size] }
69
- end
51
+ define_method(name) { @data[index, width*size] }
70
52
  end
71
53
 
72
54
  def uint32_t(name, size=nil)
@@ -78,7 +60,7 @@ module Argus
78
60
  end
79
61
 
80
62
  def float32_t(name, size=nil)
81
- define_field(name, size, "V") { |v| FloatEncoding.decode_float(v) }
63
+ define_field(name, size, "e")
82
64
  end
83
65
 
84
66
  def int32_t(name, size=nil)
@@ -86,11 +68,11 @@ module Argus
86
68
  end
87
69
 
88
70
  def matrix33_t(name, size=nil)
89
- define_field(name, size, "V", 9) { |v| nil }
71
+ define_field(name, size, "V", 9)
90
72
  end
91
73
 
92
74
  def vector31_t(name, size=nil)
93
- define_field(name, size, "V", 3) { |v| nil }
75
+ define_field(name, size, "V", 3)
94
76
  end
95
77
  end
96
78
  end
data/lib/argus/drone.rb CHANGED
@@ -6,9 +6,11 @@ module Argus
6
6
  class Drone
7
7
  attr_reader :controller, :enable_nav_monitor
8
8
 
9
- def initialize(socket=nil, host='192.168.1.1', port='5556')
10
- @socket = socket || UDPSocket.new
11
- @sender = Argus::UdpSender.new(@socket, host, port)
9
+ def initialize(opts={})
10
+ @host = opts[:remote_host] || '192.168.1.1'
11
+ @port = opts[:post] || '5556'
12
+ @socket = opts[:socket] || UDPSocket.new
13
+ @sender = opts[:sender] || Argus::UdpSender.new(socket: @socket, remote_host: @host, port: @port)
12
14
  @at = Argus::ATCommander.new(@sender)
13
15
  @controller = Argus::Controller.new(@at)
14
16
 
@@ -23,7 +25,7 @@ module Argus
23
25
  @enable_nav_monitor = enable_nav_monitor
24
26
 
25
27
  if enable_nav_monitor
26
- @nav = NavMonitor.new(@controller)
28
+ @nav = NavMonitor.new(@controller, @host)
27
29
  @nav.start
28
30
  end
29
31
 
@@ -52,6 +54,7 @@ module Argus
52
54
  turn_left turn_right
53
55
  front_camera bottom_camera
54
56
  config
57
+ led
55
58
  reset_watchdog
56
59
  ).each do |meth|
57
60
  define_method(meth) { |*args|
@@ -1,9 +1,11 @@
1
1
  module Argus
2
2
 
3
3
  class NavMonitor
4
- def initialize(controller)
4
+ attr_reader :streamer
5
+
6
+ def initialize(controller, remote_host)
5
7
  @controller = controller
6
- @nav = NavStreamer.new
8
+ @streamer = NavStreamer.new(remote_host: remote_host)
7
9
  @callbacks = []
8
10
  @mutex = Mutex.new
9
11
  @nav_data = nil
@@ -11,11 +13,11 @@ module Argus
11
13
  end
12
14
 
13
15
  def start
14
- @nav.start
16
+ @streamer.start
15
17
  @running = true
16
18
  @nav_thread = Thread.new do
17
19
  while @running
18
- data = @nav.receive_data
20
+ data = @streamer.receive_data
19
21
  update_nav_data(data) if data
20
22
  end
21
23
  end
@@ -54,7 +54,7 @@ module Argus
54
54
  ]
55
55
 
56
56
  def control_state_name
57
- CONTROL_STATE_NAMES[ctrl_state]
57
+ CONTROL_STATE_NAMES[ctrl_state & 0x0f]
58
58
  end
59
59
 
60
60
  def pitch
@@ -1,26 +1,111 @@
1
1
  require 'socket'
2
2
 
3
3
  module Argus
4
+
5
+ # NavStreamer State Transitions:
6
+ #
7
+ # State Trigger Next Action
8
+ # ------ -------------- ---- -----------------
9
+ # init start wait reconnect
10
+ #
11
+ # wait short_timeout wait request_nav_data
12
+ # wait long_timeout wait reconnect
13
+ # wait received_data run --
14
+ #
15
+ # run short_timeout run --
16
+ # run long_timeout wait reconnect
17
+ # run received_data run --
18
+
4
19
  class NavStreamer
5
- def initialize(socket=nil, host='192.168.1.1', port='5554')
6
- # TODO: Why is the port a string?
7
- @socket = socket || UDPSocket.new
8
- @host = host
9
- @port = port
10
- @socket.bind("0.0.0.0", port)
20
+ attr_reader :state
21
+
22
+ def initialize(opts={})
23
+ @state = :init
24
+ @socket = nil
25
+ @remote_host = opts.fetch(:remote_host)
26
+ @local_host = opts[:local_host] || '0.0.0.0'
27
+ @port = opts[:port] || 5554
28
+ @socket_class = opts[:socket] || UDPSocket
29
+ start_timer
11
30
  end
12
31
 
13
32
  def start
14
- @socket.send("\x01\x00\x00\x00", 0, @host, @port)
33
+ @state = :wait
34
+ reconnect
35
+ end
36
+
37
+ def short_timeout
38
+ if state == :wait
39
+ request_nav_data
40
+ end
41
+ end
42
+
43
+ def long_timeout
44
+ if @state == :wait || @state == :run
45
+ @state = :wait
46
+ reconnect
47
+ end
15
48
  end
16
49
 
17
50
  def receive_data
18
- data, from = @socket.recvfrom(1024)
51
+ data, from = @socket.recvfrom(1024)
19
52
  if data.unpack("V").first == 0x55667788
20
- NavData.new(data)
53
+ received_data
54
+ nav_data = NavData.new(data)
21
55
  else
22
56
  nil
23
57
  end
24
58
  end
59
+
60
+ def received_data
61
+ if state == :wait || state == :run
62
+ @state = :run
63
+ @long_flag = false
64
+ @short_flag = false
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def request_nav_data
71
+ @socket.send("\x01\x00\x00\x00", 0, @remote_host, @port)
72
+ end
73
+
74
+ def reconnect
75
+ disconnect if @socket
76
+ @socket = new_socket
77
+ @socket.bind(@local_host, @port) rescue nil
78
+ request_nav_data
79
+ end
80
+
81
+ def disconnect
82
+ @socket.close
83
+ @socket = nil
84
+ end
85
+
86
+ def new_socket
87
+ @socket_class.new
88
+ end
89
+
90
+ def tick
91
+ short_timeout if @short_flag
92
+ @short_flag = true
93
+ if @n == 0
94
+ long_timeout if @long_flag
95
+ @long_flag = true
96
+ end
97
+ @n += 1
98
+ @n = 0 if @n == 10
99
+ end
100
+
101
+ def start_timer
102
+ @n = 0
103
+ @thread = Thread.new do
104
+ loop do
105
+ tick
106
+ sleep 1.0
107
+ end
108
+ end
109
+ end
25
110
  end
26
111
  end
@@ -0,0 +1,62 @@
1
+ class TimeQueue
2
+ Item = Struct.new(:time, :value) do
3
+ def <=>(other)
4
+ time <=> other.time
5
+ end
6
+
7
+ def key
8
+ object_id
9
+ end
10
+
11
+ def to_s(basetime=nil)
12
+ if basetime
13
+ "#{value.inspect}@+#{time-basetime}"
14
+ else
15
+ "#{value.inspect}@#{time.strftime('%H:%M:%S.%L')}"
16
+ end
17
+ end
18
+ end
19
+
20
+ def initialize
21
+ @items = []
22
+ end
23
+
24
+ def add(time, value)
25
+ item = Item.new(time, value)
26
+ @items << item
27
+ @items.sort!
28
+ item.key
29
+ end
30
+
31
+ def remove(key)
32
+ @items.delete_if { |item| item.key == key }
33
+ end
34
+
35
+ def any_ready?(time)
36
+ ! @items.empty? && @items.first.time <= time
37
+ end
38
+
39
+ def all_ready(time)
40
+ result = []
41
+ each_ready(time) do |value| result << value end
42
+ result
43
+ end
44
+
45
+ def each_ready(time)
46
+ while any_ready?(time)
47
+ item = @items.shift
48
+ yield item.value
49
+ end
50
+ end
51
+
52
+ def to_s
53
+ base_time = nil
54
+ strings = @items[0,3].map { |item|
55
+ string = item.to_s(base_time)
56
+ base_time ||= item.time
57
+ string
58
+ }
59
+ strings << "..." if @items.size > 3
60
+ "[#{strings.join(', ')}]"
61
+ end
62
+ end
@@ -1,9 +1,9 @@
1
1
  module Argus
2
2
  class UdpSender
3
- def initialize(udp_socket, host=nil, port=nil)
4
- @udp_socket = udp_socket
5
- @host = host || '192.168.1.1'
6
- @port = port || 5556
3
+ def initialize(opts={})
4
+ @udp_socket = opts.fetch(:socket)
5
+ @host = opts.fetch(:remote_host)
6
+ @port = opts.fetch(:port, 5556)
7
7
  end
8
8
 
9
9
  def send_packet(data)
data/lib/argus/version.rb CHANGED
@@ -2,7 +2,7 @@ module Argus
2
2
  module Version # :nodoc: all
3
3
  NUMBERS = [
4
4
  MAJOR = 0,
5
- MINOR = 3,
5
+ MINOR = 4,
6
6
  BUILD = 0,
7
7
  ]
8
8
  end
@@ -4,10 +4,10 @@ module Argus
4
4
  class VideoStreamer
5
5
  attr_reader :tcp_socket, :host, :port
6
6
 
7
- def initialize(tcp_socket=nil, host='192.168.1.1', port=5555)
8
- @tcp_socket = tcp_socket || TCPSocket.new(host, port)
9
- @host = host
10
- @port = port
7
+ def initialize(opts={})
8
+ @host = opts[:host] || '192.168.1.1'
9
+ @port = opts[:port] || 5555
10
+ @tcp_socket = opts[:socket] || TCPSocket.new(@host, @port)
11
11
  end
12
12
 
13
13
  def start(udp_socket=nil)
@@ -4,7 +4,7 @@ module Argus
4
4
  describe Drone do
5
5
 
6
6
  Given(:socket) { flexmock("Socket", send: nil).should_ignore_missing }
7
- Given(:drone) { Drone.new(socket) }
7
+ Given(:drone) { Drone.new(socket: socket) }
8
8
 
9
9
  describe "default navigation monitor enabled" do
10
10
  Then { drone.enable_nav_monitor == false }
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'base64'
2
3
 
3
4
  module Argus
4
5
  describe NavOptionDemo do
@@ -6,39 +7,49 @@ module Argus
6
7
  FloatEncoding.encode_float(float)
7
8
  end
8
9
 
9
- Given(:raw_data) { [
10
- NavTag::DEMO, 148,
11
- 3, 0xcacacaca,
12
- f(5.0), f(6.0), f(7.0),
13
- -100000,
14
- f(-5.0), f(-6.0), f(-7.0),
15
- 33,
16
- [0]*9, [0]*3,
17
- 12, 34,
18
- [0]*9, [0]*3,
19
- ].flatten.pack("vv VV V3 l< V3 V V9 V3 VV V9 v3") }
10
+ # NOTE: This is a Base 64 encoded NavData packet recorded directly from the drone.
11
+ Given(:base64_data) {
12
+ "iHdmVdAEgA/5iwAAAAAAAAAAlAAAAAIAPAAAAADwREUAgCNFQFEiyAAAAABk" +
13
+ "AAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
14
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0AAADWP3i/6kNxPniCg72IpXO+64R4" +
15
+ "v+kAAD2hLGG9u7U6PatYfz8AAAAAAAAAAAAAdcMQAEgBAAAAAAAAAAAAAAAA" +
16
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
17
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
18
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
19
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
20
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
21
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
22
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8I" +
23
+ "ANQdAAA="
24
+ }
25
+ Given(:raw_data) { Base64.decode64(base64_data) }
26
+ Given(:nav_data) { NavData.new(raw_data) }
20
27
 
21
- When(:demo) { NavOptionDemo.new(raw_data) }
28
+ When(:demo) { nav_data.options.first }
22
29
 
23
30
  Then { ! demo.nil? }
31
+ Then { demo.tag == 0 }
24
32
 
25
- Then { demo.ctrl_state == 3 }
26
- Then { demo.control_state_name == :flying }
27
- Then { demo.vbat_flying_percentage == 0xcacacaca }
28
- Then { demo.battery_level == 0xcacacaca }
29
- Then { demo.theta == 5.0 }
30
- Then { demo.phi == 6.0 }
31
- Then { demo.psi == 7.0 }
32
- Then { demo.altitude == -100000 }
33
- Then { demo.vx == -5.0 }
34
- Then { demo.vy == -6.0 }
35
- Then { demo.vz == -7.0 }
36
- Then { demo.detection_camera_rot.nil? }
37
- Then { demo.detection_camera_trans.nil? }
38
- Then { demo.detection_tag_index == 12 }
39
- Then { demo.detection_camera_type == 34 }
40
- Then { demo.drone_camera_rot.nil? }
41
- Then { demo.drone_camera_trans.nil? }
33
+ Then { demo.ctrl_state == 0x20000 }
34
+ Then { demo.control_state_name == :default }
35
+ Then { demo.vbat_flying_percentage == 60 }
36
+ Then { demo.battery_level == 60 }
37
+ Then { demo.theta == 3151.0 }
38
+ Then { demo.phi == 2616.0 }
39
+ Then { demo.psi == -166213.0 }
40
+ Then { demo.pitch == 3.151 }
41
+ Then { demo.roll == 2.616 }
42
+ Then { demo.yaw == -166.213 }
43
+ Then { demo.altitude == 0 }
44
+ Then { demo.vx == about(0).delta(0.00000001) }
45
+ Then { demo.vy == about(0).delta(0.00000001) }
46
+ Then { demo.vz == about(0).delta(0.00000001) }
47
+ Then { demo.detection_camera_rot }
48
+ Then { demo.detection_camera_trans }
49
+ Then { demo.detection_tag_index == 0 }
50
+ Then { demo.detection_camera_type == 13 }
51
+ Then { demo.drone_camera_rot }
52
+ Then { demo.drone_camera_trans }
42
53
  end
43
54
 
44
55
  end
@@ -41,8 +41,8 @@ module Argus
41
41
  Then { detect.dist == [50, 51, 52, 53] }
42
42
  Then { detect.distance == [50, 51, 52, 53] }
43
43
  Then { detect.orientation_angle == [60.0, 61.0, 62.0, 63.0] }
44
- Then { detect.rotation == [nil, nil, nil, nil] }
45
- Then { detect.translation == [nil, nil, nil, nil] }
44
+ Then { detect.rotation.size == 9 * 4 }
45
+ Then { detect.translation.size == 3 * 4 }
46
46
  Then { detect.camera_source == [70, 71, 72, 73] }
47
47
  end
48
48
 
@@ -2,27 +2,110 @@ require 'spec_helper'
2
2
 
3
3
  module Argus
4
4
  describe NavStreamer do
5
+ Given(:remote_host) { '192.168.1.1' }
6
+ Given(:port) { 5554 }
5
7
  Given(:socket) { flexmock("Socket", send: nil).should_ignore_missing }
6
- Given(:streamer) { NavStreamer.new(socket) }
8
+ Given(:streamer) { NavStreamer.new(remote_host: remote_host, socket: flexmock(new: socket)) }
7
9
 
8
- context "starting the stream" do
9
- When { streamer.start }
10
- Then { socket.should have_received(:bind).with(String, Object) }
11
- Then { socket.should have_received(:send) }
12
- end
10
+ context "after starting" do
11
+ Given { streamer.start }
12
+
13
+ context "when receiving good data" do
14
+ Given(:bytes) { Bytes.make_nav_data(Bytes.make_header(0x1234, 0, 0)) }
15
+ Given { socket.should_receive(recvfrom: bytes) }
16
+ When(:nav_data) { streamer.receive_data }
17
+ Then { nav_data.state_mask == 0x1234}
18
+ end
13
19
 
14
- context "when receiving good data" do
15
- Given(:bytes) { Bytes.make_nav_data(Bytes.make_header(0x1234, 0, 0)) }
16
- Given { socket.should_receive(:recvfrom => bytes) }
17
- When(:nav_data) { streamer.receive_data }
18
- Then { nav_data.state_mask == 0x1234}
20
+ context "when receiving bad data" do
21
+ Given(:bytes) { [0x89, 0x77, 0x66, 0x55, 0x34, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].pack("C*") }
22
+ Given { socket.should_receive(:recvfrom => bytes) }
23
+ When(:nav_data) { streamer.receive_data }
24
+ Then { nav_data.nil? }
25
+ end
19
26
  end
20
27
 
21
- context "when receiving bad data" do
22
- Given(:bytes) { [0x89, 0x77, 0x66, 0x55, 0x34, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].pack("C*") }
23
- Given { socket.should_receive(:recvfrom => bytes) }
24
- When(:nav_data) { streamer.receive_data }
25
- Then { nav_data.nil? }
28
+ describe "State Transitions" do
29
+ Given {
30
+ flexmock(streamer, reconnect: nil, request_nav_data: nil)
31
+ }
32
+
33
+ def goto_wait
34
+ streamer.start
35
+ end
36
+
37
+ def goto_run
38
+ streamer.start
39
+ streamer.received_data
40
+ end
41
+
42
+ context "when init & start" do
43
+ Given { streamer.start }
44
+ Then { streamer.should have_received(:reconnect).once }
45
+ Then { streamer.state == :wait }
46
+ end
47
+
48
+ context "when init & short_timeout" do
49
+ Given { streamer.short_timeout }
50
+ Then { streamer.should have_received(:reconnect).never }
51
+ Then { streamer.should have_received(:request_nav_data).never }
52
+ Then { streamer.state == :init }
53
+ end
54
+
55
+ context "when init & long_timeout" do
56
+ Given { streamer.long_timeout }
57
+ Then { streamer.should have_received(:reconnect).never }
58
+ Then { streamer.should have_received(:request_nav_data).never }
59
+ Then { streamer.state == :init }
60
+ end
61
+
62
+ context "when wait & received_data" do
63
+ Given { goto_wait }
64
+ Given { streamer.received_data }
65
+ Then { streamer.should have_received(:reconnect).once }
66
+ Then { streamer.should have_received(:request_nav_data).never }
67
+ Then { streamer.state == :run }
68
+ end
69
+
70
+ context "when wait & short_timeout" do
71
+ Given { goto_wait }
72
+ Given { streamer.short_timeout }
73
+ Then { streamer.should have_received(:reconnect).once }
74
+ Then { streamer.should have_received(:request_nav_data).once }
75
+ Then { streamer.state == :wait }
76
+ end
77
+
78
+ context "when wait & long_timeout" do
79
+ Given { goto_wait }
80
+ Given { streamer.long_timeout }
81
+ Then { streamer.should have_received(:reconnect).twice }
82
+ Then { streamer.should have_received(:request_nav_data).never }
83
+ Then { streamer.state == :wait }
84
+ end
85
+
86
+ context "when run & received_data" do
87
+ Given { goto_run }
88
+ Given { streamer.received_data }
89
+ Then { streamer.should have_received(:reconnect).once }
90
+ Then { streamer.should have_received(:request_nav_data).never }
91
+ Then { streamer.state == :run }
92
+ end
93
+
94
+ context "when run & short_timeout" do
95
+ Given { goto_run }
96
+ Given { streamer.short_timeout }
97
+ Then { streamer.should have_received(:reconnect).once }
98
+ Then { streamer.should have_received(:request_nav_data).never }
99
+ Then { streamer.state == :run }
100
+ end
101
+
102
+ context "when run & long_timeout" do
103
+ Given { goto_run }
104
+ Given { streamer.long_timeout }
105
+ Then { streamer.should have_received(:reconnect).twice }
106
+ Then { streamer.should have_received(:request_nav_data).never }
107
+ Then { streamer.state == :wait }
108
+ end
26
109
  end
27
110
  end
28
111
  end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+ require 'time'
3
+
4
+ describe TimeQueue do
5
+ Given(:time) { Time.now }
6
+ Given(:tq) { TimeQueue.new }
7
+
8
+ context "with an empty queue" do
9
+ Then { ! tq.any_ready?(time+100) }
10
+ end
11
+
12
+ context "with several items" do
13
+ Given {
14
+ tq.add(time, :zero)
15
+ tq.add(time+2, :two)
16
+ tq.add(time+1, :one)
17
+ }
18
+ Then { ! tq.any_ready?(time-1) }
19
+ Then { tq.any_ready?(time) }
20
+
21
+ Then { tq.all_ready(time-1) == [] }
22
+ Then { tq.all_ready(time ) == [:zero] }
23
+ Then { tq.all_ready(time+1) == [:zero, :one] }
24
+ Then { tq.all_ready(time+2) == [:zero, :one, :two] }
25
+ end
26
+
27
+ describe "#to_s" do
28
+ Given(:time) { Time.parse("12:00:00") }
29
+ Given(:items) { [ ] }
30
+ Given {
31
+ items.each.with_index do |item, i| tq.add(time+i, item) end
32
+ }
33
+
34
+ context "with no items" do
35
+ Then { tq.to_s == "[]" }
36
+ end
37
+
38
+ context "with one item" do
39
+ Given(:items) { [ :zero ] }
40
+ Then { tq.to_s == "[:zero@12:00:00.000]" }
41
+ end
42
+
43
+ context "with four items" do
44
+ Given(:items) { [ :zero, :one, :two, :three ] }
45
+ Then { tq.to_s == "[:zero@12:00:00.000, :one@+1.0, :two@+2.0, ...]" }
46
+ end
47
+ end
48
+
49
+ describe "removing items" do
50
+ Given {
51
+ tq.add(time, :zero)
52
+ tq.add(time+2, :two)
53
+ }
54
+ Given!(:onekey) { tq.add(time+1, :one) }
55
+
56
+ When { tq.remove(onekey) }
57
+ let(:result) { tq.all_ready(time+100) }
58
+
59
+ Then { result == [:zero, :two] }
60
+ end
61
+ end
@@ -4,7 +4,7 @@ require 'socket'
4
4
  describe Argus::UdpSender do
5
5
  Given(:port) { '5500' }
6
6
  Given(:socket) { UDPSocket.new }
7
- Given(:sender) { Argus::UdpSender.new(socket, 'localhost', port) }
7
+ Given(:sender) { Argus::UdpSender.new(socket: socket, remote_host: 'localhost', port: port) }
8
8
  Given!(:server) {
9
9
  server = UDPSocket.new
10
10
  server.bind(nil, port)
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  module Argus
4
4
  describe VideoStreamer do
5
5
  Given(:tcp_socket) { flexmock("TCPSocket", send: nil).should_ignore_missing }
6
- Given(:streamer) { VideoStreamer.new(tcp_socket) }
6
+ Given(:streamer) { VideoStreamer.new(socket: tcp_socket) }
7
7
  Given(:udp_socket) { flexmock("UDPSocket", send: nil).should_ignore_missing }
8
8
 
9
9
  describe "starting the stream" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hybridgroup-argus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Weirich
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-05-13 00:00:00.000000000 Z
13
+ date: 2013-08-20 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec-given
@@ -56,6 +56,7 @@ files:
56
56
  - lib/argus/nav_option_vision_detect.rb
57
57
  - lib/argus/nav_streamer.rb
58
58
  - lib/argus/nav_tag.rb
59
+ - lib/argus/time_queue.rb
59
60
  - lib/argus/udp_sender.rb
60
61
  - lib/argus/version.rb
61
62
  - lib/argus/video_data.rb
@@ -74,6 +75,7 @@ files:
74
75
  - spec/argus/nav_option_unknown_spec.rb
75
76
  - spec/argus/nav_option_vision_detect_spec.rb
76
77
  - spec/argus/nav_streamer_spec.rb
78
+ - spec/argus/time_queue_spec.rb
77
79
  - spec/argus/udp_sender_spec.rb
78
80
  - spec/argus/video_data_envelope_spec.rb
79
81
  - spec/argus/video_data_spec.rb