hybridgroup-argus 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/lib/argus/at_commander.rb +24 -3
  3. data/lib/argus/cad_type.rb +22 -0
  4. data/lib/argus/cfields.rb +98 -0
  5. data/lib/argus/controller.rb +34 -5
  6. data/lib/argus/drone.rb +28 -1
  7. data/lib/argus/float_encoding.rb +13 -0
  8. data/lib/argus/led_animation.rb +48 -0
  9. data/lib/argus/nav_data.rb +66 -49
  10. data/lib/argus/nav_monitor.rb +78 -0
  11. data/lib/argus/nav_option.rb +29 -0
  12. data/lib/argus/nav_option_checksum.rb +20 -0
  13. data/lib/argus/nav_option_demo.rb +79 -0
  14. data/lib/argus/nav_option_unknown.rb +9 -0
  15. data/lib/argus/nav_option_vision_detect.rb +83 -0
  16. data/lib/argus/nav_streamer.rb +12 -4
  17. data/lib/argus/nav_tag.rb +35 -0
  18. data/lib/argus/version.rb +1 -1
  19. data/lib/argus/video_data.rb +15 -0
  20. data/lib/argus/video_data_envelope.rb +55 -0
  21. data/lib/argus/video_streamer.rb +23 -0
  22. data/lib/argus.rb +5 -9
  23. data/spec/argus/controller_spec.rb +49 -0
  24. data/spec/argus/drone_spec.rb +24 -0
  25. data/spec/argus/float_encoding_spec.rb +12 -0
  26. data/spec/argus/led_animation_spec.rb +21 -0
  27. data/spec/argus/nav_data_spec.rb +147 -0
  28. data/spec/argus/nav_option_checksum_spec.rb +21 -0
  29. data/spec/argus/nav_option_demo_spec.rb +44 -0
  30. data/spec/argus/nav_option_spec.rb +32 -0
  31. data/spec/argus/nav_option_unknown_spec.rb +19 -0
  32. data/spec/argus/nav_option_vision_detect_spec.rb +65 -0
  33. data/spec/argus/nav_streamer_spec.rb +28 -0
  34. data/spec/argus/udp_sender_spec.rb +1 -1
  35. data/spec/argus/video_data_envelope_spec.rb +26 -0
  36. data/spec/argus/video_data_spec.rb +18 -0
  37. data/spec/argus/video_streamer_spec.rb +16 -0
  38. data/spec/spec_helper.rb +3 -0
  39. data/spec/support/bytes.rb +48 -0
  40. metadata +36 -15
  41. data/lib/argus/pave_parser.rb +0 -39
  42. data/lib/argus/tcp_video_streamer.rb +0 -20
  43. data/lib/argus/udp_nav_streamer.rb +0 -24
