ogn_client-ruby 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0e4b42ab724fb2c9046c419ab356990d476e4dcc
4
- data.tar.gz: 9c1617d22daa0fb63e936eb491acf2e6ff78a39e
3
+ metadata.gz: 02438399c35649b6367b7c29b764915182edc72b
4
+ data.tar.gz: c1d8d0cccae554f55cb74b9944dbcfe91a6a1ea0
5
5
  SHA512:
6
- metadata.gz: 68a2ca8b91f5ec145eb70ffa7cfc511b62ed324f97431a50232193e13b26bc90fb51b036030944b543935245a3900974c3d4b3fbeffac6a74d5bd9ffe34b12f3
7
- data.tar.gz: 6a522636b0cdf6eb93dbde9bb588607474a57a988a64f7f9480a8b3be2457e52f04ccc4afda6d2cecf17940145ada2ec8f3af2bc49183ad6fb3afa991113b4aa
6
+ metadata.gz: 102a7568799ecdbacb814fc7f5ab956a780ef237748f47e4bf4fcca6eedcf1bc11ea299b204a8a4d69da93e66d3f3e9ef4af0f6d55cb1937ca515e38ddc5e458
7
+ data.tar.gz: d9b989f3a32cc8b8c3316afa9a4d48391dee7de676326214a759eb76927f40c856e2008e792449a5df790c19cc605f6909a939631f450af22e404b7f0d3fb7fb
@@ -0,0 +1,14 @@
1
+ ---
2
+ languages:
3
+ Ruby: true
4
+ engines:
5
+ fixme:
6
+ enabled: true
7
+ rubocop:
8
+ enabled: true
9
+ ratings:
10
+ paths:
11
+ - "lib/**"
12
+ - "**.rb"
13
+ exclude_paths:
14
+ - "spec/**/*"
@@ -1,3 +1,4 @@
1
+ ---
1
2
  language: ruby
2
3
  rvm:
3
4
  - 2.2.3
@@ -1,5 +1,51 @@
1
+ ## 0.1.1
2
+
3
+ * remove debug support and raise errors instead
4
+ * convert raw messages to UTF-8 before parsing
5
+ * new sender and receiver attributes
6
+ * `Sender#flight_level
7
+ * `Sender#flarm_software_version`
8
+ * `Sender#flarm_hardware_version`
9
+ * `Sender#flarm_id`
10
+ * `Receiver#manual_correction`
11
+ * `Receiver#automatic_correction`
12
+ * renamed message attribute
13
+ * `Message#speed` -> `Message#ground_speed`
14
+ * verification of supported receiver version
15
+ * supported receiver versions <= 0.2.5
16
+
1
17
  ## 0.1.0
2
18
 
3
- ### initial release
4
19
  * OGN subscription
