gps_pvt 0.10.1 → 0.10.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/Rakefile +27 -16
- data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +10 -10
- data/ext/ninja-scan-light/tool/navigation/GPS.h +22 -3
- data/ext/ninja-scan-light/tool/swig/Coordinate.i +6 -0
- data/ext/ninja-scan-light/tool/swig/SylphideMath.i +37 -0
- data/ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb +6 -4
- data/gps_pvt.gemspec +1 -0
- data/lib/gps_pvt/asn1/asn1.rb +34 -11
- data/lib/gps_pvt/asn1/asn1.y +112 -63
- data/lib/gps_pvt/ntrip.rb +6 -3
- data/lib/gps_pvt/receiver/almanac.rb +137 -0
- data/lib/gps_pvt/receiver/extension.rb +3 -6
- data/lib/gps_pvt/receiver.rb +1 -0
- data/lib/gps_pvt/supl.rb +162 -55
- data/lib/gps_pvt/upl/MAP-LCS-DataTypes-V17_4_0-Release17.asn +740 -0
- data/lib/gps_pvt/upl/RRLP-V17_0_0-Release17.asn +6 -1
- data/lib/gps_pvt/upl/upl.json.gz +0 -0
- data/lib/gps_pvt/upl/upl.rb +48 -0
- data/lib/gps_pvt/util.rb +8 -2
- data/lib/gps_pvt/version.rb +1 -1
- metadata +18 -2
data/lib/gps_pvt/supl.rb
CHANGED
@@ -16,6 +16,7 @@ class SUPL_Client
|
|
16
16
|
:port => 7275,
|
17
17
|
:debug => 0,
|
18
18
|
:protocol => [:lpp, :rrlp],
|
19
|
+
:req_data => [:ephemeris], # :almanac
|
19
20
|
}.merge(opts)
|
20
21
|
end
|
21
22
|
|
@@ -152,6 +153,16 @@ class SUPL_Client
|
|
152
153
|
cmd[:sessionID] = @session_id
|
153
154
|
proc{|posinit|
|
154
155
|
posinit[:sETCapabilities] = @capability
|
156
|
+
req_data = [
|
157
|
+
@opts[:req_data].find_index(:almanac) && :almanacRequested,
|
158
|
+
:utcModelRequested,
|
159
|
+
:ionosphericModelRequested,
|
160
|
+
:referenceLocationRequested,
|
161
|
+
:referenceTimeRequested,
|
162
|
+
:acquisitionAssistanceRequested,
|
163
|
+
:realTimeIntegrityRequested,
|
164
|
+
@opts[:req_data].find_index(:ephemeris) && :navigationModelRequested,
|
165
|
+
].compact
|
155
166
|
posinit[:requestedAssistData] = Hash[*([
|
156
167
|
:almanacRequested,
|
157
168
|
:utcModelRequested,
|
@@ -163,15 +174,7 @@ class SUPL_Client
|
|
163
174
|
:realTimeIntegrityRequested,
|
164
175
|
:navigationModelRequested,
|
165
176
|
].collect{|k|
|
166
|
-
[k,
|
167
|
-
:utcModelRequested,
|
168
|
-
:ionosphericModelRequested,
|
169
|
-
:referenceLocationRequested,
|
170
|
-
:referenceTimeRequested,
|
171
|
-
:acquisitionAssistanceRequested,
|
172
|
-
:realTimeIntegrityRequested,
|
173
|
-
:navigationModelRequested,
|
174
|
-
].include?(k)]
|
177
|
+
[k, req_data.include?(k)]
|
175
178
|
}.flatten(1))]
|
176
179
|
posinit[:requestedAssistData][:"ver2-RequestedAssistData-extension"] = {
|
177
180
|
:ganssRequestedCommonAssistanceDataList => {
|
@@ -185,18 +188,21 @@ class SUPL_Client
|
|
185
188
|
:ganssRequestedGenericAssistanceDataList => [
|
186
189
|
# SBAS
|
187
190
|
{:ganssId => 1, :ganssSBASid => [0, 1, 0], # MSAS
|
188
|
-
:ganssRealTimeIntegrity => true,
|
189
|
-
:ganssNavigationModelData => {:ganssWeek => 0, :ganssToe => 0, :"t-toeLimit" => 0},
|
191
|
+
:ganssRealTimeIntegrity => true,
|
190
192
|
:ganssReferenceMeasurementInfo => false, :ganssUTCModel => true, :ganssAuxiliaryInformation => false},
|
191
193
|
# QZSS
|
192
|
-
{:ganssId => 3, :ganssRealTimeIntegrity => true,
|
193
|
-
:ganssNavigationModelData => {:ganssWeek => 0, :ganssToe => 0, :"t-toeLimit" => 0},
|
194
|
+
{:ganssId => 3, :ganssRealTimeIntegrity => true,
|
194
195
|
:ganssReferenceMeasurementInfo => false, :ganssUTCModel => true, :ganssAuxiliaryInformation => false},
|
195
196
|
# GLONASS
|
196
|
-
{:ganssId => 4, :ganssRealTimeIntegrity => true,
|
197
|
-
:ganssNavigationModelData => {:ganssWeek => 0, :ganssToe => 0, :"t-toeLimit" => 0},
|
197
|
+
{:ganssId => 4, :ganssRealTimeIntegrity => true,
|
198
198
|
:ganssReferenceMeasurementInfo => false, :ganssUTCModel => true, :ganssAuxiliaryInformation => false},
|
199
|
-
]
|
199
|
+
].collect{|items|
|
200
|
+
items[:ganssAlmanac] = @opts[:req_data].include?(:almanac)
|
201
|
+
items[:ganssNavigationModelData] = {
|
202
|
+
:ganssWeek => 0, :ganssToe => 0, :"t-toeLimit" => 0
|
203
|
+
} if @opts[:req_data].include?(:ephemeris)
|
204
|
+
items
|
205
|
+
},
|
200
206
|
}
|
201
207
|
posinit[:requestedAssistData][:navigationModelData] = {
|
202
208
|
:gpsWeek => 0,
|
@@ -302,7 +308,25 @@ class SUPL_Client
|
|
302
308
|
:ephemL2Pflag
|
303
309
|
:ephemAODA
|
304
310
|
=end
|
305
|
-
|
311
|
+
|
312
|
+
ALM_KEY_TBL_RRLP = Hash[*({
|
313
|
+
:e => [:almanacE, -21],
|
314
|
+
:i0 => [:almanacKsii, -19, true],
|
315
|
+
:dot_Omega0 => [:almanacOmegaDot, -38, true],
|
316
|
+
:SV_health => :almanacSVhealth,
|
317
|
+
:sqrt_A => [:almanacAPowerHalf, -11],
|
318
|
+
:Omega0 => [:almanacOmega0, -23, true],
|
319
|
+
:omega => [:almanacW, -23, true],
|
320
|
+
:M0 => [:almanacM0, -23, true],
|
321
|
+
:a_f0 => [:almanacAF0, -20],
|
322
|
+
:a_f1 => [:almanacAF1, -38],
|
323
|
+
}.collect{|dst_k, (src_k, sf_pow2, sc2rad)|
|
324
|
+
sf_pow2 ||= 0
|
325
|
+
sf = sf_pow2 < 0 ? Rational(1, 1 << -sf_pow2) : (1 << sf_pow2)
|
326
|
+
sf = sf.to_f * GPS::GPS_SC2RAD if sc2rad
|
327
|
+
["#{dst_k}=".to_sym, [src_k, sf]]
|
328
|
+
}.flatten(1))]
|
329
|
+
|
306
330
|
def attach_rrlp(msg)
|
307
331
|
t_gps = proc{
|
308
332
|
week_rem, sec008 = [:gpsWeek, :gpsTOW23b].collect{|k| msg[:referenceTime][:gpsTime][k]}
|
@@ -337,10 +361,11 @@ class SUPL_Client
|
|
337
361
|
params
|
338
362
|
}
|
339
363
|
msg.define_singleton_method(:ephemeris){
|
340
|
-
self[:navigationModel]
|
364
|
+
next [] unless (model = self[:navigationModel])
|
365
|
+
model[:navModelList].collect{|sat|
|
341
366
|
eph = GPS::Ephemeris::new
|
342
|
-
eph.svid =
|
343
|
-
eph_src =
|
367
|
+
eph.svid = sat[:satelliteID] + 1
|
368
|
+
eph_src = sat[:satStatus][:newSatelliteAndModelUC]
|
344
369
|
EPH_KEY_TBL_RRLP.each{|dst_k, (src_k, sf)|
|
345
370
|
v = sf * eph_src[src_k]
|
346
371
|
eph.send(dst_k, v.kind_of?(Rational) ? v.to_f : v)
|
@@ -357,6 +382,30 @@ class SUPL_Client
|
|
357
382
|
eph
|
358
383
|
}
|
359
384
|
}
|
385
|
+
msg.define_singleton_method(:almanac){
|
386
|
+
next [] unless (model = self[:almanac])
|
387
|
+
week = self[:almanac][:alamanacWNa]
|
388
|
+
week += (t_gps.week >> 8) << 8
|
389
|
+
model[:almanacList].collect{|sat|
|
390
|
+
eph = GPS::Ephemeris::new
|
391
|
+
eph.svid = sat[:satelliteID] + 1
|
392
|
+
ALM_KEY_TBL_RRLP.each{|dst_k, (src_k, sf)|
|
393
|
+
v = sf * sat[src_k]
|
394
|
+
eph.send(dst_k, v.kind_of?(Rational) ? v.to_f : v)
|
395
|
+
}
|
396
|
+
eph.i0 = GPS::GPS_SC2RAD * 0.3 + eph.i0
|
397
|
+
eph.WN = week
|
398
|
+
eph.t_oc = eph.t_oe = sat[:alamanacToa] << 12
|
399
|
+
[:iodc, :t_GD, :a_f2, :iode, :c_rs, :delta_n,
|
400
|
+
:c_uc, :c_us, :c_ic, :c_is, :c_rc, :dot_i0, :iode_subframe3].each{|k|
|
401
|
+
eph.send("#{k}=", 0)
|
402
|
+
}
|
403
|
+
eph.URA_index = -1
|
404
|
+
#eph.fit_interval
|
405
|
+
eph
|
406
|
+
}
|
407
|
+
}
|
408
|
+
:alamanacToa # typo in TS
|
360
409
|
msg
|
361
410
|
end
|
362
411
|
|
@@ -412,6 +461,25 @@ class SUPL_Client
|
|
412
461
|
:N_T=, :p=, :delta_tau_n=, :P4=,
|
413
462
|
:tau_GPS=, :tau_c=, :day_of_year=, :year=, :n=, :freq_ch=
|
414
463
|
=end
|
464
|
+
|
465
|
+
ALM_KEY_TBL_LPP = Hash[*({
|
466
|
+
:e => [:E, -21],
|
467
|
+
:i0 => [:DeltaI, -19, true],
|
468
|
+
:dot_Omega0 => [:OMEGADOT, -38, true],
|
469
|
+
:SV_health => :SVHealth,
|
470
|
+
:sqrt_A => [:SqrtA, -11],
|
471
|
+
:Omega0 => [:OMEGAo, -23, true],
|
472
|
+
:omega => [:Omega, -23, true],
|
473
|
+
:M0 => [:Mo, -23, true],
|
474
|
+
:a_f0 => [:af0, -20],
|
475
|
+
:a_f1 => [:af1, -38],
|
476
|
+
}.collect{|dst_k, (src_k, sf_pow2, sc2rad)|
|
477
|
+
sf_pow2 ||= 0
|
478
|
+
sf = sf_pow2 < 0 ? Rational(1, 1 << -sf_pow2) : (1 << sf_pow2)
|
479
|
+
sf = sf.to_f * GPS::GPS_SC2RAD if sc2rad
|
480
|
+
["#{dst_k}=".to_sym,
|
481
|
+
[(src_k.kind_of?(Symbol) ? "navAlm#{src_k}" : src_k).to_sym, sf]]
|
482
|
+
}.flatten(1))]
|
415
483
|
|
416
484
|
def attach_lpp(msg)
|
417
485
|
t_gps = proc{|data|
|
@@ -460,9 +528,9 @@ class SUPL_Client
|
|
460
528
|
}.call
|
461
529
|
leap_seconds = iono_utc.delta_t_LS rescue t_gps.leap_seconds
|
462
530
|
msg.define_singleton_method(:iono_utc){iono_utc}
|
463
|
-
extract_gps_ephemeris = proc{|
|
531
|
+
extract_gps_ephemeris = proc{|model, sys|
|
464
532
|
offset = {:gps => 1, :qzss => 193}[sys]
|
465
|
-
|
533
|
+
model[:"gnss-SatelliteList"].collect{|v|
|
466
534
|
eph = GPS::Ephemeris::new
|
467
535
|
eph.svid = v[:svID][:"satellite-id"] + offset
|
468
536
|
eph_src = v[:"gnss-ClockModel"][:"nav-ClockModel"].merge(v[:"gnss-OrbitModel"][:"nav-KeplerianSet"])
|
@@ -489,42 +557,81 @@ class SUPL_Client
|
|
489
557
|
[:"provideAssistanceData-r9"][:"a-gnss-ProvideAssistanceData"] \
|
490
558
|
[:"gnss-GenericAssistData"]
|
491
559
|
res = [:gps, :qzss].collect{|k|
|
492
|
-
|
493
|
-
|
494
|
-
|
560
|
+
model = assist_data.find{|v| v[:"gnss-ID"][:"gnss-id"] == k}[:"gnss-NavigationModel"] rescue nil
|
561
|
+
next [] unless model
|
562
|
+
extract_gps_ephemeris.call(model, k)
|
495
563
|
}.flatten(1)
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
eph = GPS::Ephemeris_GLONASS::new
|
504
|
-
eph.svid = sat[:svID][:"satellite-id"] + 1
|
505
|
-
eph_src = sat[:"gnss-ClockModel"][:"glonass-ClockModel"].merge(
|
506
|
-
sat[:"gnss-OrbitModel"][:"glonass-ECEF"])
|
507
|
-
(EPH_KEY_TBL_LPP_GLO.collect{|dst_k, (src_k, sf)|
|
508
|
-
v = eph_src[src_k]
|
509
|
-
[dst_k, sf.send(sf.kind_of?(Proc) ? :call : :*, case v
|
510
|
-
when Array; Integer(v.join, 2)
|
511
|
-
when true; 1
|
512
|
-
when false; 0
|
513
|
-
else; v
|
514
|
-
end)]
|
515
|
-
} + utc_params_glo).each{|dst_k, v|
|
516
|
-
eph.send(dst_k, v.kind_of?(Rational) ? v.to_f : v)
|
564
|
+
proc{|assist_data_glo|
|
565
|
+
next unless assist_data_glo
|
566
|
+
next unless nav_model = assist_data_glo[:"gnss-NavigationModel"]
|
567
|
+
utc_params_glo = {
|
568
|
+
:tau_c= => [:tauC, Rational(1, 1 << 31)],
|
569
|
+
}.collect{|dst_k, (src_k, sf)|
|
570
|
+
[dst_k, sf * assist_data_glo[:"gnss-UTC-Model"][:utcModel3][src_k]]
|
517
571
|
}
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
572
|
+
res += nav_model[:"gnss-SatelliteList"].collect{|sat|
|
573
|
+
eph = GPS::Ephemeris_GLONASS::new
|
574
|
+
eph.svid = sat[:svID][:"satellite-id"] + 1
|
575
|
+
eph_src = sat[:"gnss-ClockModel"][:"glonass-ClockModel"].merge(
|
576
|
+
sat[:"gnss-OrbitModel"][:"glonass-ECEF"])
|
577
|
+
(EPH_KEY_TBL_LPP_GLO.collect{|dst_k, (src_k, sf)|
|
578
|
+
v = eph_src[src_k]
|
579
|
+
[dst_k, sf.send(sf.kind_of?(Proc) ? :call : :*, case v
|
580
|
+
when Array; Integer(v.join, 2)
|
581
|
+
when true; 1
|
582
|
+
when false; 0
|
583
|
+
else; v
|
584
|
+
end)]
|
585
|
+
} + utc_params_glo).each{|dst_k, v|
|
586
|
+
eph.send(dst_k, v.kind_of?(Rational) ? v.to_f : v)
|
587
|
+
}
|
588
|
+
eph.B_n = sat[:svHealth][0]
|
589
|
+
eph.F_T_index = Integer(sat[:svHealth][1..4].join, 2)
|
590
|
+
eph.t_b = Integer(sat[:iod][4..-1].join, 2) * 15 * 60
|
591
|
+
eph.set_date((t_gps + 3 * 60 * 60).c_tm(leap_seconds)) # UTC -> Moscow time
|
592
|
+
eph.N_T = eph.NA
|
593
|
+
eph.rehash(leap_seconds)
|
594
|
+
eph
|
595
|
+
}
|
596
|
+
}.call(assist_data.find{|v| v[:"gnss-ID"][:"gnss-id"] == :glonass})
|
526
597
|
res
|
527
598
|
}
|
599
|
+
extract_gps_almanac = proc{|alm, sys|
|
600
|
+
next [] unless alm
|
601
|
+
offset = {:gps => 1, :qzss => 193}[sys]
|
602
|
+
week = alm[:weekNumber] # optional but required for non-GLONASS
|
603
|
+
week += (t_gps.week >> 8) << 8
|
604
|
+
t_oa = alm[:toa] << 12 # optional but required for non-GLONASS
|
605
|
+
alm[:"gnss-AlmanacList"].collect{|v|
|
606
|
+
next unless v = v[:"keplerianNAV-Almanac"]
|
607
|
+
eph = GPS::Ephemeris::new
|
608
|
+
eph.svid = v[:svID][:"satellite-id"] + offset
|
609
|
+
ALM_KEY_TBL_LPP.each{|dst_k, (src_k, sf)|
|
610
|
+
v2 = sf * v[src_k]
|
611
|
+
eph.send(dst_k, v2.kind_of?(Rational) ? v2.to_f : v2)
|
612
|
+
}
|
613
|
+
eph.i0 = GPS::GPS_SC2RAD * 0.3 + eph.i0
|
614
|
+
eph.WN = week
|
615
|
+
eph.t_oc = eph.t_oe = t_oa
|
616
|
+
[:iodc, :t_GD, :a_f2, :iode, :c_rs, :delta_n,
|
617
|
+
:c_uc, :c_us, :c_ic, :c_is, :c_rc, :dot_i0, :iode_subframe3].each{|k|
|
618
|
+
eph.send("#{k}=", 0)
|
619
|
+
}
|
620
|
+
eph.URA_index = -1
|
621
|
+
#eph.fit_interval
|
622
|
+
eph
|
623
|
+
}.compact
|
624
|
+
}
|
625
|
+
msg.define_singleton_method(:almanac){
|
626
|
+
assist_data = self[:c1][:provideAssistanceData][:criticalExtensions][:c1] \
|
627
|
+
[:"provideAssistanceData-r9"][:"a-gnss-ProvideAssistanceData"] \
|
628
|
+
[:"gnss-GenericAssistData"]
|
629
|
+
[:gps, :qzss].collect{|k|
|
630
|
+
model = assist_data.find{|v| v[:"gnss-ID"][:"gnss-id"] == k}[:"gnss-Almanac"] rescue nil
|
631
|
+
next [] unless model
|
632
|
+
extract_gps_almanac.call(model, k)
|
633
|
+
}.flatten(1)
|
634
|
+
}
|
528
635
|
msg
|
529
636
|
end
|
530
637
|
end
|
@@ -537,7 +644,7 @@ OpenURI.class_eval{
|
|
537
644
|
options[:port] = target.port
|
538
645
|
URI.decode_www_form(target.query || "").each{|k, v|
|
539
646
|
case k = k.to_sym
|
540
|
-
when :protocol
|
647
|
+
when :protocol, :req_data
|
541
648
|
(options[k] ||= []) << v.to_sym
|
542
649
|
end
|
543
650
|
}
|