nmea_gps 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/Guardfile +18 -0
- data/LICENSE.txt +22 -0
- data/README.md +80 -0
- data/Rakefile +7 -0
- data/lib/nmea_gps/config.rb +11 -0
- data/lib/nmea_gps/gps.rb +82 -0
- data/lib/nmea_gps/sentence_base.rb +37 -0
- data/lib/nmea_gps/sentences/gga.rb +70 -0
- data/lib/nmea_gps/sentences/gll.rb +34 -0
- data/lib/nmea_gps/sentences/gsa.rb +57 -0
- data/lib/nmea_gps/sentences/gsv.rb +34 -0
- data/lib/nmea_gps/sentences/rmc.rb +65 -0
- data/lib/nmea_gps/sentences/vtg.rb +27 -0
- data/lib/nmea_gps/sentences/zda.rb +31 -0
- data/lib/nmea_gps/version.rb +3 -0
- data/lib/nmea_gps.rb +40 -0
- data/nmea_gps.gemspec +29 -0
- data/spec/ddd_formatable_spec.rb +18 -0
- data/spec/lib/gps_spec.rb +97 -0
- data/spec/lib/nmea_gps/gps_spec.rb +138 -0
- data/spec/lib/nmea_gps/sentence_base_spec.rb +25 -0
- data/spec/lib/nmea_gps/sentences/gga_spec.rb +59 -0
- data/spec/lib/nmea_gps/sentences/gll_spec.rb +37 -0
- data/spec/lib/nmea_gps/sentences/gsa_spec.rb +44 -0
- data/spec/lib/nmea_gps/sentences/gsv_spec.rb +36 -0
- data/spec/lib/nmea_gps/sentences/rmc_spec.rb +62 -0
- data/spec/lib/nmea_gps/sentences/vtg_spec.rb +28 -0
- data/spec/lib/nmea_gps/sentences/zda_spec.rb +32 -0
- data/spec/nmea_gps_spec.rb +8 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/utc_timeable_spec.rb +32 -0
- metadata +205 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fa3fef3d96dff44cb620276abc67d7e7eab832f0
|
4
|
+
data.tar.gz: c5ed23427e8805430ce9392035a149f8d1c74f3e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 40adfabfbbfcf6167565709b84634dfb3c8d0cffcd82bbe9f9a00b3b557df3016aed4064639259deef1864dafd206a3ad6208d8cbee616fbff9c2ab52e9272df
|
7
|
+
data.tar.gz: 29ddd56de23382fd20364a607b234efa347ae430ab1e6b515411ec00cdffb869965d5ed6811110f7e308287197426c0333bc48d546b42772fb4b2780f24fd708
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
5
|
+
# rspec may be run, below are examples of the most common uses.
|
6
|
+
# * bundler: 'bundle exec rspec'
|
7
|
+
# * bundler binstubs: 'bin/rspec'
|
8
|
+
# * spring: 'bin/rsspec' (This will use spring if running and you have
|
9
|
+
# installed the spring binstubs per the docs)
|
10
|
+
# * zeus: 'zeus rspec' (requires the server to be started separetly)
|
11
|
+
# * 'just' rspec: 'rspec'
|
12
|
+
guard :rspec, cmd: 'bundle exec rspec' do
|
13
|
+
watch(%r{^spec/.+_spec\.rb$})
|
14
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
15
|
+
watch('spec/spec_helper.rb') { "spec" }
|
16
|
+
|
17
|
+
end
|
18
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 ore
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
## Installation
|
2
|
+
|
3
|
+
Add this line to your application's Gemfile:
|
4
|
+
|
5
|
+
gem 'nmea_gps'
|
6
|
+
|
7
|
+
And then execute:
|
8
|
+
|
9
|
+
$ bundle
|
10
|
+
|
11
|
+
Or install it yourself as:
|
12
|
+
|
13
|
+
$ gem install nmea_gps
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
|
19
|
+
# create a serialport to your GPS receiver
|
20
|
+
# you should know how to open a connection between your GPS device
|
21
|
+
# mine runs on `9600 baudrate`, `8bit`, `1stop bit`, `none parity`
|
22
|
+
serialport = SerialPort.new("/dev/cu.your_whatever_device", 9600, 8, 1, SerialPort::NONE)
|
23
|
+
|
24
|
+
# you should know about your GPS receiver's update Hz(how often it will update logs 10Hz = 10 times per sec.)
|
25
|
+
# if you don't know leave it blank. It will at least update every sec.
|
26
|
+
gps = Nmea::Gps.new serialport update_hz: 10
|
27
|
+
|
28
|
+
# this will be called automatically!!
|
29
|
+
gps.rmc do |rmc|
|
30
|
+
p rmc.time
|
31
|
+
p rmc.latitude
|
32
|
+
p rmc.longitude
|
33
|
+
p rmc.heading
|
34
|
+
p rmc.date
|
35
|
+
end
|
36
|
+
|
37
|
+
# start the tracking
|
38
|
+
gps.track!
|
39
|
+
|
40
|
+
# you can also have
|
41
|
+
# gps.gga do |gga|
|
42
|
+
# ..
|
43
|
+
# end
|
44
|
+
# gps.gll do |gll|
|
45
|
+
# ..
|
46
|
+
# end
|
47
|
+
# gps.gsa do |gsa|
|
48
|
+
# ..
|
49
|
+
# end
|
50
|
+
# gps.vtg do |vtg|
|
51
|
+
# ..
|
52
|
+
# end
|
53
|
+
# gps.zda do |zda|
|
54
|
+
# ..
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# this one gets multiple Gsv objects
|
58
|
+
# gps.gsv do |gsvs|
|
59
|
+
# p gsvs.count
|
60
|
+
# ..
|
61
|
+
# end
|
62
|
+
|
63
|
+
# do your other works
|
64
|
+
# ..
|
65
|
+
# ..
|
66
|
+
# ..
|
67
|
+
|
68
|
+
# when you want to stop callbacks, you can call this
|
69
|
+
# gps.stop!
|
70
|
+
# then close the connection
|
71
|
+
# serialport.close
|
72
|
+
```
|
73
|
+
|
74
|
+
## Contributing
|
75
|
+
|
76
|
+
1. Fork it ( https://github.com/[my-github-username]/nmea_gps/fork )
|
77
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
78
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
79
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
80
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/nmea_gps/gps.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
module Nmea
|
2
|
+
|
3
|
+
class Gps
|
4
|
+
TALKER_ID = "GP"
|
5
|
+
|
6
|
+
def initialize(serial_port, update_hz: 1)
|
7
|
+
self.callbacks = {}
|
8
|
+
self.gps_serial_port = serial_port
|
9
|
+
self.update_hz = 1.second.to_f / update_hz.to_i
|
10
|
+
end
|
11
|
+
|
12
|
+
Dir[Pathname(__FILE__).join("../sentences/*.rb")].collect do |path|
|
13
|
+
Pathname(path).basename(".rb").to_s
|
14
|
+
end.each do |sentence|
|
15
|
+
define_method(sentence) do |&block|
|
16
|
+
self.callbacks[__callee__] = block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def track!
|
21
|
+
self.track_thread = Thread.new do
|
22
|
+
loop do
|
23
|
+
callback!
|
24
|
+
frequency
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def stop!
|
30
|
+
self.track_thread.kill if self.track_thread.respond_to? :kill
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
attr_accessor :gps_serial_port, :update_hz, :callbacks, :track_thread
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def hz
|
39
|
+
self.update_hz
|
40
|
+
end
|
41
|
+
|
42
|
+
def frequency
|
43
|
+
sleep hz
|
44
|
+
end
|
45
|
+
|
46
|
+
def line_set
|
47
|
+
Hash.new{|hash, key| hash[key] = [] }.tap do |set|
|
48
|
+
loop do
|
49
|
+
line = self.gps_serial_port.gets("\r\n").strip
|
50
|
+
# %w[ GLL RMC VTG GGA GSA GSV ZDA].join.chars.uniq.sort.join
|
51
|
+
return unless match = line.match(/\A\$#{TALKER_ID}([ACDGLMRSTVZ]{3})/)
|
52
|
+
|
53
|
+
sentence = match[1].downcase.to_sym
|
54
|
+
set[sentence] << line
|
55
|
+
break if sentence == :gga
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def callback!
|
61
|
+
this_set = line_set
|
62
|
+
this_set.keys.each do |sentence|
|
63
|
+
this_callback = self.callbacks[sentence]
|
64
|
+
next unless this_callback
|
65
|
+
|
66
|
+
target_class = "Nmea::Gps::#{sentence.to_s.camelcase}".constantize
|
67
|
+
|
68
|
+
object = if sentence == :gsv
|
69
|
+
this_set[sentence].sort.collect do |line|
|
70
|
+
target_class.new line
|
71
|
+
end
|
72
|
+
else
|
73
|
+
target_class.new(this_set[sentence].first)
|
74
|
+
end
|
75
|
+
|
76
|
+
this_callback.call object
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Nmea
|
2
|
+
class Gps
|
3
|
+
|
4
|
+
class SentenceBase
|
5
|
+
|
6
|
+
STATUSES = {
|
7
|
+
"A" => :valid,
|
8
|
+
"V" => :invalid,
|
9
|
+
}
|
10
|
+
|
11
|
+
MODES = {
|
12
|
+
"A" => :autonomous,
|
13
|
+
"N" => :no_fix,
|
14
|
+
"D" => :dgps,
|
15
|
+
"E" => :dr,
|
16
|
+
}
|
17
|
+
|
18
|
+
|
19
|
+
def initialize(line)
|
20
|
+
@line = line
|
21
|
+
end
|
22
|
+
|
23
|
+
def name
|
24
|
+
raise "override this method"
|
25
|
+
end
|
26
|
+
|
27
|
+
def raw_data
|
28
|
+
_, *data = self.line.split("*").first.split(",")
|
29
|
+
data
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
attr_reader :line
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Nmea
|
2
|
+
class Gps
|
3
|
+
|
4
|
+
class Gga < SentenceBase
|
5
|
+
include Nmea::UtcTimeable, Nmea::DddFormatable
|
6
|
+
|
7
|
+
QUALITIES = {
|
8
|
+
0 => :invalid,
|
9
|
+
1 => :gps_sps_fix,
|
10
|
+
2 => :dgps_fix,
|
11
|
+
3 => :gps_pps_fix,
|
12
|
+
}
|
13
|
+
|
14
|
+
def name
|
15
|
+
"Global positioning system fixed data"
|
16
|
+
end
|
17
|
+
|
18
|
+
def time
|
19
|
+
hhmmss_to_local_time raw_data[0]
|
20
|
+
end
|
21
|
+
|
22
|
+
def latitude
|
23
|
+
dmm_to_ddd raw_data[1], raw_data[2]
|
24
|
+
end
|
25
|
+
|
26
|
+
def longitude
|
27
|
+
dmm_to_ddd raw_data[3], raw_data[4]
|
28
|
+
end
|
29
|
+
|
30
|
+
def quality
|
31
|
+
QUALITIES[raw_data[5].to_i]
|
32
|
+
end
|
33
|
+
|
34
|
+
def number_of_satellites
|
35
|
+
raw_data[6].to_i
|
36
|
+
end
|
37
|
+
alias :satellites :number_of_satellites
|
38
|
+
|
39
|
+
# http://en.wikipedia.org/wiki/Dilution_of_precision_%28GPS%29
|
40
|
+
def horizontal_dilution_of_precision
|
41
|
+
raw_data[7].to_f
|
42
|
+
end
|
43
|
+
alias :hdop :horizontal_dilution_of_precision
|
44
|
+
|
45
|
+
def altitude_in_meters
|
46
|
+
raw_data[8].to_f
|
47
|
+
end
|
48
|
+
alias :altitude :altitude_in_meters
|
49
|
+
|
50
|
+
def height_of_geoid_above_wgs84_ellipsoid
|
51
|
+
raw_data[10].to_f
|
52
|
+
end
|
53
|
+
alias :height_of_geoid :height_of_geoid_above_wgs84_ellipsoid
|
54
|
+
|
55
|
+
def time_in_seconds_since_last_dgps_update
|
56
|
+
raw_data[12].to_i
|
57
|
+
end
|
58
|
+
alias :last_dgps_update :time_in_seconds_since_last_dgps_update
|
59
|
+
|
60
|
+
def dgps_station_id
|
61
|
+
raw_data[13].to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
def checksum
|
65
|
+
raw_data[14].to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Nmea
|
2
|
+
class Gps
|
3
|
+
|
4
|
+
class Gll < SentenceBase
|
5
|
+
include Nmea::UtcTimeable, Nmea::DddFormatable
|
6
|
+
|
7
|
+
def name
|
8
|
+
"Geographic position—latitude/longitude"
|
9
|
+
end
|
10
|
+
|
11
|
+
def latitude
|
12
|
+
dmm_to_ddd raw_data[0], raw_data[1]
|
13
|
+
end
|
14
|
+
|
15
|
+
def longitude
|
16
|
+
dmm_to_ddd raw_data[2], raw_data[3]
|
17
|
+
end
|
18
|
+
|
19
|
+
def time
|
20
|
+
hhmmss_to_local_time raw_data[4]
|
21
|
+
end
|
22
|
+
|
23
|
+
def status
|
24
|
+
STATUSES[raw_data[5]]
|
25
|
+
end
|
26
|
+
|
27
|
+
def mode
|
28
|
+
MODES[raw_data[6]]
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Nmea
|
2
|
+
class Gps
|
3
|
+
|
4
|
+
class Gsa < SentenceBase
|
5
|
+
|
6
|
+
MODE_SELECTIONS = {
|
7
|
+
"M" => :manual,
|
8
|
+
"A" => :automatic,
|
9
|
+
}
|
10
|
+
|
11
|
+
MODES = {
|
12
|
+
"1" => :fix_not_available,
|
13
|
+
"2" => :fix_2D,
|
14
|
+
"3" => :fix_3D,
|
15
|
+
}
|
16
|
+
|
17
|
+
def name
|
18
|
+
"GNSS DOP and active satellites"
|
19
|
+
end
|
20
|
+
|
21
|
+
def mode_selection
|
22
|
+
MODE_SELECTIONS[raw_data[0]]
|
23
|
+
end
|
24
|
+
|
25
|
+
def mode
|
26
|
+
MODES[raw_data[1]]
|
27
|
+
end
|
28
|
+
|
29
|
+
def ids_of_svs_used_in_position_fix(at = :all)
|
30
|
+
ids = raw_data[2..13]
|
31
|
+
return ids if at == :all
|
32
|
+
|
33
|
+
id = ids[at.to_i - 1]
|
34
|
+
return nil if id.blank?
|
35
|
+
|
36
|
+
id.to_i
|
37
|
+
end
|
38
|
+
alias :svs_ids :ids_of_svs_used_in_position_fix
|
39
|
+
|
40
|
+
def position_dilution_of_precision
|
41
|
+
raw_data[14].to_f
|
42
|
+
end
|
43
|
+
alias :pdop :position_dilution_of_precision
|
44
|
+
|
45
|
+
def horizontal_dilution_of_precision
|
46
|
+
raw_data[15].to_f
|
47
|
+
end
|
48
|
+
alias :hdop :horizontal_dilution_of_precision
|
49
|
+
|
50
|
+
def vertical_dilution_of_precision
|
51
|
+
raw_data[16].to_f
|
52
|
+
end
|
53
|
+
alias :vdop :vertical_dilution_of_precision
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Nmea
|
2
|
+
class Gps
|
3
|
+
|
4
|
+
class Gsv < SentenceBase
|
5
|
+
def name
|
6
|
+
"GNSS satellites in view"
|
7
|
+
end
|
8
|
+
|
9
|
+
def number_of_message
|
10
|
+
raw_data[0].to_i
|
11
|
+
end
|
12
|
+
|
13
|
+
def message_number
|
14
|
+
raw_data[1].to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
def number_of_satellites_in_view
|
18
|
+
raw_data[2].to_i
|
19
|
+
end
|
20
|
+
|
21
|
+
def satellites
|
22
|
+
raw_data[3..-1].each_slice(4).collect do |slice|
|
23
|
+
OpenStruct.new.tap do |satellite|
|
24
|
+
satellite.id = slice.first.to_i
|
25
|
+
satellite.elevation = slice[1].to_i
|
26
|
+
satellite.azinmuth = slice[2].to_i
|
27
|
+
satellite.signal_to_noise_ratio = satellite.snr = slice.last.to_i
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Nmea
|
2
|
+
class Gps
|
3
|
+
|
4
|
+
class Rmc < SentenceBase
|
5
|
+
include Nmea::UtcTimeable, Nmea::DddFormatable
|
6
|
+
|
7
|
+
def name
|
8
|
+
"Recommended minimum specific GNSS data"
|
9
|
+
end
|
10
|
+
|
11
|
+
def time
|
12
|
+
hhmmss_to_local_time raw_data[0]
|
13
|
+
end
|
14
|
+
|
15
|
+
def status
|
16
|
+
STATUSES[raw_data[1]]
|
17
|
+
end
|
18
|
+
|
19
|
+
def latitude
|
20
|
+
dmm_to_ddd raw_data[2], raw_data[3]
|
21
|
+
end
|
22
|
+
|
23
|
+
def longitude
|
24
|
+
dmm_to_ddd raw_data[4], raw_data[5]
|
25
|
+
end
|
26
|
+
|
27
|
+
def knot_per_hour
|
28
|
+
raw_data[6].to_f
|
29
|
+
end
|
30
|
+
|
31
|
+
def km_per_hour
|
32
|
+
knot_per_hour * 1.85200
|
33
|
+
end
|
34
|
+
|
35
|
+
def mile_per_hour
|
36
|
+
knot_per_hour * 1.15077945
|
37
|
+
end
|
38
|
+
|
39
|
+
def heading
|
40
|
+
raw_data[7].to_f
|
41
|
+
end
|
42
|
+
|
43
|
+
def date
|
44
|
+
_, day, month, year = raw_data[8].match(/(\d{2})(\d{2})(\d{2})/).to_a
|
45
|
+
Date.parse("#{year}/#{month}/#{day}")
|
46
|
+
end
|
47
|
+
|
48
|
+
def magnetic_variation
|
49
|
+
return nil if raw_data[9].blank?
|
50
|
+
raw_data[9].to_f
|
51
|
+
end
|
52
|
+
|
53
|
+
def magnetic_variation_direction
|
54
|
+
return nil if raw_data[10].blank?
|
55
|
+
raw_data[10].to_f
|
56
|
+
end
|
57
|
+
|
58
|
+
def mode
|
59
|
+
MODES[raw_data[11]]
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Nmea
|
2
|
+
class Gps
|
3
|
+
|
4
|
+
class Vtg < SentenceBase
|
5
|
+
def name
|
6
|
+
"Course over ground and ground speed"
|
7
|
+
end
|
8
|
+
|
9
|
+
def true_course
|
10
|
+
raw_data[0].to_f
|
11
|
+
end
|
12
|
+
|
13
|
+
def magnetic_course
|
14
|
+
return if raw_data[2].blank?
|
15
|
+
raw_data[2].to_f
|
16
|
+
end
|
17
|
+
|
18
|
+
def knot_per_hour
|
19
|
+
raw_data[4].to_f
|
20
|
+
end
|
21
|
+
|
22
|
+
def km_per_hour
|
23
|
+
raw_data[6].to_f
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Nmea
|
2
|
+
class Gps
|
3
|
+
|
4
|
+
class Zda < SentenceBase
|
5
|
+
include Nmea::UtcTimeable
|
6
|
+
|
7
|
+
def name
|
8
|
+
"Date and Time"
|
9
|
+
end
|
10
|
+
|
11
|
+
def time
|
12
|
+
hhmmss_to_local_time raw_data[0]
|
13
|
+
end
|
14
|
+
|
15
|
+
def date
|
16
|
+
Date.parse("#{raw_data[3]}/#{raw_data[2]}/#{raw_data[1]}")
|
17
|
+
end
|
18
|
+
|
19
|
+
def local_zone_hours
|
20
|
+
return if raw_data[4].blank?
|
21
|
+
raw_data[4].to_i
|
22
|
+
end
|
23
|
+
|
24
|
+
def local_zone_minutes
|
25
|
+
return if raw_data[5].blank?
|
26
|
+
raw_data[5].to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/nmea_gps.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "serialport"
|
3
|
+
require "ostruct"
|
4
|
+
|
5
|
+
require 'active_support'
|
6
|
+
require 'active_support/core_ext'
|
7
|
+
Time.zone = "UTC"
|
8
|
+
|
9
|
+
require "nmea_gps/version"
|
10
|
+
require "nmea_gps/config"
|
11
|
+
require "nmea_gps/gps"
|
12
|
+
|
13
|
+
require "nmea_gps/sentence_base"
|
14
|
+
Dir[Pathname(__FILE__).join("../sentences/*.rb")].each {|file| require file }
|
15
|
+
|
16
|
+
module Nmea
|
17
|
+
|
18
|
+
module UtcTimeable
|
19
|
+
protected
|
20
|
+
def hhmmss_to_local_time(text)
|
21
|
+
hh, mm, ss = text.chars.each_slice(2).collect{|chars| chars.join }
|
22
|
+
utc_today = Time.zone.today
|
23
|
+
Time.zone.local(utc_today.year, utc_today.month, utc_today.day, hh, mm, ss).
|
24
|
+
in_time_zone(Nmea::Config.time_zone)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module DddFormatable
|
29
|
+
protected
|
30
|
+
def dmm_to_ddd(dmm, direction)
|
31
|
+
dmm = dmm.to_f / 100
|
32
|
+
integer = dmm.to_i
|
33
|
+
decimal = dmm % 1
|
34
|
+
|
35
|
+
(integer + decimal / 60 * 100.0) * ("NE".include?(direction) ? 1 : -1)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|