|  |  |  | @ -16,7 +16,7 @@ from common.params import Params, put_nonblocking | 
			
		
	
		
			
				
					|  |  |  |  | from laika import AstroDog | 
			
		
	
		
			
				
					|  |  |  |  | from laika.constants import SECS_IN_HR, SECS_IN_MIN | 
			
		
	
		
			
				
					|  |  |  |  | from laika.downloader import DownloadFailed | 
			
		
	
		
			
				
					|  |  |  |  | from laika.ephemeris import Ephemeris, EphemerisType, convert_ublox_ephem | 
			
		
	
		
			
				
					|  |  |  |  | from laika.ephemeris import Ephemeris, EphemerisType, convert_ublox_ephem, parse_qcom_ephem | 
			
		
	
		
			
				
					|  |  |  |  | from laika.gps_time import GPSTime | 
			
		
	
		
			
				
					|  |  |  |  | from laika.helpers import ConstellationId | 
			
		
	
		
			
				
					|  |  |  |  | from laika.raw_gnss import GNSSMeasurement, correct_measurements, process_measurements, read_raw_ublox, read_raw_qcom | 
			
		
	
	
		
			
				
					|  |  |  | @ -61,6 +61,7 @@ class Laikad: | 
			
		
	
		
			
				
					|  |  |  |  |     self.last_pos_fix = [] | 
			
		
	
		
			
				
					|  |  |  |  |     self.last_pos_residual = [] | 
			
		
	
		
			
				
					|  |  |  |  |     self.last_pos_fix_t = None | 
			
		
	
		
			
				
					|  |  |  |  |     self.gps_week = None | 
			
		
	
		
			
				
					|  |  |  |  |     self.use_qcom = use_qcom | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   def load_cache(self): | 
			
		
	
	
		
			
				
					|  |  |  | @ -107,11 +108,11 @@ class Laikad: | 
			
		
	
		
			
				
					|  |  |  |  |     return self.last_pos_fix | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   def is_good_report(self, gnss_msg): | 
			
		
	
		
			
				
					|  |  |  |  |     if gnss_msg.which == 'drMeasurementReport' and self.use_qcom: | 
			
		
	
		
			
				
					|  |  |  |  |     if gnss_msg.which() == 'drMeasurementReport' and self.use_qcom: | 
			
		
	
		
			
				
					|  |  |  |  |       constellation_id = ConstellationId.from_qcom_source(gnss_msg.drMeasurementReport.source) | 
			
		
	
		
			
				
					|  |  |  |  |       # TODO support GLONASS | 
			
		
	
		
			
				
					|  |  |  |  |       return constellation_id in [ConstellationId.GPS, ConstellationId.SBAS] | 
			
		
	
		
			
				
					|  |  |  |  |     elif gnss_msg.which == 'measurementReport' and not self.use_qcom: | 
			
		
	
		
			
				
					|  |  |  |  |     elif gnss_msg.which() == 'measurementReport' and not self.use_qcom: | 
			
		
	
		
			
				
					|  |  |  |  |       return True | 
			
		
	
		
			
				
					|  |  |  |  |     else: | 
			
		
	
		
			
				
					|  |  |  |  |       return False | 
			
		
	
	
		
			
				
					|  |  |  | @ -129,9 +130,28 @@ class Laikad: | 
			
		
	
		
			
				
					|  |  |  |  |       new_meas = read_raw_ublox(report) | 
			
		
	
		
			
				
					|  |  |  |  |     return week, tow, new_meas | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   def is_ephemeris(self, gnss_msg): | 
			
		
	
		
			
				
					|  |  |  |  |     if self.use_qcom: | 
			
		
	
		
			
				
					|  |  |  |  |       return gnss_msg.which() == 'drSvPoly' | 
			
		
	
		
			
				
					|  |  |  |  |     else: | 
			
		
	
		
			
				
					|  |  |  |  |       return gnss_msg.which() == 'ephemeris' | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   def read_ephemeris(self, gnss_msg): | 
			
		
	
		
			
				
					|  |  |  |  |     # TODO this only works on GLONASS | 
			
		
	
		
			
				
					|  |  |  |  |     if self.use_qcom: | 
			
		
	
		
			
				
					|  |  |  |  |       # TODO this is not robust to gps week rollover | 
			
		
	
		
			
				
					|  |  |  |  |       if self.gps_week is None: | 
			
		
	
		
			
				
					|  |  |  |  |         return | 
			
		
	
		
			
				
					|  |  |  |  |       ephem = parse_qcom_ephem(gnss_msg.drSvPoly, self.gps_week) | 
			
		
	
		
			
				
					|  |  |  |  |     else: | 
			
		
	
		
			
				
					|  |  |  |  |       ephem = convert_ublox_ephem(gnss_msg.ephemeris) | 
			
		
	
		
			
				
					|  |  |  |  |     self.astro_dog.add_navs({ephem.prn: [ephem]}) | 
			
		
	
		
			
				
					|  |  |  |  |     self.cache_ephemeris(t=ephem.epoch) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   def process_gnss_msg(self, gnss_msg, gnss_mono_time: int, block=False): | 
			
		
	
		
			
				
					|  |  |  |  |     if self.is_good_report(gnss_msg): | 
			
		
	
		
			
				
					|  |  |  |  |       week, tow, new_meas = self.read_report(gnss_msg) | 
			
		
	
		
			
				
					|  |  |  |  |       self.gps_week = week | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       t = gnss_mono_time * 1e-9 | 
			
		
	
		
			
				
					|  |  |  |  |       if week > 0: | 
			
		
	
	
		
			
				
					|  |  |  | @ -172,12 +192,10 @@ class Laikad: | 
			
		
	
		
			
				
					|  |  |  |  |         "correctedMeasurements": meas_msgs | 
			
		
	
		
			
				
					|  |  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |  |       return dat | 
			
		
	
		
			
				
					|  |  |  |  |     # TODO this only works on GLONASS, qcom needs live ephemeris parsing too | 
			
		
	
		
			
				
					|  |  |  |  |     elif gnss_msg.which == 'ephemeris': | 
			
		
	
		
			
				
					|  |  |  |  |       ephem = convert_ublox_ephem(gnss_msg.ephemeris) | 
			
		
	
		
			
				
					|  |  |  |  |       self.astro_dog.add_navs({ephem.prn: [ephem]}) | 
			
		
	
		
			
				
					|  |  |  |  |       self.cache_ephemeris(t=ephem.epoch) | 
			
		
	
		
			
				
					|  |  |  |  |     #elif gnss_msg.which == 'ionoData': | 
			
		
	
		
			
				
					|  |  |  |  |     elif self.is_ephemeris(gnss_msg): | 
			
		
	
		
			
				
					|  |  |  |  |       self.read_ephemeris(gnss_msg) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     #elif gnss_msg.which() == 'ionoData': | 
			
		
	
		
			
				
					|  |  |  |  |     # todo add this. Needed to better correct messages offline. First fix ublox_msg.cc to sent them. | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   def update_localizer(self, est_pos, t: float, measurements: List[GNSSMeasurement]): | 
			
		
	
	
		
			
				
					|  |  |  | @ -265,9 +283,11 @@ def create_measurement_msg(meas: GNSSMeasurement): | 
			
		
	
		
			
				
					|  |  |  |  |   c.satVel = meas.sat_vel.tolist() | 
			
		
	
		
			
				
					|  |  |  |  |   ephem = meas.sat_ephemeris | 
			
		
	
		
			
				
					|  |  |  |  |   assert ephem is not None | 
			
		
	
		
			
				
					|  |  |  |  |   week, time_of_week = -1, -1 | 
			
		
	
		
			
				
					|  |  |  |  |   if ephem.eph_type == EphemerisType.NAV: | 
			
		
	
		
			
				
					|  |  |  |  |     source_type = EphemerisSourceType.nav | 
			
		
	
		
			
				
					|  |  |  |  |     week, time_of_week = -1, -1 | 
			
		
	
		
			
				
					|  |  |  |  |   elif ephem.eph_type == EphemerisType.QCOM_POLY: | 
			
		
	
		
			
				
					|  |  |  |  |     source_type = EphemerisSourceType.qcom | 
			
		
	
		
			
				
					|  |  |  |  |   else: | 
			
		
	
		
			
				
					|  |  |  |  |     assert ephem.file_epoch is not None | 
			
		
	
		
			
				
					|  |  |  |  |     week = ephem.file_epoch.week | 
			
		
	
	
		
			
				
					|  |  |  | @ -325,6 +345,7 @@ class EphemerisSourceType(IntEnum): | 
			
		
	
		
			
				
					|  |  |  |  |   nav = 0 | 
			
		
	
		
			
				
					|  |  |  |  |   nasaUltraRapid = 1 | 
			
		
	
		
			
				
					|  |  |  |  |   glonassIacUltraRapid = 2 | 
			
		
	
		
			
				
					|  |  |  |  |   qcom = 3 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | def main(sm=None, pm=None): | 
			
		
	
	
		
			
				
					|  |  |  | @ -348,6 +369,17 @@ def main(sm=None, pm=None): | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     if sm.updated[raw_gnss_socket]: | 
			
		
	
		
			
				
					|  |  |  |  |       gnss_msg = sm[raw_gnss_socket] | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       # TODO: Understand and use remaining unknown constellations | 
			
		
	
		
			
				
					|  |  |  |  |       if gnss_msg.which() == "drMeasurementReport": | 
			
		
	
		
			
				
					|  |  |  |  |         if getattr(gnss_msg, gnss_msg.which()).source not in ['glonass', 'gps', 'beidou', 'sbas']: | 
			
		
	
		
			
				
					|  |  |  |  |           continue | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         if getattr(gnss_msg, gnss_msg.which()).gpsWeek > np.iinfo(np.int16).max: | 
			
		
	
		
			
				
					|  |  |  |  |           # gpsWeek 65535 is received rarely from quectel, this cannot be | 
			
		
	
		
			
				
					|  |  |  |  |           # passed to GnssMeasurements's gpsWeek (Int16) | 
			
		
	
		
			
				
					|  |  |  |  |           continue | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       msg = laikad.process_gnss_msg(gnss_msg, sm.logMonoTime[raw_gnss_socket], block=replay) | 
			
		
	
		
			
				
					|  |  |  |  |       if msg is not None: | 
			
		
	
		
			
				
					|  |  |  |  |         pm.send('gnssMeasurements', msg) | 
			
		
	
	
		
			
				
					|  |  |  | 
 |