5
- * parser for senders (aircraft), receivers and comments
20
+ * parser for senders, receivers and comments with attributes
21
+ * `Message#raw`
22
+ * `Message#callsign`
23
+ * `Message#receiver`
24
+ * `Message#time`
25
+ * `Message#longitude`
26
+ * `Message#latitude`
27
+ * `Message#altitude`
28
+ * `Message#heading`
29
+ * `Message#speed`
30
+ * `Sender#stealth_mode`
31
+ * `Sender#no_tracking`
32
+ * `Sender#sender_type`
33
+ * `Sender#address_type`
34
+ * `Sender#id`
35
+ * `Sender#climb_rate`
36
+ * `Sender#turn_rate`
37
+ * `Sender#signal`
38
+ * `Sender#errors`
39
+ * `Sender#frequency_offset`
40
+ * `Sender#gps_accuracy`
41
+ * `Sender#proximity`
42
+ * `Receiver#version`
43
+ * `Receiver#platform`
44
+ * `Receiver#cpu_load`
45
+ * `Receiver#cpu_temperature`
46
+ * `Receiver#ram_free`
47
+ * `Receiver#ram_total`
48
+ * `Receiver#ntp_offset`
49
+ * `Receiver#ntp_correction`
50
+ * `Receiver#signal`
51
+ * `Comment#comment`
data/README.md CHANGED
@@ -1,3 +1,8 @@
1
+ [![Version](https://img.shields.io/gem/v/ogn_client-ruby.svg?style=flat)](https://rubygems.org/gems/ogn_client-ruby)
2
+ [![Continuous Integration](https://img.shields.io/travis/svoop/ogn_client-ruby/master.svg?style=flat)](https://travis-ci.org/svoop/ogn_client-ruby)
3
+ [![Code Climate](https://img.shields.io/codeclimate/github/svoop/ogn_client-ruby.svg?style=flat)](https://codeclimate.com/github/svoop/ogn_client-ruby)
4
+ [![Gitter](https://img.shields.io/gitter/room/svoop/ogn_client-ruby.svg?style=flat)](https://gitter.im/svoop/ogn_client-ruby)
5
+
1
6
  # ogn_client-ruby
2
7
 
3
8
  [OGN](http://glidernet.org) broadcasts aircraft positions as [APRS](http://www.aprs.org)/[APRS-IS](http://www.aprs-is.net) messages. This gem hooks into this stream of data and provides the necessary classes to parse the raw message strings into meaningful objects.
@@ -31,37 +36,39 @@ Choose a [valid callsign](http://www.aprs-is.net/Connecting.aspx#loginrules) and
31
36
 
32
37
  ```ruby
33
38
  OGNClient::APRS.start(callsign: 'ROCT', filter: 'r/33/-97/200') do |aprs|
34
- puts aprs.gets until aprs.eof?
39
+ loop { puts aprs.gets }
35
40
  end
36
41
  ```
37
42
 
38
43
  ### Parse Raw Message Strings
39
44
 
45
+ :point_up: Refer to the wiki for an introduction to [OGN flavoured APRS](https://github.com/svoop/ogn_client-ruby/wiki) messages.
46
+
40
47
  In the above example, each `aprs.gets` returns a raw message string. To decode this string, just pass it to the message parser:
41
48
 
42
49
  ```ruby
43
50
  OGNClient::Message.parse(aprs.gets)
44
51
  ```
45
52
 
46
- This factory method will return an instance of one of the following four classes.
53
+ :point_up: Raw APRS messages as returned by `aprs.gets` are "ASCII-8BIT" encoded and may contain tailing whitespace. The parser removes this whitespace and converts the string to "UTF-8".
47
54
 
48
- :point_up: Refer to the wiki for an introduction to [OGN flavoured APRS](https://github.com/svoop/ogn_client-ruby/wiki) messages.
55
+ The factory method `OGNClient::Message.parse` will return one an instance of `OGNClient::Sender`, `OGNClient::Receiver`, `OGNClient::comment` or [raise an error](#errors). When this happens, either the message is crippled, the [OGN](http://glidernet.org) specifications have changed or you have found a bug in the parser code. You may want to store such messages, [file a bug](#community-support) and replay them once the bug has been fixed.
49
56
 
50
57
  #### OGNClient::Sender
51
58
 
52
59
  Senders are usually aircraft equipped with [FLARM](https://flarm.com) (anti-collision warning system) or similar devices which broadcast position data as RF beacons.
53
60
 
54
- The data is converted into the metric system since [OGN](http://glidernet.org) is primarily made for gliders which mostly use the metric system for speed, climb rate and so forth.
61
+ The data is converted into the metric system since [OGN](http://glidernet.org) is primarily made for gliders which mostly use the metric system for ground speed, climb rate and so forth.
55
62
 
56
63
  Attributes:
57
64
  * **callsign** - origin callsign
58
65
  * **receiver** - receiver callsign
59
- * **time** - UTZ/zulu time with date
60
- * **longitude** - degrees from -180 (W) to 180 (E)
61
- * **latitude** - degrees from -90 (S) to 90 (N)
62
- * **altitude** - meters
66
+ * **time** - zulu/UTC time with date
67
+ * **longitude** - WGS84 degrees from -180 (W) to 180 (E)
68
+ * **latitude** - WGS84 degrees from -90 (S) to 90 (N)
69
+ * **altitude** - WGS84 meters above mean see level QNH
63
70
  * **heading** - degrees from 1 to 360
64
- * **speed** - kilometers per hour
71
+ * **ground_speed** - kilometers per hour
65
72
  * **stealth_mode** - boolean (should always be false)
66
73
  * **no_tracking** - boolean
67
74
  * **sender_type** - see [SENDER_TYPES](https://github.com/svoop/ogn_client-ruby/blob/master/lib/ogn_client/messages/sender.rb)
@@ -69,11 +76,15 @@ Attributes:
69
76
  * **id** - device ID
70
77
  * **climb_rate** - meters per second
71
78
  * **turn_rate** - revolutions per minute
79
+ * **flight_level** - 100 feet QNE
72
80
  * **signal** - signal to noise ratio in decibel
73
81
  * **errors** - number of CRC errors
74
82
  * **frequency_offset** - kilohertz
75
83
  * **gps_accuracy** - array [vertical meters, horizontal meters]
76
- * **proximity** - array of callsign tails
84
+ * **flarm_software_version** - version as #<Gem::Version "major.minor">
85
+ * **flarm_hardware_version** - version as #<Gem::Version "major">
86
+ * **flarm_id** - FLARM device ID
87
+ * **proximity** - array of FLARM device ID tails
77
88
 
78
89
  #### OGNClient::Receiver
79
90
 
@@ -82,13 +93,13 @@ Receivers are little RF boxes which pick up the RF beacons from aircraft and rel
82
93
  Attributes:
83
94
  * **callsign** - origin callsign
84
95
  * **receiver** - receiver callsign
85
- * **time** - UTZ/zulu time with date
86
- * **longitude** - degrees from -180 (W) to 180 (E)
87
- * **latitude** - degrees from -90 (S) to 90 (N)
88
- * **altitude** - meters
96
+ * **time** - zulu/UTC time with date
97
+ * **longitude** - WG84 degrees from -180 (W) to 180 (E)
98
+ * **latitude** - WG84 degrees from -90 (S) to 90 (N)
99
+ * **altitude** - WG84 meters above mean sea level QNH
89
100
  * **heading** - degrees from 1 to 360
90
- * **speed** - kilometers per hour
91
- * **version** - software version "major.minor.patch"
101
+ * **ground_speed** - kilometers per hour
102
+ * **version** - software version as #<Gem::Version "major.minor.patch">
92
103
  * **platform** - e.g. :arm
93
104
  * **cpu_load** - as reported by "uptime"
94
105
  * **cpu_temperature** - in degrees celsius
@@ -105,23 +116,42 @@ Comments are sent on a regular basis to keep the connection alive.
105
116
  Attribute:
106
117
  * **comment** - raw message with the comment marker stripped
107
118
 
108
- #### OGNClient::Message
119
+ ## Errors
109
120
 
110
- Generic message objects are only used as a fallback in case the raw message string could not be parsed into one of the above three [OGN](http://glidernet.org) object types. If this happens, either the [OGN](http://glidernet.org) specifications have changed, the message is invalid or you have found a bug in the parser code. You can choose to ignore such messages or to store them for debugging and replaying once the bug is fixed.
121
+ The following domain specific errors may be raised:
111
122
 
112
- ## Debugging
123
+ * OGNClient::MessageError - errors during the parsing of a message
124
+ * OGNClient::ReceiverError - errors during the parsing of a receiver message
113
125
 
114
- To get additional debug messages, either invoke Ruby with the `-d` flag or set the global debug variable explicitly:
126
+ They all inherit from `OGNClient::Error`. An fault-tolerant subscription could therefore look as follows:
115
127
 
116
128
  ```ruby
117
- $DEBUG = true
129
+ logger = Logger.new('/tmp/ogn_client.log')
130
+ OGNClient::APRS.start(callsign: 'ROCT', filter: 'r/33/-97/200') do |aprs|
131
+ loop do
132
+ begin
133
+ message = OGNClient::Message.parse aprs.gets
134
+ rescue OGNClient::Error => error
135
+ logger.error error.message
136
+ end
137
+ puts message.raw
138
+ end
139
+ end
118
140
  ```
119
141
 
142
+ ## Community Support
143
+
144
+ * Look for developers and users on [Gitter](https://gitter.im/svoop/ogn_client-ruby).
145
+ * Ask your questions on [Stackoverflow](https://stackoverflow.com/questions/ask?tags=ogn_client-ruby,ruby,gem).
146
+ * Bug reports and pull requests are welcome on [GitHub](https://github.com/svoop/ogn_client-ruby).
147
+
120
148
  ## Development
121
149
 
122
150
  Check out the repository, install the dependencies and run the test suite:
123
151
 
124
152
  $ git clone git@github.com:svoop/ogn_client-ruby.git
153
+ $ cd ogn_client-ruby
154
+ $ gem install bundler
125
155
  $ bin/setup
126
156
  $ rake
127
157
 
@@ -137,12 +167,9 @@ And to install this gem onto your local machine:
137
167
 
138
168
  $ bundle exec rake install
139
169
 
140
- ## Contributing
141
-
142
- Bug reports and pull requests are welcome on GitHub at https://github.com/svoop/ogn_client-ruby
143
-
144
170
  ## Feature Brainstorming
145
171
 
172
+ * registration lookups
146
173
  * configuration option to switch between metric and aeronautical units
147
174
  * more data sources such as ADS-B
148
175
 
data/Rakefile CHANGED
@@ -9,3 +9,5 @@ Rake::TestTask.new do |t|
9
9
  end
10
10
 
11
11
  task :default => :test
12
+
13
+ Dir.glob('tasks/*.rake').each { |task| load task }
@@ -1,7 +1,7 @@
1
1
  require 'socket'
2
2
 
3
3
  require_relative 'ogn_client/version'
4
- require_relative 'ogn_client/debug'
4
+ require_relative 'ogn_client/errors'
5
5
  require_relative 'ogn_client/aprs'
6
6
  require_relative 'ogn_client/message'
7
7
  require_relative 'ogn_client/messages/comment'
@@ -0,0 +1,8 @@
1
+ module OGNClient
2
+
3
+ class Error < StandardError; end
4
+
5
+ class MessageError < Error; end
6
+ class ReceiverError < Error; end
7
+
8
+ end
@@ -27,49 +27,50 @@ module OGNClient
27
27
  (?<time>\d{6})h
28
28
  (?<latitude>\d{4}\.\d{2}[NS]).
29
29
  (?<longitude>\d{5}\.\d{2}[EW]).
30
- (?:(?<heading>\d{3})/(?<speed>\d{3}))?.*?
30
+ (?:(?<heading>\d{3})/(?<ground_speed>\d{3}))?.*?
31
31
  /A=(?<altitude>\d{6})\s
32
32
  (?:!W((?<latitude_enhancement>\d)(?<longitude_enhancement>\d))!)?
33
33
  )x
34
34
 
35
35
  attr_reader :raw
36
- attr_reader :callsign # origin callsign
37
- attr_reader :receiver # receiver callsign
38
- attr_reader :time # zulu time with date
39
- attr_reader :longitude # degrees from -180 (W) to 180 (E)
40
- attr_reader :latitude # degrees from -90 (S) to 90 (N)
41
- attr_reader :altitude # meters
42
- attr_reader :heading # degrees from 1 to 360
43
- attr_reader :speed # kilometers per hour
36
+ attr_reader :callsign # origin callsign
37
+ attr_reader :receiver # receiver callsign
38
+ attr_reader :time # zulu/UTC time with date
39
+ attr_reader :longitude # WGS84 degrees from -180 (W) to 180 (E)
40
+ attr_reader :latitude # WGS84 degrees from -90 (S) to 90 (N)
41
+ attr_reader :altitude # WGS84 meters above mean sea level QNH
42
+ attr_reader :heading # degrees from 1 to 360
43
+ attr_reader :ground_speed # kilometers per hour
44
44
 
45
45
  def self.parse(raw)
46
- OGNClient::Sender.new.parse(raw) ||
47
- OGNClient::Receiver.new.parse(raw) ||
48
- OGNClient::Comment.new.parse(raw) ||
49
- new.parse(raw)
46
+ fail(OGNClient::MessageError, "raw message must be String but is #{raw.class}") unless raw.is_a? String
47
+ raw = raw.chomp.force_encoding('ASCII-8BIT').encode('UTF-8')
48
+ OGNClient::Sender.new.send(:parse, raw) ||
49
+ OGNClient::Receiver.new.send(:parse, raw) ||
50
+ OGNClient::Comment.new.send(:parse, raw)
50
51
  end
51
52
 
53
+ def to_s
54
+ @raw
55
+ end
56
+
57
+ private
58
+
52
59
  def parse(raw)
53
60
  @raw = raw
54
- raw.match(POSITION_PATTERN) do |match|
61
+ @raw.match(POSITION_PATTERN) do |match|
55
62
  %i(callsign receiver time altitude).each do |attr|
56
63
  send "#{attr}=", match[attr]
57
64
  end
58
65
  self.heading = match[:heading] if match[:heading] && match[:heading] != '000'
59
- self.speed = match[:speed] if match[:speed] && match[:heading] != '000'
66
+ self.ground_speed = match[:ground_speed] if match[:ground_speed] && match[:heading] != '000'
60
67
  self.longitude = [match[:longitude], match[:longitude_enhancement]]
61
68
  self.latitude = [match[:latitude], match[:latitude_enhancement]]
62
69
  self
63
- end || OGNClient.debug("invalid message: `#{@raw}'")
70
+ end || fail(OGNClient::MessageError, "message parsing failed: `#{@raw}'")
64
71
  self
65
72
  end
66
73
 
67
- def to_s
68
- @raw
69
- end
70
-
71
- private
72
-
73
74
  def callsign=(raw)
74
75
  @callsign = raw
75
76
  end
@@ -103,8 +104,8 @@ module OGNClient
103
104
  @heading = raw.to_i
104
105
  end
105
106
 
106
- def speed=(raw)
107
- @speed = (raw.to_i * 1.852).round
107
+ def ground_speed=(raw)
108
+ @ground_speed = (raw.to_i * 1.852).round
108
109
  end
109
110
 
110
111
  end
@@ -8,16 +8,16 @@ module OGNClient
8
8
 
9
9
  attr_reader :comment # free form text comment
10
10
 
11
+ private
12
+
11
13
  def parse(raw)
12
14
  @raw = raw
13
- raw.match COMMENT_PATTERN do |match|
15
+ @raw.match COMMENT_PATTERN do |match|
14
16
  self.comment = match[:comment]
15
17
  self
16
18
  end
17
19
  end
18
20
 
19
- private
20
-
21
21
  def comment=(raw)
22
22
  @comment = raw
23
23
  end
@@ -3,38 +3,54 @@ module OGNClient
3
3
  class Receiver < Message
4
4
 
5
5
  RECEIVER_PATTERN = %r(
6
- v(?<version>\d+\.\d+\.\d+)\.(?<platform>.+?)\s
6
+ (?:
7
+ v(?<version>\d+\.\d+\.\d+)
8
+ (?:\.(?<platform>.+?))?
9
+ \s)?
7
10
  CPU:(?<cpu_load>[\d.]+)\s
8
11
  RAM:(?<ram_free>[\d.]+)/(?<ram_total>[\d.]+)MB\s
9
- NTP:(?<ntp_offset>[\d.]+)ms/(?<ntp_correction>[+-][\d.]+)ppm\s
10
- (?:(?<cpu_temperature>[+-][\d.]+)C\s)?
11
- RF:(?<signal>[+-][\d.]+)dB
12
+ NTP:(?<ntp_offset>[\d.]+)ms/(?<ntp_correction>[+-][\d.]+)ppm\s?
13
+ (?:(?<cpu_temperature>[+-][\d.]+)C\s*)?
14
+ (?:RF:
15
+ (?:
16
+ (?<manual_correction>[+-][\d]+)
17
+ (?<automatic_correction>[+-][\d.]+)ppm/
18
+ )?
19
+ (?<signal>[+-][\d.]+)dB
20
+ )?
12
21
  $)x
13
22
 
14
- attr_reader :version # software version "major.minor.patch"
15
- attr_reader :platform # e.g. "ARM"
16
- attr_reader :cpu_load # as reported by "uptime"
17
- attr_reader :cpu_temperature # degrees celsius
18
- attr_reader :ram_free # megabytes
19
- attr_reader :ram_total # megabytes
20
- attr_reader :ntp_offset # milliseconds
21
- attr_reader :ntp_correction # parts-per-million
22
- attr_reader :signal # signal-to-noise ratio in decibel
23
+ SUPPORTED_RECEIVER_VERSION = Gem::Version.new('0.2.5')
24
+
25
+ attr_reader :version # software version as #<Gem::Version "major.minor.patch">
26
+ attr_reader :platform # e.g. "ARM"
27
+ attr_reader :cpu_load # as reported by "uptime"
28
+ attr_reader :cpu_temperature # degrees celsius
29
+ attr_reader :ram_free # megabytes
30
+ attr_reader :ram_total # megabytes
31
+ attr_reader :ntp_offset # milliseconds
32
+ attr_reader :ntp_correction # parts-per-million
33
+ attr_reader :manual_correction # as per configuration
34
+ attr_reader :automatic_correction # based on GSM
35
+ attr_reader :signal # signal-to-noise ratio in decibel
36
+
37
+ private
23
38
 
24
39
  def parse(raw)
25
- raw.match RECEIVER_PATTERN do |match|
40
+ @raw = raw
41
+ @raw.match RECEIVER_PATTERN do |match|
26
42
  return unless super
27
- %i(version platform cpu_load cpu_temperature ram_free ram_total ntp_offset ntp_correction signal).each do |attr|
43
+ %i(version platform cpu_load cpu_temperature ram_free ram_total ntp_offset ntp_correction manual_correction automatic_correction signal).each do |attr|
28
44
  send("#{attr}=", match[attr]) if match[attr]
29
45
  end
30
46
  self
31
47
  end
32
48
  end
33
49
 
34
- private
35
-
36
50
  def version=(raw)
37
- @version = raw
51
+ @version = Gem::Version.new(raw)
52
+ fail(OGNClient::ReceiverError, "unsupported receiver version: `#{@raw}'") if @version > SUPPORTED_RECEIVER_VERSION
53
+ @version
38
54
  end
39
55
 
40
56
  def platform=(raw)
@@ -65,6 +81,14 @@ module OGNClient
65
81
  @ntp_correction = raw.to_f.round(2)
66
82
  end
67
83
 
84
+ def manual_correction=(raw)
85
+ @manual_correction = raw.to_i
86
+ end
87
+
88
+ def automatic_correction=(raw)
89
+ @automatic_correction = raw.to_f.round(1)
90
+ end
91
+
68
92
  def signal=(raw)
69
93
  @signal = raw.to_f.round(3)
70
94
  end
@@ -6,10 +6,14 @@ module OGNClient
6
6
  id(?<details>\w{2})(?<id>\w+?)\s
7
7
  (?<climb_rate>[+-]\d+?)fpm\s
8
8
  (?<turn_rate>[+-][\d.]+?)rot\s
9
+ (?:FL(?<flight_level>[\d.]+)\s)?
9
10
  (?<signal>[\d.]+?)dB\s
10
11
  (?<errors>\d+)e\s
11
12
  (?<frequency_offset>[+-][\d.]+?)kHz\s?
12
13
  (?:gps(?<gps_accuracy>\d+x\d+)\s?)?
14
+ (?:s(?<flarm_software_version>[\d.]+)\s?)?
15
+ (?:h(?<flarm_hardware_version>[\dA-F]{2})\s?)?
16
+ (?:r(?<flarm_id>[\dA-F]+)\s?)?
13
17
  (?:hear(?<proximity>.+))?
14
18
  $)x
15
19
 
@@ -37,31 +41,39 @@ module OGNClient
37
41
  3 => :ogn
38
42
  }
39
43
 
40
- attr_reader :stealth_mode # boolean
41
- attr_reader :no_tracking # boolean
42
- attr_reader :sender_type # see SENDER_TYPES
43
- attr_reader :address_type # see ADDRESS_TYPES
44
- attr_reader :id # device ID
45
- attr_reader :climb_rate # meters per second
46
- attr_reader :turn_rate # revolutions per minute
47
- attr_reader :signal # signal to noise ratio in decibel
48
- attr_reader :errors # number of CRC errors
49
- attr_reader :frequency_offset # kilohertz
50
- attr_reader :gps_accuracy # array [vertical meters, horizontal meters]
51
- attr_reader :proximity # array of callsign tails
44
+ attr_reader :stealth_mode # boolean
45
+ attr_reader :no_tracking # boolean
46
+ attr_reader :sender_type # see SENDER_TYPES
47
+ attr_reader :address_type # see ADDRESS_TYPES
48
+ attr_reader :id # device ID
49
+ attr_reader :climb_rate # meters per second
50
+ attr_reader :turn_rate # revolutions per minute
51
+ attr_reader :flight_level # 100 feet QNE
52
+ attr_reader :signal # signal to noise ratio in decibel
53
+ attr_reader :errors # number of CRC errors
54
+ attr_reader :frequency_offset # kilohertz
55
+ attr_reader :gps_accuracy # array [vertical meters, horizontal meters]
56
+ attr_reader :flarm_software_version # version as #<Gem::Version "major.minor">
57
+ attr_reader :flarm_hardware_version # version as #<Gem::Version "major">
58
+ attr_reader :flarm_id # FLARM device ID
59
+ attr_reader :proximity # array of FLARM device ID tails
60
+
61
+ private
52
62
 
53
63
  def parse(raw)
54
- raw.match SENDER_PATTERN do |match|
64
+ @raw = raw
65
+ @raw.match SENDER_PATTERN do |match|
55
66
  return unless super
56
- %i(details id climb_rate turn_rate signal errors frequency_offset gps_accuracy proximity).each do |attr|
67
+ %i(details id climb_rate turn_rate flight_level signal errors frequency_offset gps_accuracy flarm_software_version flarm_hardware_version flarm_id proximity).each do |attr|
57
68
  send("#{attr}=", match[attr]) if match[attr]
58
69
  end
70
+ # NOTE: [@svoop] [ruby21] workaround necessary until support for ruby21 is removed
71
+ # self.flarm_id ||= id if address_type == :icao || address_type == :flarm
72
+ self.flarm_id = id if !flarm_id && (address_type == :icao || address_type == :flarm)
59
73
  self
60
74
  end
61
75
  end
62
76
 
63
- private
64
-
65
77
  def details=(raw)
66
78
  byte = raw.to_i(16)
67
79
  @stealth_mode = !(byte & 0b10000000).zero?
@@ -82,6 +94,10 @@ module OGNClient
82
94
  @turn_rate = (raw.to_i / 4.0).round(1)
83
95
  end
84
96
 
97
+ def flight_level=(raw)
98
+ @flight_level = raw.to_f.round(2)
99
+ end
100
+
85
101
  def signal=(raw)
86
102
  @signal = raw.to_f.round(1)
87
103
  end
@@ -98,6 +114,18 @@ module OGNClient
98
114
  @gps_accuracy = raw.split('x').map(&:to_i)
99
115
  end
100
116
 
117
+ def flarm_software_version=(raw)
118
+ @flarm_software_version = Gem::Version.new raw
119
+ end
120
+
121
+ def flarm_hardware_version=(raw)
122
+ @flarm_hardware_version = Gem::Version.new raw.to_i(16)
123
+ end
124
+
125
+ def flarm_id=(raw)
126
+ @flarm_id = raw
127
+ end
128
+
101
129
  def proximity=(raw)
102
130
  @proximity = raw.split(/\shear/)
103
131
  end
@@ -1,3 +1,3 @@
1
1
  module OGNClient
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1".freeze
3
3
  end
@@ -0,0 +1,21 @@
1
+
2
+ namespace :test do
3
+
4
+ desc "Parse real-time APRS messages and test the parser"
5
+ task :parser do
6
+ require 'ogn_client'
7
+ OGNClient::APRS.start(callsign: 'ROCT') do |aprs|
8
+ loop do
9
+ print '.'
10
+ raw = aprs.gets
11
+ begin
12
+ OGNClient::Message.parse raw
13
+ rescue OGNClient::Error => error
14
+ puts
15
+ warn "WARNING: #{error.message}"
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ogn_client-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sven Schwyn
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-12-05 00:00:00.000000000 Z
11
+ date: 2015-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -103,6 +103,7 @@ executables: []
103
103
  extensions: []
104
104
  extra_rdoc_files: []
105
105
  files:
106
+ - ".code_climate.yml"
106
107
  - ".editorconfig"
107
108
  - ".gitignore"
108
109
  - ".ruby-version"
@@ -117,13 +118,14 @@ files:
117
118
  - bin/setup
118
119
  - lib/ogn_client.rb
119
120
  - lib/ogn_client/aprs.rb
120
- - lib/ogn_client/debug.rb
121
+ - lib/ogn_client/errors.rb
121
122
  - lib/ogn_client/message.rb
122
123
  - lib/ogn_client/messages/comment.rb
123
124
  - lib/ogn_client/messages/receiver.rb
124
125
  - lib/ogn_client/messages/sender.rb
125
126
  - lib/ogn_client/version.rb
126
127
  - ogn_client-ruby.gemspec
128
+ - tasks/test.rake
127
129
  homepage: https://github.com/svoop/ogn_client-ruby
128
130
  licenses:
129
131
  - MIT
@@ -1,9 +0,0 @@
1
- module OGNClient
2
- class << self
3
-
4
- def debug(message)
5
- puts "DEBUG: #{message}" if $DEBUG
6
- end
7
-
8
- end
9
- end