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 +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
|