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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 61222b712f9c3d858153e12e2a386aa03e8e06a1
4
+ data.tar.gz: a0c4785df6cde5776eb45c997382b96f5de4e656
5
+ SHA512:
6
+ metadata.gz: 7f306362aafe950603de3dba9d6efefbaa834a23b4fa27c6e655f85d146b702b115543665dc6d7ea1c273ace9cadbc5a4aec7f68fe3280a763ddbf2c3580d29d
7
+ data.tar.gz: 028aa4c216e1ebec8a6756635b54221ba87f6bfa6c6d34fb9d0f9ebd8226e464911048d2b9c954dbbb7d84cd46f19cbc138f163b76a9fdec3c480e20ea68e8c0
@@ -2,6 +2,8 @@ require 'thread'
2
2
 
3
3
  module Argus
4
4
  class ATCommander
5
+ attr_reader :timestamps
6
+
5
7
  def initialize(sender)
6
8
  @sender = sender
7
9
  @seq = 0
@@ -11,12 +13,14 @@ module Argus
11
13
  @thread = nil
12
14
  @interval = 0.020
13
15
  @mutex = Mutex.new
16
+ @timestamps = []
14
17
  end
15
18
 
16
19
  def start
17
20
  @running = true
18
21
  @thread = Thread.new do
19
22
  while @running
23
+ log_time
20
24
  tick
21
25
  sleep @interval
22
26
  end
@@ -53,11 +57,24 @@ module Argus
53
57
  end
54
58
 
55
59
  def config(key, value)
56
- @buffer << "AT*CONFIG=605,\"#{key}\",\"#{value}\"\r"
60
+ @mutex.synchronize do
61
+ command("CONFIG", "\"#{key}\",\"#{value}\"")
62
+ end
63
+ end
64
+
65
+ def reset_watchdog
66
+ @mutex.synchronize do
67
+ command("COMWDG")
68
+ end
57
69
  end
58
70
 
59
71
  private
60
72
 
73
+ def log_time
74
+ @timestamps.shift if @timestamps.size >= 1000
75
+ @timestamps << Time.now.to_f
76
+ end
77
+
61
78
  def packet
62
79
  yield self
63
80
  flush
@@ -68,9 +85,13 @@ module Argus
68
85
  @buffer = ""
69
86
  end
70
87
 
71
- def command(name, args)
88
+ def command(name, args=nil)
72
89
  @seq += 1
73
- @buffer << "AT*#{name}=#{@seq},#{args}\r"
90
+ if args
91
+ @buffer << "AT*#{name}=#{@seq},#{args}\r"
92
+ else
93
+ @buffer << "AT*#{name}=#{@seq}\r"
94
+ end
74
95
  end
75
96
  end
76
97
  end