@@ -0,0 +1,79 @@
1
+ require 'argus/cfields'
2
+ require 'argus/float_encoding'
3
+ require 'argus/nav_option'
4
+ require 'argus/nav_tag'
5
+
6
+ module Argus
7
+
8
+ class NavOptionDemo < NavOption
9
+ include CFields
10
+
11
+ uint32_t :ctrl_state # Flying state (landed, flying,
12
+ alias :control_state :ctrl_state
13
+ # hovering, etc.) defined in
14
+ # CTRL_STATES enum.
15
+ uint32_t :vbat_flying_percentage # battery voltage filtered (mV)
16
+ alias :battery_level :vbat_flying_percentage
17
+
18
+ float32_t :theta # UAV's pitch in milli-degrees
19
+ float32_t :phi # UAV's roll in milli-degrees
20
+ float32_t :psi # UAV's yaw in milli-degrees
21
+
22
+ int32_t :altitude # UAV's altitude in centimeters
23
+
24
+ float32_t :vx # UAV's estimated linear velocity
25
+ float32_t :vy # UAV's estimated linear velocity
26
+ float32_t :vz # UAV's estimated linear velocity
27
+
28
+ uint32_t :num_frames # streamed frame index // Not
29
+ # used -> To integrate in video
30
+ # stage.
31
+
32
+ # Camera parameters compute by detection
33
+ matrix33_t :detection_camera_rot # Deprecated ! Don't use !
34
+ vector31_t :detection_camera_trans # Deprecated ! Don't use !
35
+ uint32_t :detection_tag_index # Deprecated ! Don't use !
36
+
37
+ uint32_t :detection_camera_type # Type of tag searched in detection
38
+
39
+ # Camera parameters compute by drone
40
+ matrix33_t :drone_camera_rot # Deprecated ! Don't use !
41
+ vector31_t :drone_camera_trans # Deprecated ! Don't use !
42
+
43
+ CONTROL_STATE_NAMES = [
44
+ :default,
45
+ :init,
46
+ :landed,
47
+ :flying,
48
+ :hovering,
49
+ :test,
50
+ :trans_takeoff,
51
+ :trans_gotofix,
52
+ :trans_landing,
53
+ :trans_looping,
54
+ ]
55
+
56
+ def control_state_name
57
+ CONTROL_STATE_NAMES[ctrl_state]
58
+ end
59
+
60
+ def pitch
61
+ theta / 1000.0
62
+ end
63
+
64
+ def roll
65
+ phi / 1000.0
66
+ end
67
+
68
+ def yaw
69
+ psi / 1000.0
70
+ end
71
+
72
+ def self.tag
73
+ NavTag::DEMO
74
+ end
75
+
76
+ NavOption.register(self)
77
+ end
78
+
79
+ end
@@ -0,0 +1,9 @@
1
+ module Argus
2
+
3
+ class NavOptionUnknown < NavOption
4
+ def self.tag
5
+ NavTag::UNKNOWN
6
+ end
7
+ end
8
+
9
+ end
@@ -0,0 +1,83 @@
1
+ require 'argus/cfields'
2
+ require 'argus/nav_tag'
3
+
4
+ module Argus
5
+
6
+ class NavOptionVisionDetect < NavOption
7
+ include CFields
8
+
9
+ NB_NAVDATA_DETECTION_RESULTS = 4
10
+
11
+ uint32_t :nb_detected
12
+ alias :detected_count :nb_detected
13
+ uint32_t :type, NB_NAVDATA_DETECTION_RESULTS
14
+ uint32_t :xc, NB_NAVDATA_DETECTION_RESULTS
15
+ uint32_t :yc, NB_NAVDATA_DETECTION_RESULTS
16
+ uint32_t :width, NB_NAVDATA_DETECTION_RESULTS
17
+ uint32_t :height, NB_NAVDATA_DETECTION_RESULTS
18
+ uint32_t :dist, NB_NAVDATA_DETECTION_RESULTS
19
+ alias :distance :dist
20
+ float32_t :orientation_angle, NB_NAVDATA_DETECTION_RESULTS
21
+ matrix33_t :rotation, NB_NAVDATA_DETECTION_RESULTS
22
+ vector31_t :translation, NB_NAVDATA_DETECTION_RESULTS
23
+ uint32_t :camera_source, NB_NAVDATA_DETECTION_RESULTS
24
+
25
+ class Detection
26
+ def initialize(vision_detected, index)
27
+ @vision_detected = vision_detected
28
+ @index = index
29
+ end
30
+
31
+ def type
32
+ @vision_detected.type[@index]
33
+ end
34
+
35
+ def type_name
36
+ CadType::NAMES[type]
37
+ end
38
+
39
+ def x
40
+ @vision_detected.xc[@index]
41
+ end
42
+
43
+ def y
44
+ @vision_detected.yc[@index]
45
+ end
46
+
47
+ def width
48
+ @vision_detected.width[@index]
49
+ end
50
+
51
+ def height
52
+ @vision_detected.height[@index]
53
+ end
54
+
55
+ def distance
56
+ @vision_detected.distance[@index]
57
+ end
58
+
59
+ def orientation_angle
60
+ @vision_detected.orientation_angle[@index]
61
+ end
62
+
63
+ def camera_source
64
+ @vision_detected.camera_source[@index]
65
+ end
66
+ end
67
+
68
+ def type_name
69
+ type.map { |t| CadType::NAMES[t] }
70
+ end
71
+
72
+ def detections
73
+ @detections ||= (0...detected_count).map { |i| Detection.new(self, i) }
74
+ end
75
+
76
+ def self.tag
77
+ NavTag::VISION_DETECT
78
+ end
79
+
80
+ NavOption.register(self)
81
+ end
82
+
83
+ end
@@ -1,18 +1,26 @@
1
1
  require 'socket'
2
2
 
3
3
  module Argus
4
- class NavStreamer
4
+ class NavStreamer
5
5
  def initialize(socket=nil, host='192.168.1.1', port='5554')
6
+ # TODO: Why is the port a string?
6
7
  @socket = socket || UDPSocket.new
