hybridgroup-argus 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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