@@ -0,0 +1,22 @@
1
+ module Argus
2
+ module CadType
3
+
4
+ NAMES = [
5
+ :horizontal, # Deprecated
6
+ :vertical, # Deprecated
7
+ :vision, # Detection of 2D horizontal tags on drone shells
8
+ :none, # Detection disabled
9
+ :cocarde, # Detects a roundel under the drone
10
+ :oriented_cocarde, # Detects an oriented roundel under the drone
11
+ :stripe, # Detects a uniform stripe on the ground
12
+ :h_cocarde, # Detects a roundel in front of the drone
13
+ :h_oriented_cocarde, # Detects an oriented roundel in front of the drone
14
+ :stripe_v,
15
+ :multiple_detection_mode, # The drone uses several detections at the same time
16
+ :cap, # Detects a Cap orange and green in front of the drone
17
+ :oriented_cocarde_bw, # Detects the black and white roundel
18
+ :vision_v2, # Detects 2nd version of shell/tag in front of the drone
19
+ :tower_side, # Detect a tower side with the front camera
20
+ ]
21
+ end
22
+ end
@@ -0,0 +1,98 @@
1
+ require 'argus/float_encoding'
2
+
3
+ module Argus
4
+
5
+ module CFields
6
+ include FloatEncoding
7
+
8
+ def self.included(base)
9
+ base.send :extend, ClassMethods
10
+ end
11
+
12
+ def initialize(*args)
13
+ super
14
+ @data = unpack_data(args.first)
15
+ end
16
+
17
+ def unpack_data(data)
18
+ @data = data.unpack(self.class.format_string)
19
+ end
20
+
21
+ module ClassMethods
22
+ def data_index
23
+ @data_index ||= 0
24
+ end
25
+
26
+ def format_string
27
+ @format_string ||= "x4"
28
+ end
29
+
30
+ def allot(n=1)
31
+ result = data_index
32
+ @data_index += n
33
+ result
34
+ end
35
+
36
+ def define_field(name, size, format, width=1, &transform)
37
+ if size
38
+ define_array_field(name, size, format, width, transform)
39
+ else
40
+ define_scaler_field(name, format, width, transform)
41
+ end
42
+ end
43
+
44
+ def define_scaler_field(name, format, width, transform)
45
+ index = allot(width)
46
+ 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
56
+ end
57
+
58
+ def define_array_field(name, size, format, width, transform)
59
+ index = allot(width*size)
60
+ 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
70
+ end
71
+
72
+ def uint32_t(name, size=nil)
73
+ define_field(name, size, "V")
74
+ end
75
+
76
+ def uint16_t(name, size=nil)
77
+ define_field(name, size, "v")
78
+ end
79
+
80
+ def float32_t(name, size=nil)
81
+ define_field(name, size, "V") { |v| FloatEncoding.decode_float(v) }
82
+ end
83
+
84
+ def int32_t(name, size=nil)
85
+ define_field(name, size, "l<")
86
+ end
87
+
88
+ def matrix33_t(name, size=nil)
89
+ define_field(name, size, "V", 9) { |v| nil }
90
+ end
91
+
92
+ def vector31_t(name, size=nil)
93
+ define_field(name, size, "V", 3) { |v| nil }
94
+ end
95
+ end
96
+ end
97
+
98
+ end
@@ -1,5 +1,8 @@
1
+ require 'argus/float_encoding'
2
+
1
3
  module Argus
2
4
  class Controller
5
+ include FloatEncoding
3
6
 
4
7
  def initialize(at_commander)
5
8
  @at_commander = at_commander
@@ -83,14 +86,44 @@ module Argus
83
86
  update_pcmd
84
87
  end
85
88
 
89
+ def led(selection, hertz, duration)
90
+ selection = LedAnimation.lookup_value(selection)
91
+ value = [
92
+ selection,
93
+ FloatEncoding.encode_float(hertz),
94
+ duration
95
+ ].join(',')
96
+ @at_commander.config("leds:leds_anim",value)
97
+ self
98
+ end
99
+
100
+ def enable_detection(colors, type=10, select=32)
101
+ config("detect:enemy_colors",colors.to_s)
102
+ config("detect:detect_type", type.to_s)
103
+ config("detect:detections_select_h", select.to_s)
104
+ self
105
+ end
106
+
107
+ def config(key, value)
108
+ @at_commander.config(key, value)
109
+ end
110
+
111
+ def demo_mode
112
+ @at_commander.config("general:navdata_demo", "TRUE")
113
+ end
114
+
86
115
  def front_camera
87
116
  @at_commander.config("video:video_channel", "2")
88
117
  end
89
-
118
+
90
119
  def bottom_camera
91
120
  @at_commander.config("video:video_channel", "1")
92
121
  end
93
122
 
123
+ def reset_watchdog
124
+ @at_commander.reset_watchdog
125
+ end
126
+
94
127
  private
95
128
 
96
129
  REF_BASE = [18, 20, 22, 24, 28].
@@ -122,9 +155,5 @@ module Argus
122
155
  self
123
156
  end
124
157
 
125
- def encode_float(float)
126
- [float].pack('g').unpack("l>").first
127
- end
128
-
129
158
  end
130
159
  end
data/lib/argus/drone.rb CHANGED
@@ -1,22 +1,47 @@
1
1
  require 'socket'