7
- @streamer = Argus::UdpNavStreamer.new(@socket, host, port)
8
+ @host = host
9
+ @port = port
10
+ @socket.bind("0.0.0.0", port)
8
11
  end
9
12
 
10
13
  def start
11
- @streamer.start_stream
14
+ @socket.send("\x01\x00\x00\x00", 0, @host, @port)
12
15
  end
13
16
 
14
17
  def receive_data
15
- @streamer.receive_packet
18
+ data, from = @socket.recvfrom(1024)
19
+ if data.unpack("V").first == 0x55667788
20
+ NavData.new(data)
21
+ else
22
+ nil
23
+ end
16
24
  end
17
25
  end
18
26
  end
@@ -0,0 +1,35 @@
1
+ module Argus
2
+ module NavTag
3
+ DEMO,
4
+ TIME,
5
+ RAW_MEASURES,
6
+ PHYS_MEASURES,
7
+ GYROS_OFFSETS,
8
+ EULER_ANGLES,
9
+ REFERENCES,
10
+ TRIMS,
11
+ RC_REFERENCES,
12
+ PWM,
13
+ ALTITUDE,
14
+ VISION_RAW,
15
+ VISION_OF,
16
+ VISION,
17
+ VISION_PERF,
18
+ TRACKERS_SEND,
19
+ VISION_DETECT,
20
+ WATCHDOG,
21
+ ADC_DATA_FRAME,
22
+ VIDEO_STREAM,
23
+ GAMES,
24
+ PRESSURE_RAW,
25
+ MAGNETO,
26
+ WIND,
27
+ KALMAN_PRESSURE,
28
+ HDVIDEO_STREAM,
29
+ WIFI = (0..100).to_a
30
+
31
+ CHECKSUM = 0xffff
32
+ UNKNOWN = 0xfffe # Not part of the AR Drone DSK, Only used in Argus
33
+ end
34
+
35
+ end
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 = 2,
5
+ MINOR = 3,
6
6
  BUILD = 0,
7
7
  ]
8
8
  end
@@ -0,0 +1,15 @@
1
+ module Argus
2
+ class VideoData
3
+ attr_reader :socket, :envelope, :frame
4
+
5
+ def initialize(socket)
6
+ @socket = socket
7
+ @envelope = VideoDataEnvelope.new(@socket)
8
+ @frame = parse_frame
9
+ end
10
+
11
+ def parse_frame
12
+ socket.read(envelope.payload_size) if envelope
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,55 @@
1
+ module Argus
2
+ class VideoDataEnvelope
3
+ attr_reader :socket
4
+
5
+ def initialize(socket)
6
+ @socket = socket
7
+ parse
8
+ end
9
+
10
+ def parse
11
+ data(:signature, 4, "A*")
12
+ data(:version, 1, "C")
13
+ data(:video_codec, 1, "C")
14
+ data(:header_size, 2, "v")
15
+ data(:payload_size, 4, "V")
16
+ data(:encoded_stream_width, 2, "v")
17
+ data(:encoded_stream_height, 2, "v")
18
+ data(:display_width, 2, "v")
19
+ data(:display_height, 2, "v")
20
+ data(:frame_number, 4, "V")
21
+ data(:timestamp, 4, "V")
22
+ data(:total_chunks, 1, "C")
23
+ data(:chunk_index, 1, "C")
24
+ data(:frame_type, 1, "C")
25
+ data(:control, 1, "C")
26
+ data(:stream_byte_position_lw, 4, "V")
27
+ data(:stream_byte_position_uw, 4, "V")
28
+ data(:stream_id, 2, "v")
29
+ data(:total_slices, 1, "C")
30
+ data(:slice_index, 1, "C")
31
+ data(:header1_size, 1, "C")
32
+ data(:header2_size, 1, "C")
33
+ data(:reserved_2, 2, "H*")
34
+ data(:advertised_size, 4, "V")
35
+ data(:reserved_12, 12, "H*")
36
+ socket.read(4) # TODO: look at why just throwing this data away
37
+ end
38
+
39
+ def data(name, size, format)
40
+ define_data(name, get_data(size, format))
41
+ end
42
+
43
+ def get_data(size, format)
44
+ socket.read(size).unpack(format).first
45
+ end
46
+
47
+ def define_data(name, value)
48
+ ivar = "@#{name}".to_sym
49
+ instance_variable_set(ivar, value)
50
+ self.class.send(:define_method, name) do
51
+ instance_variable_get(ivar)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,23 @@
1
+ require 'socket'
2
+
3
+ module Argus
4
+ class VideoStreamer
5
+ attr_reader :tcp_socket, :host, :port
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
11
+ end
12
+
13
+ def start(udp_socket=nil)
14
+ @udp_socket = udp_socket || UDPSocket.new
15
+ @udp_socket.send("\x01\x00\x00\x00", 0, host, port)
16
+ @udp_socket.close
17
+ end
18
+
19
+ def receive_data
20
+ VideoData.new(tcp_socket)
21
+ end
22
+ end
23
+ end
data/lib/argus.rb CHANGED
@@ -1,9 +1,5 @@
1
- require 'argus/at_commander'
2
- require 'argus/controller'
3
- require 'argus/udp_sender'
4
- require 'argus/udp_nav_streamer'
5
- require 'argus/nav_data'
6
- require 'argus/nav_streamer'
7
- require 'argus/drone'
8
- require 'argus/tcp_video_streamer'
9
- require 'argus/pave_parser'
1
+ # Require all the top level files in argus/*.rb
2
+
3
+ Dir[File.dirname(__FILE__) + "/argus/*.rb"].sort.each do |pn|
4
+ require "argus/#{File.basename(pn, '.rb')}"
5
+ end
@@ -92,4 +92,53 @@ describe Argus::Controller do
92
92
  Then { at.should have_received(:pcmd).with("1,-1090519040,-1082130432,1045220557,-1085485875") }
