gps_pvt 0.10.1 → 0.10.3

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.
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, :ganssAlmanac => false,
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, :ganssAlmanac => false,
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, :ganssAlmanac => false,
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][:navModelList].collect{|v|
364
+ next [] unless (model = self[:navigationModel])
365
+ model[:navModelList].collect{|sat|
341
366
  eph = GPS::Ephemeris::new
342
- eph.svid = v[:satelliteID] + 1
343
- eph_src = v[:satStatus][:newSatelliteAndModelUC]
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{|sat_list, sys|
531
+ extract_gps_ephemeris = proc{|model, sys|
464
532
  offset = {:gps => 1, :qzss => 193}[sys]
465
- sat_list.collect{|v|
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
- extract_gps_ephemeris.call(
493
- assist_data.select{|v| v[:"gnss-ID"][:"gnss-id"] == k}[0] \
494
- [:"gnss-NavigationModel"][:"gnss-SatelliteList"], k)
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
- assist_data_glo = assist_data.select{|v| v[:"gnss-ID"][:"gnss-id"] == :glonass}[0]
497
- utc_params_glo = {
498
- :tau_c= => [:tauC, Rational(1, 1 << 31)],
499
- }.collect{|dst_k, (src_k, sf)|
500
- [dst_k, sf * assist_data_glo[:"gnss-UTC-Model"][:utcModel3][src_k]]
501
- }
502
- res += assist_data_glo[:"gnss-NavigationModel"][:"gnss-SatelliteList"].collect{|sat|
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
- eph.B_n = sat[:svHealth][0]
519
- eph.F_T_index = Integer(sat[:svHealth][1..4].join, 2)
520
- eph.t_b = Integer(sat[:iod][4..-1].join, 2) * 15 * 60
521
- eph.set_date((t_gps + 3 * 60 * 60).c_tm(leap_seconds)) # UTC -> Moscow time
522
- eph.N_T = eph.NA
523
- eph.rehash(leap_seconds)
524
- eph
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
  }