2
+ require 'argus/nav_monitor'
2
3
 
3
4
  module Argus
5
+
4
6
  class Drone
7
+ attr_reader :controller, :enable_nav_monitor
8
+
5
9
  def initialize(socket=nil, host='192.168.1.1', port='5556')
6
10
  @socket = socket || UDPSocket.new
7
11
  @sender = Argus::UdpSender.new(@socket, host, port)
8
12
  @at = Argus::ATCommander.new(@sender)
9
13
  @controller = Argus::Controller.new(@at)
14
+
15
+ @enable_nav_monitor = false
10
16
  end
11
17
 
12
- def start
18
+ def commander
19
+ @at
20
+ end
21
+
22
+ def start(enable_nav_monitor=true)
23
+ @enable_nav_monitor = enable_nav_monitor
24
+
25
+ if enable_nav_monitor
26
+ @nav = NavMonitor.new(@controller)
27
+ @nav.start
28
+ end
29
+
13
30
  @at.start
14
31
  end
15
32
 
16
33
  def stop
17
34
  @controller.land
35
+
18
36
  @at.stop
37
+ @nav.stop if enable_nav_monitor
38
+
19
39
  @at.join
40
+ @nav.join if enable_nav_monitor
41
+ end
42
+
43
+ def nav_callback(*args, &block)
44
+ @nav.callback(*args, &block)
20
45
  end
21
46
 
22
47
  %w(
@@ -26,6 +51,8 @@ module Argus
26
51
  up down
27
52
  turn_left turn_right
28
53
  front_camera bottom_camera
54
+ config
55
+ reset_watchdog
29
56
  ).each do |meth|
