hybridgroup-argus 0.2.0 → 0.3.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.
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