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.
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
  }