93
93
  end
94
94
  end
95
+
96
+ describe "led command" do
97
+ Invariant { result.should == controller }
98
+
99
+ context "when setting with numeric sequence" do
100
+ When(:result) { controller.led(3, 2.0, 4) }
101
+ Then {
102
+ at.should have_received(:config)
103
+ .with("leds:leds_anim", "3,1073741824,4")
104
+ }
105
+ end
106
+
107
+ context "when setting with symbolic sequence" do
108
+ When(:result) { controller.led(:blink_orange, 2.0, 4) }
109
+ Then {
110
+ at.should have_received(:config)
111
+ .with("leds:leds_anim", "3,1073741824,4")
112
+ }
113
+ end
114
+ end
115
+
116
+ describe "enabled detection command" do
117
+ Invariant { result.should == controller }
118
+
119
+ context "when setting all parameters" do
120
+ Given(:enemy) { 2 }
121
+ Given(:type) { 11 }
122
+ Given(:select) { 33 }
123
+
124
+ When(:result) { controller.enable_detection(enemy, type, select) }
125
+
126
+ Then { at.should have_received(:config).with("detect:enemy_colors", enemy.to_s) }
127
+ Then { at.should have_received(:config).with("detect:detect_type", type.to_s) }
128
+ Then { at.should have_received(:config).with("detect:detections_select_h", select.to_s) }
129
+ end
130
+
131
+ context "when setting with only enemy" do
132
+ Given(:enemy) { 2 }
133
+ Given(:type) { 10 }
134
+ Given(:select) { 32 }
135
+
136
+ When(:result) { controller.enable_detection(enemy) }
137
+
138
+ Then { at.should have_received(:config).with("detect:enemy_colors", enemy.to_s) }
139
+ Then { at.should have_received(:config).with("detect:detect_type", type.to_s) }
140
+ Then { at.should have_received(:config).with("detect:detections_select_h", select.to_s) }
141
+ end
142
+ end
143
+
95
144
  end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ module Argus