30
57
  define_method(meth) { |*args|
31
58
  @controller.send(meth, *args)
@@ -0,0 +1,13 @@
1
+ module Argus
2
+ module FloatEncoding
3
+ module_function
4
+
5
+ def encode_float(float)
6
+ [float].pack('g').unpack("l>").first
7
+ end
8
+
9
+ def decode_float(encoded_float)
10
+ [encoded_float].pack("l>").unpack("g").first
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,48 @@
1
+ module Argus
2
+
3
+ module LedAnimation
4
+ NAMES = [
5
+ :blink_green_red,
6
+ :blink_green,
7
+ :blink_red,
8
+ :blink_orange,
9
+ :snake_green_red,
10
+ :fire,
11
+ :standard,
12
+ :red,
13
+ :green,
14
+ :red_snake,
15
+ :blank,
16
+ :right_missile,
17
+ :left_missile,
18
+ :double_missile,
19
+ :front_left_green_others_red,
20
+ :front_right_green_others_red,
21
+ :rear_right_green_others_red,
22
+ :rear_left_green_others_red,
23
+ :left_green_right_red,
24
+ :left_red_right_green,
25
+ :blink_standard,
26
+ ]
27
+
28
+ VALUES = {}
29
+ NAMES.each.with_index { |name, index| VALUES[name] = index }
30
+
31
+ def self.lookup_name(numeric_value)
32
+ NAMES[numeric_value]
33
+ end
34
+
35
+ def self.lookup_value(symbolic_name)
36
+ case symbolic_name
37
+ when Symbol
38
+ VALUES[symbolic_name]
39
+ when Integer
40
+ symbolic_name
41
+ when /^\d+/
42
+ symbolic_name.to_i
43
+ when String
44
+ VALUES[symbolic_name.intern]
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,61 +1,78 @@
1
1
  module Argus
2
2
  class NavData
3
- attr_accessor :drone_state, :options, :vision_flag, :sequence_number
3
+ attr_accessor :state_mask, :vision_flag, :sequence_number, :options
4
+
4
5
  def initialize(data)
5
6
  @data = data
6
7
  parse_nav_data(@data)
7
8
  end
8
9
 
9
- private
10
+ def raw
11
+ @data
12
+ end
13
+
14
+ def self.bit_mask_readers(*names)
15
+ names.each.with_index do |name, bit_number|
16
+ if name.is_a?(Array)
17
+ name, off_value, on_value = name
18
+ else
19
+ off_value = false
20
+ on_value = true
21
+ end
22
+ define_method(name) { @state_mask[bit_number] == 0 ? off_value : on_value }
23
+ end
24
+ end
25
+
26
+ bit_mask_readers(
27
+ :flying?, # FLY MASK : (0) ardrone is landed, (1) ardrone is flying
28
+ :video_enabled?, # VIDEO MASK : (0) video disable, (1) video enable
29
+ :vision_enabled?, # VISION MASK : (0) vision disable, (1) vision enable
30
+ [:control_algorithm, # CONTROL ALGO : (0) euler angles control, (1) angular speed control
31
+ :euler, :angular_speed],
32
+ :altitude_control_algorithm_active?, # ALTITUDE CONTROL ALGO : (0) altitude control inactive (1) altitude control active
33
+ :start_button_pressed?, # USER feedback : Start button state
34
+ :control_command_ack?, # Control command ACK : (0) None, (1) one received
35
+ :camera_ready?, # CAMERA MASK : (0) camera not ready, (1) Camera ready
36
+ :travelling_enabled?, # Travelling mask : (0) disable, (1) enable
37
+ :usb_ready?, # USB key : (0) usb key not ready, (1) usb key ready
38
+ [:mode, :all, :demo], # Navdata demo : (0) All navdata, (1) only navdata demo
39
+ :bootstrap?, # Navdata bootstrap : (0) options sent in all or demo mode, (1) no navdata options sent
40
+ :moter_problem?, # Motors status : (0) Ok, (1) Motors problem
41
+ :communication_lost?, # Communication Lost : (1) com problem, (0) Com is ok
42
+ :software_fault?, # Software fault detected - user should land as quick as possible (1)
43
+ :low_battery?, # VBat low : (1) too low, (0) Ok
44
+ :emergency_landing_requested?, # User Emergency Landing : (1) User EL is ON, (0) User EL is OF
45
+ :timer_elapsed?, # Timer elapsed : (1) elapsed, (0) not elapsed
46
+ :magnometer_needs_calibration?, # Magnetometer calibration state : (0) Ok, no calibration needed, (1) not ok, calibration needed
47
+ :angles_out_of_range?, # Angles : (0) Ok, (1) out of range
48
+ :too_much_wind?, # WIND MASK: (0) ok, (1) Too much wind
49
+ :ultrasonic_sensor_deaf?, # Ultrasonic sensor : (0) Ok, (1) deaf
50
+ :cutout_detected?, # Cutout system detection : (0) Not detected, (1) detected
51
+ :pic_version_number_ok?, # PIC Version number OK : (0) a bad version number, (1) version number is OK
52
+ :at_codec_thread_on?, # ATCodec thread ON : (0) thread OFF (1) thread ON
53
+ :navdata_thread_on?, # Navdata thread ON : (0) thread OFF (1) thread ON
54
+ :video_thread_on?, # Video thread ON : (0) thread OFF (1) thread ON
55
+ :acquisition_thread_on?, # Acquisition thread ON : (0) thread OFF (1) thread ON
56
+ :control_watchdog_delayed?, # CTRL watchdog : (1) delay in control execution (> 5ms), (0) control is well scheduled
57
+ :adc_watchdog_delayed?, # ADC Watchdog : (1) delay in uart2 dsr (> 5ms), (0) uart2 is good
58
+ :com_watchdog_problem?, # Communication Watchdog : (1) com problem, (0) Com is ok
59
+ :emergency_landing?) # Emergency landing : (0) no emergency, (1) emergency
60
+
61
+ private
62
+
10
63
  def parse_nav_data(data)
11
- state = data.unpack("V").first
12
- @drone_state = {
13
- :flying=>state[0], #/*!< FLY MASK : (0) ardrone is landed, (1) ardrone is flying */
14
- :videoEnabled=>state[1], #/*!< VIDEO MASK : (0) video disable, (1) video enable */
15
- :visionEnabled=>state[2], #/*!< VISION MASK : (0) vision disable, (1) vision enable */
16
- :controlAlgorithm=>state[3], #/*!< CONTROL ALGO : (0) euler angles control, (1) angular speed control */
17
- :altitudeControlAlgorithm=>state[4], #/*!< ALTITUDE CONTROL ALGO : (0) altitude control inactive (1) altitude control active */
18
- :startButtonState=>state[5], #/*!< USER feedback : Start button state */
19
- :controlCommandAck=>state[6], #/*!< Control command ACK : (0) None, (1) one received */
20
- :cameraReady=>state[7], #/*!< CAMERA MASK : (0) camera not ready, (1) Camera ready */
21
- :travellingEnabled=>state[8], #/*!< Travelling mask : (0) disable, (1) enable */
22
- :usbReady=>state[9], #/*!< USB key : (0) usb key not ready, (1) usb key ready */
23
- :navdataDemo=>state[10], #/*!< Navdata demo : (0) All navdata, (1) only navdata demo */
24
- :navdataBootstrap=>state[11], #/*!< Navdata bootstrap : (0) options sent in all or demo mode, (1) no navdata options sent */
25
- :motorProblem=>state[12], #/*!< Motors status : (0) Ok, (1) Motors problem */
26
- :communicationLost=>state[13], #/*!< Communication Lost : (1) com problem, (0) Com is ok */
27
- :softwareFault=>state[14], #/*!< Software fault detected - user should land as quick as possible (1) */
28
- :lowBattery=>state[15], #/*!< VBat low : (1) too low, (0) Ok */
29
- :userEmergencyLanding=>state[16], #/*!< User Emergency Landing : (1) User EL is ON, (0) User EL is OFF*/
30
- :timerElapsed=>state[17], #/*!< Timer elapsed : (1) elapsed, (0) not elapsed */
31
- :MagnometerNeedsCalibration=>state[18], #/*!< Magnetometer calibration state : (0) Ok, no calibration needed, (1) not ok, calibration needed */
32
- :anglesOutOfRange=>state[19], #/*!< Angles : (0) Ok, (1) out of range */
33
- :tooMuchWind=>state[20], #/*!< WIND MASK: (0) ok, (1) Too much wind */
34
- :ultrasonicSensorDeaf=>state[21], #/*!< Ultrasonic sensor : (0) Ok, (1) deaf */
35
- :cutoutDetected=>state[22], #/*!< Cutout system detection : (0) Not detected, (1) detected */
36
- :picVersionNumberOk=>state[23], #/*!< PIC Version number OK : (0) a bad version number, (1) version number is OK */
37
- :atCodecThreadOn=>state[24], #/*!< ATCodec thread ON : (0) thread OFF (1) thread ON */
38
- :navdataThreadOn=>state[25], #/*!< Navdata thread ON : (0) thread OFF (1) thread ON */
39
- :videoThreadOn=>state[26], #/*!< Video thread ON : (0) thread OFF (1) thread ON */
40
- :acquisitionThreadOn=>state[27], #/*!< Acquisition thread ON : (0) thread OFF (1) thread ON */
41
- :controlWatchdogDelay=>state[28], #/*!< CTRL watchdog : (1) delay in control execution (> 5ms), (0) control is well scheduled */
42
- :adcWatchdogDelay=>state[29], #/*!< ADC Watchdog : (1) delay in uart2 dsr (> 5ms), (0) uart2 is good */
43
- :comWatchdogProblem=>state[30], #/*!< Communication Watchdog : (1) com problem, (0) Com is ok */
44
- :emergencyLanding=>state[31] #/*!< Emergency landing : (0) no emergency, (1) emergency */
45
- }
46
- data.slice!(0..3)
47
- @sequence_number = data.unpack("V").first
48
- data.slice!(0..3)
49
- @vision_flag = data.unpack("V").first
64
+ tag, @state_mask, @sequence_number, @vision_flag = data.unpack("VVVV")
65
+ parse_nav_options(data[16..-1])
66
+ end
67
+
68
+ def parse_nav_options(data)
50
69
  @options = []
51
- option1 = {}
52
- data.slice!(0..3)
53
- option1[:id] = data.unpack("v").first
54
- data.slice!(0..1)
55
- option1[:size] = data.unpack("v").first
56
- data.slice!(0..1)
57
- option1[:data] = data.unpack("V").first
58
- @options.push(option1)
70
+ loop do
71
+ opt = NavOption.parse(data)
72
+ data = data[opt.size .. -1]
73
+ @options << opt
74
+ break if data.nil? || data.empty?
75
+ end
59
76
  end
60
77
  end
61
78
  end
@@ -0,0 +1,78 @@
1
+ module Argus
2
+
3
+ class NavMonitor
4
+ def initialize(controller)
5
+ @controller = controller
6
+ @nav = NavStreamer.new
7
+ @callbacks = []
8
+ @mutex = Mutex.new
9
+ @nav_data = nil
10
+ @nav_options = {}
11
+ end
12
+
13
+ def start
14
+ @nav.start
15
+ @running = true
16
+ @nav_thread = Thread.new do
17
+ while @running
18
+ data = @nav.receive_data
19
+ update_nav_data(data) if data
20
+ end
21
+ end
22
+ end
23
+
24
+ def stop
25
+ @running = false
26
+ end
27
+
28
+ def join
29
+ @nav_thread.join
30
+ end
31
+
32
+ def callback(callback=nil, &block)
33
+ @mutex.synchronize do
34
+ @callbacks << callback unless callback.nil?
35
+ @callbacks << block if block_given?
36
+ end
37
+ end
38
+
39
+ def data
40
+ @mutex.synchronize { @nav_data }
41
+ end
42
+
43
+ def option(tag)
44
+ @mutex.synchronize { @nav_options[tag] }
45
+ end
46
+
47
+ private
48
+
49
+ def update_nav_data(data)
50
+ @mutex.synchronize do
51
+ update_internal_nav_data(data)
52
+ do_callbacks(data)
53
+ end
54
+ rescue Exception => ex
55
+ puts "ERROR in callback: #{ex}"
56
+ puts ex.message
57
+ puts ex.backtrace
58
+ $stdout.flush
59
+ end
60
+
61
+ def update_internal_nav_data(data)
62
+ @nav_data = data
63
+ if @nav_data.bootstrap?
64
+ @controller.demo_mode
65
+ end
66
+ data.options.each do |opt|
67
+ @nav_options[opt.tag] = opt if opt.tag < 100
68
+ end
69
+ end
70
+
71
+ def do_callbacks(data)
72
+ @callbacks.each do |callback|
73
+ callback.call(data)
74
+ end
75
+ end
76
+ end
77
+
78
+ end
@@ -0,0 +1,29 @@
1
+ module Argus
2
+
3
+ class NavOption
4
+ attr_reader :tag
5
+
6
+ def initialize(data)
7
+ @tag, @size = data.unpack("vv")
8
+ end
9
+
10
+ def size
11
+ @size < 4 ? 4 : @size
12
+ end
13
+
14
+ def self.options
15
+ @options ||= { }
16
+ end
17
+
18
+ def self.register(option)
19
+ options[option.tag] = option
20
+ end
21
+
22
+ def self.parse(raw_data)
23
+ tag = raw_data.unpack("v").first
24
+ option = options[tag] || NavOptionUnknown
25
+ option.new(raw_data)
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,20 @@
1
+ require 'argus/cfields'
2
+ require 'argus/nav_option'
3
+ require 'argus/nav_tag'
4
+
5
+ module Argus
6
+
7
+ class NavOptionChecksum < NavOption
8
+ include CFields
9
+
10
+ uint32_t :chks
11
+ alias :checksum :chks
12
+
13
+ def self.tag
14
+ NavTag::CHECKSUM
15
+ end
16
+
17
+ NavOption.register(self)
18
+ end
19
+
20
+ end