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 +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +28 -2
- data/Rakefile +4 -0
- data/lib/argus/cfields.rb +5 -23
- data/lib/argus/drone.rb +7 -4
- data/lib/argus/nav_monitor.rb +6 -4
- data/lib/argus/nav_option_demo.rb +1 -1
- data/lib/argus/nav_streamer.rb +94 -9
- data/lib/argus/time_queue.rb +62 -0
- data/lib/argus/udp_sender.rb +4 -4
- data/lib/argus/version.rb +1 -1
- data/lib/argus/video_streamer.rb +4 -4
- data/spec/argus/drone_spec.rb +1 -1
- data/spec/argus/nav_option_demo_spec.rb +40 -29
- data/spec/argus/nav_option_vision_detect_spec.rb +2 -2
- data/spec/argus/nav_streamer_spec.rb +99 -16
- data/spec/argus/time_queue_spec.rb +61 -0
- data/spec/argus/udp_sender_spec.rb +1 -1
- data/spec/argus/video_streamer_spec.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43c7894a41a1033f29b7da584853f6652165ed9c
|
4
|
+
data.tar.gz: 1d8496bc4cb2f4139d62b1e63ddbde9389f9be46
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ad023f7f146c1dcd8457734fdeb532f3462439bf24fb1da9872732c05c27d505be576bdd88e0204e5ffac9cdc154e237bda84278fadce24db96d8f4f48496a1
|
7
|
+
data.tar.gz: f162db2640775556506541e8ca6485a337b55d354bd2edd3705be92120d899830839a19492be7344c764497c94c54a3a03c35e8076927612f346cdfad5aa95a2
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
|
10
10
|
## Example
|
11
11
|
|
12
|
-
|
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
|
-
|
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
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
|
-
|
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
|
-
|
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, "
|
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)
|
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)
|
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(
|
10
|
-
@
|
11
|
-
@
|
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|
|
data/lib/argus/nav_monitor.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
module Argus
|
2
2
|
|
3
3
|
class NavMonitor
|
4
|
-
|
4
|
+
attr_reader :streamer
|
5
|
+
|
6
|
+
def initialize(controller, remote_host)
|
5
7
|
@controller = controller
|
6
|
-
@
|
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
|
-
@
|
16
|
+
@streamer.start
|
15
17
|
@running = true
|
16
18
|
@nav_thread = Thread.new do
|
17
19
|
while @running
|
18
|
-
data = @
|
20
|
+
data = @streamer.receive_data
|
19
21
|
update_nav_data(data) if data
|
20
22
|
end
|
21
23
|
end
|
data/lib/argus/nav_streamer.rb
CHANGED
@@ -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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
@
|
9
|
-
@
|
10
|
-
@
|
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
|
-
@
|
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
|
-
|
51
|
+
data, from = @socket.recvfrom(1024)
|
19
52
|
if data.unpack("V").first == 0x55667788
|
20
|
-
|
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
|
data/lib/argus/udp_sender.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module Argus
|
2
2
|
class UdpSender
|
3
|
-
def initialize(
|
4
|
-
@udp_socket =
|
5
|
-
@host =
|
6
|
-
@port = port
|
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
data/lib/argus/video_streamer.rb
CHANGED
@@ -4,10 +4,10 @@ module Argus
|
|
4
4
|
class VideoStreamer
|
5
5
|
attr_reader :tcp_socket, :host, :port
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
@
|
9
|
-
@
|
10
|
-
@
|
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)
|
data/spec/argus/drone_spec.rb
CHANGED
@@ -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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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) {
|
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 ==
|
26
|
-
Then { demo.control_state_name == :
|
27
|
-
Then { demo.vbat_flying_percentage ==
|
28
|
-
Then { demo.battery_level ==
|
29
|
-
Then { demo.theta ==
|
30
|
-
Then { demo.phi ==
|
31
|
-
Then { demo.psi ==
|
32
|
-
Then { demo.
|
33
|
-
Then { demo.
|
34
|
-
Then { demo.
|
35
|
-
Then { demo.
|
36
|
-
Then { demo.
|
37
|
-
Then { demo.
|
38
|
-
Then { demo.
|
39
|
-
Then { demo.
|
40
|
-
Then { demo.
|
41
|
-
Then { demo.
|
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 ==
|
45
|
-
Then { detect.translation ==
|
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
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
22
|
-
Given
|
23
|
-
|
24
|
-
|
25
|
-
|
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.
|
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-
|
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
|