4
+ describe Drone do
5
+
6
+ Given(:socket) { flexmock("Socket", send: nil).should_ignore_missing }
7
+ Given(:drone) { Drone.new(socket) }
8
+
9
+ describe "default navigation monitor enabled" do
10
+ Then { drone.enable_nav_monitor == false }
11
+ end
12
+
13
+ describe "default navigation monitor enabled when started" do
14
+ When { drone.start }
15
+ Then { drone.enable_nav_monitor == true }
16
+ end
17
+
18
+ describe "navigation monitor can be disabled when started" do
19
+ When { drone.start(false) }
20
+ Then { drone.enable_nav_monitor == false }
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ module Argus
4
+
5
+ describe FloatEncoding do
6
+ Given(:f) { 5.0 }
7
+ Given(:encoded_f) { 1084227584 }
8
+ Then { FloatEncoding.encode_float(f) == encoded_f }
9
+ Then { FloatEncoding.decode_float(encoded_f) == f }
10
+ end
11
+
12
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ module Argus
4
+
5
+ describe LedAnimation do
6
+ describe ".lookup_name" do
7
+ Then { LedAnimation.lookup_name(3) == :blink_orange }
8
+ end
9
+
10
+ describe ".lookup_value" do
11
+ Then { LedAnimation.lookup_value(:blink_orange) == 3 }
12
+ Then { LedAnimation.lookup_value("blink_orange") == 3 }
13
+ Then { LedAnimation.lookup_value(3) == 3 }
14
+ Then { LedAnimation.lookup_value("3") == 3 }
15
+
16
+ Then { LedAnimation.lookup_value(:unknown) == nil }
17
+ Then { LedAnimation.lookup_value("UNKNOWN") == nil }
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,147 @@
1
+ require 'spec_helper'
2
+
3
+ module Argus
4
+ describe NavData do
5
+ Given(:state_bits) { 0xcf8a0c94 }
6
+ Given(:seq_num) { 173064 }
7
+ Given(:vision_flag) { 0 }
8
+ Given(:raw_header) { Bytes.make_header(state_bits, seq_num, vision_flag) }
9
+ Given(:raw_nav_bytes) { Bytes.make_nav_data(raw_header) }
10
+
11
+ When(:nav_data) { NavData.new(raw_nav_bytes) }
12
+
13
+ Then { nav_data.sequence_number == 173064 }
14
+ Then { nav_data.vision_flag == 0 }
15
+
16
+ describe "sequence number" do
17
+ Given(:seq_num) { 1234 }
18
+ Then { nav_data.sequence_number == 1234 }
19
+ end
20
+
21
+ describe "vision flag" do
22
+ Given(:vision_flag) { 1 }
23
+ Then { nav_data.vision_flag == 1 }
24
+ end
25
+
26
+ describe "state queries" do
27
+
28
+ def bit(n)
29
+ 0x00000001 << n
30
+ end
31
+
32
+ # Matcher for handling the mask testing for the state mask.
33
+ #
34
+ # Usage:
35
+ # bit(5).should be_the_mask_for(:method [, off_value, on_value])
36
+ #
37
+ # If off_value and on_value are not given, then false/true will
38
+ # be assumed.
39
+ #
40
+ matcher :be_the_mask_for do |method, off_result=false, on_result=true|
41
+ match do |mask|
42
+ @msg = "OK"
43
+ try_alternative(method, 0, off_result) &&
44
+ try_alternative(method, mask, on_result)
45
+ end
46
+
47
+ failure_message_for_should do |mask|
48
+ @msg
49
+ end
50
+
51
+ # Try one of the alternatives. Sending method to the navdata
52
+ # constructed with mask should return teh expected value.
53
+ def try_alternative(method, mask, expected)
54
+ raw = Bytes.make_nav_data(Bytes.make_header(mask, 1, 0))
55
+ nav_data = NavData.new(raw)
56
+ result = nav_data.send(method)
57
+ return true if result == expected
58
+ @msg = "expected mask of 0x#{'%08x' % mask} with #{method}\n" +
59
+ "to return: #{expected.inspect}\n" +
60
+ "got: #{result.inspect}"
61
+ false
62
+ end
63
+ end
64
+
65
+ Then { bit(0).should be_the_mask_for(:flying?) }
66
+ Then { bit(1).should be_the_mask_for(:video_enabled?) }
67
+ Then { bit(2).should be_the_mask_for(:vision_enabled?) }
68
+ Then { bit(3).should be_the_mask_for(:control_algorithm, :euler, :angular_speed) }
69
+
70
+ Then { bit(4).should be_the_mask_for(:altitude_control_algorithm_active?) }
71
+ Then { bit(5).should be_the_mask_for(:start_button_pressed?) }
72
+ Then { bit(6).should be_the_mask_for(:control_command_ack?) }
73
+ Then { bit(7).should be_the_mask_for(:camera_ready?) }
74
+
75
+ Then { bit(8).should be_the_mask_for(:travelling_enabled?) }
76
+ Then { bit(9).should be_the_mask_for(:usb_ready?) }
77
+ Then { bit(10).should be_the_mask_for(:mode, :all, :demo) }
78
+ Then { bit(11).should be_the_mask_for(:bootstrap?) }
79
+
80
+ Then { bit(12).should be_the_mask_for(:moter_problem?) }
81
+ Then { bit(13).should be_the_mask_for(:communication_lost?) }
82
+ Then { bit(14).should be_the_mask_for(:software_fault?) }
83
+ Then { bit(15).should be_the_mask_for(:low_battery?) }
84
+
85
+ Then { bit(16).should be_the_mask_for(:emergency_landing_requested?) }
86
+ Then { bit(17).should be_the_mask_for(:timer_elapsed?) }
87
+ Then { bit(18).should be_the_mask_for(:magnometer_needs_calibration?) }
88
+ Then { bit(19).should be_the_mask_for(:angles_out_of_range?) }
89
+
90
+ Then { bit(20).should be_the_mask_for(:too_much_wind?) }
91
+ Then { bit(21).should be_the_mask_for(:ultrasonic_sensor_deaf?) }
92
+ Then { bit(22).should be_the_mask_for(:cutout_detected?) }
93
+ Then { bit(23).should be_the_mask_for(:pic_version_number_ok?) }
94
+
95
+ Then { bit(24).should be_the_mask_for(:at_codec_thread_on?) }
96
+ Then { bit(25).should be_the_mask_for(:navdata_thread_on?) }
97
+ Then { bit(26).should be_the_mask_for(:video_thread_on?) }
98
+ Then { bit(27).should be_the_mask_for(:acquisition_thread_on?) }
99
+
100
+ Then { bit(28).should be_the_mask_for(:control_watchdog_delayed?) }
101
+ Then { bit(29).should be_the_mask_for(:adc_watchdog_delayed?) }
102
+ Then { bit(30).should be_the_mask_for(:com_watchdog_problem?) }
103
+ Then { bit(31).should be_the_mask_for(:emergency_landing?) }
104
+ end
105
+
106
+ describe "state mask" do
107
+ context "all zeros" do
108
+ Given(:state_bits) { 0 }
109
+ Then { nav_data.state_mask == state_bits }
110
+ end
111
+
112
+ context "non-zero" do
113
+ Given(:state_bits) { 12345 }
114
+ Then { nav_data.state_mask == state_bits }
115
+ end
116
+ end
117
+
118
+ describe "#options" do
119
+ Then { nav_data.options.size == 1 }
120
+ Then { nav_data.options.first.is_a?(NavOptionChecksum) }
121
+ end
122
+ end
123
+
124
+ describe "multiple options" do
125
+ context "with good data" do
126
+ Given(:raw_header) { Bytes.make_header(0, 0, 0) }
127
+ Given(:raw_nav_bytes) {
128
+ Bytes.make_nav_data(raw_header, Bytes.make_demo_data)
129
+ }
130
+ When(:nav_data) { NavData.new(raw_nav_bytes) }
131
+ Then { nav_data.options.size == 2 }
132
+ Then { nav_data.options[0].is_a?(NavOptionDemo) }
133
+ Then { nav_data.options[1].is_a?(NavOptionChecksum) }
134
+ end
135
+
136
+ context "with short data" do
137
+ Given(:raw_nav_bytes) {
138
+ Bytes.make_header(0, 0, 0).pack("C*") +
139
+ [4321, 100, 0].pack("vvV")
140
+ }
141
+ When(:nav_data) { NavData.new(raw_nav_bytes) }
142
+ Then { nav_data.options.size == 1 }
143
+ Then { nav_data.options[0].is_a?(NavOptionUnknown) }
144
+ end
145
+ end
146
+
147
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ module Argus
4
+
5
+ describe NavOptionChecksum do
6
+ Given(:raw_data) { [NavTag::CHECKSUM, 8, 0x12345678].pack("vvV") }
7
+ Given(:csum) { NavOptionChecksum.new(raw_data) }
8
+
9
+ describe ".tag" do
10
+ Then { NavOptionChecksum.tag == NavTag::CHECKSUM }
11
+ end
12
+
13
+ describe "data fields" do
14
+ Then { csum.tag == NavOptionChecksum.tag }
15
+ Then { csum.size == raw_data.size }
16
+ Then { csum.chks == 0x12345678 }
17
+ Then { csum.checksum == 0x12345678 }
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ module Argus
4
+ describe NavOptionDemo do
5
+ def f(float)
6
+ FloatEncoding.encode_float(float)
7
+ end
8
+
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") }
20
+
21
+ When(:demo) { NavOptionDemo.new(raw_data) }
22
+
23
+ Then { ! demo.nil? }
24
+
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? }
42
+ end
43
+
44
+ end