diff --git a/src/pyubxutils/ubxbase.py b/src/pyubxutils/ubxbase.py index 54510b9..c895877 100644 --- a/src/pyubxutils/ubxbase.py +++ b/src/pyubxutils/ubxbase.py @@ -6,6 +6,10 @@ This command line utility configures an RTK-compatible u-blox GNSS receiver to operate in Base Station mode. +RTCM 1006 (Antenna Reference Data) is only output if the base +station is active, so receipt of this message type is used as +a configuration success criterion. + Created on 06 Jan 2023 :author: semuadmin @@ -21,6 +25,7 @@ from time import sleep from pyubx2 import ( + ERR_IGNORE, NMEA_PROTOCOL, RTCM3_PROTOCOL, UBX_PROTOCOL, @@ -63,6 +68,8 @@ def __init__(self, stream: object, **kwargs): self.logger = getLogger(__name__) self._stream = stream + self._port = kwargs["port"] + self._porttype = kwargs.get("porttype", "USB") self._timemode = int(kwargs.get("timemode", TMODE_DISABLED)) self._acclimit = int(kwargs.get("acclimit", DEFAULT_ACCURACY)) self._duration = int(kwargs.get("duration", DEFAULT_DURATION)) @@ -70,7 +77,9 @@ def __init__(self, stream: object, **kwargs): self._waittime = int(kwargs.get("waittime", WAITTIME)) self._fixedpos = kwargs.get("fixedpos", DEFAULT_POS) self._ubxreader = UBXReader( - self._stream, protfilter=NMEA_PROTOCOL | UBX_PROTOCOL | RTCM3_PROTOCOL + self._stream, + protfilter=NMEA_PROTOCOL | UBX_PROTOCOL | RTCM3_PROTOCOL, + quitonerror=ERR_IGNORE, ) self._out_queue = Queue() self._stop_event = Event() @@ -85,19 +94,20 @@ def __init__(self, stream: object, **kwargs): self._stop_event, ), ) + self._svin_elapsed = 0 self._msg_ack = 0 self._msg_nak = 0 self._msg_write = 0 - self._msg_load = 0 if self._timemode == TMODE_DISABLED else 1 + self._msg_load = 0 # if self._timemode == TMODE_DISABLED else 1 self._msg_rtcm = 0 - def _config_svin(self, queue: Queue, port_type: str = "USB") -> int: + def _config_svin(self, queue: Queue) -> int: """ Configure Survey-In mode with specified accuracy limit. """ print( - f"Survey-in duration {self._duration}s, accuracy limit {self._acclimit}cm ..." + f"Survey-in duration {self._duration}s, accuracy limit {self._acclimit}cm" ) self._waittime += self._duration layers = 1 @@ -107,7 +117,7 @@ def _config_svin(self, queue: Queue, port_type: str = "USB") -> int: ("CFG_TMODE_MODE", self._timemode), ("CFG_TMODE_SVIN_ACC_LIMIT", acclimit), ("CFG_TMODE_SVIN_MIN_DUR", self._duration), - (f"CFG_MSGOUT_UBX_NAV_SVIN_{port_type}", 1), + # (f"CFG_MSGOUT_UBX_NAV_SVIN_{port_type}", 1), ] ubx = UBXMessage.config_set(layers, transaction, cfg_data) queue.put(ubx) @@ -121,7 +131,7 @@ def _config_fixed(self, queue: Queue) -> int: print( f"Fixed position format {('ECEF','LLH')[self._postype]}, {self._fixedpos}, " - f"accuracy limit {self._acclimit}cm ..." + f"accuracy limit {self._acclimit}cm" ) layers = 1 transaction = 0 @@ -178,15 +188,21 @@ def _config_disabled(self, queue: Queue) -> int: self._msg_load += 1 return 1 - def config_rtcm(self, queue: Queue, rate: int = 1, port_type: str = "USB") -> int: + def _config_output( + self, queue: Queue, rate: int = 1, port_type: str = "USB" + ) -> int: """ - Configure which RTCM3 messages to output. + Configure which RTCM3 and UBX messages to output. """ - print(f"{('Disabling','Enabling')[rate]} RTCM output messages ...") + print(f"{('Disabling','Enabling')[rate]} output messages") layers = 1 # 1 = RAM, 2 = BBR, 4 = Flash (can be OR'd) transaction = 0 - cfg_data = [] + cfg_data = ( + [(f"CFG_MSGOUT_UBX_NAV_SVIN_{port_type}", 1)] + if self._timemode == TMODE_SVIN + else [] + ) for rtcm_type in ( "1006", "1077", @@ -212,7 +228,7 @@ def _read_data( ): """ THREADED - Read incoming acknowledgements from device + Read incoming UBX and RTCM data from device. """ # pylint: disable=broad-except @@ -243,6 +259,12 @@ def _read_data( self.logger.debug( f"RTCM 1006 ACTIVE BASE {self._msg_rtcm} - {parsed_data}" ) + if ( + self._timemode == TMODE_SVIN + and parsed_data.identity == "NAV-SVIN" + ): + self._svin_elapsed = parsed_data.dur + self.logger.debug(f"UBX NAV-SVIN - {parsed_data}") # send config message(s) to receiver if not queue.empty(): @@ -271,9 +293,13 @@ def run(self): """ rc = 0 - print( - f"Configuring {('Disabled', 'Survey-In', 'Fixed')[self._timemode]} timing mode ..." - ) + if self._timemode in (TMODE_FIXED, TMODE_SVIN): + print( + f"Configuring device at port {self._port} as base station using " + f"{('disabled', 'survey-in', 'fixed')[self._timemode]} timing mode" + ) + else: + print(f"Configuring device at port {self._port} to disable base station") start = datetime.now() self._read_thread.start() @@ -284,44 +310,56 @@ def run(self): else: rc = self._config_disabled(self._out_queue) if rc: - rc = self.config_rtcm(self._out_queue, self._timemode != TMODE_DISABLED) + rc = self._config_output( + self._out_queue, + rate=self._timemode != TMODE_DISABLED, + port_type=self._porttype, + ) - # loop until waittime expired or user presses Ctrl-C + # loop until waittime / survey duration expired or user presses Ctrl-C i = 0 while datetime.now() < start + timedelta(seconds=self._waittime): try: - progbar(i, self._waittime, min(self._waittime, 60)) - i += 1 + if self._timemode == TMODE_SVIN: + i = self._svin_elapsed # from NAV-SVIN message + wt = self._duration + else: + i += 1 + wt = self._waittime + progbar(i, wt, wt) sleep(1) except KeyboardInterrupt: # capture Ctrl-C - print("Terminated by user. Configuration may be incomplete.") + print("\nTerminated by user. Configuration may be incomplete.") break self._stop_event.set() self._read_thread.join() - if self._msg_ack + self._msg_rtcm >= self._msg_load: + if self._msg_ack == self._msg_load and ( + (self._timemode in (TMODE_FIXED, TMODE_SVIN) and self._msg_rtcm > 1) + or (self._timemode == TMODE_DISABLED and self._msg_rtcm == 0) + ): print( - "Configuration successfully loaded. " + "Configuration successful. " f"{self._msg_ack} configuration messages acknowledged. " - f"{self._msg_rtcm} RTCM 1006 (active base) message confirmed." + f"{self._msg_rtcm} RTCM 1006 (active base) messages confirmed." ) + rc = 1 else: - null = self._msg_load - self._msg_ack - self._msg_nak - self._msg_rtcm - rc = 0 print( - "\nConfiguration may be incomplete. " + "\nConfiguration unsuccessful. " f"{self._msg_load} configuration messages sent, " f"{self._msg_ack} acknowledged, {self._msg_nak} rejected, " - f"{self._msg_rtcm} RTCM 1006 (active base), {null} null responses." + f"{self._msg_rtcm} RTCM 1006 (active base) messages received." ) - if null: + if not self._msg_rtcm: print( - f"Consider reducing accuracy limit to >{self._acclimit} cm" - f"or increasing waittime to >{self._waittime} seconds." + f"Consider increasing accuracy limit to >{self._acclimit}cm " + f"or increasing survey duration to >{self._duration} seconds." ) if self._msg_nak: - print("Check device is compatible.") + print("Check device supports base station configuration.") + rc = 0 return rc @@ -369,6 +407,14 @@ def fixedpos_in_range(value): type=float, default=3.0, ) + ap.add_argument( + "--portype", + required=False, + help="Serial port type", + type=str, + choices=("USB", "UART1", "UART2", "I2C"), + default="USB", + ) ap.add_argument( "--timemode", required=False, @@ -421,7 +467,7 @@ def fixedpos_in_range(value): kwargs = set_common_args("ubxload", ap, logdefault=VERBOSITY_HIGH) with Serial( - kwargs.pop("port"), kwargs.pop("baudrate"), timeout=kwargs.pop("timeout") + kwargs.get("port"), kwargs.pop("baudrate"), timeout=kwargs.pop("timeout") ) as serial_stream: ubl = UBXBase(serial_stream, **kwargs) ubl.run() diff --git a/src/pyubxutils/ubxcompare.py b/src/pyubxutils/ubxcompare.py index 6262f1c..14f6b72 100644 --- a/src/pyubxutils/ubxcompare.py +++ b/src/pyubxutils/ubxcompare.py @@ -75,7 +75,7 @@ def __init__(self, infiles: str, form: int = FORMAT_TXT, diffsonly: bool = True) fcount += 1 self.parse_file(cfgdict, file.strip(), fcount, form) - self.logger.info( + print( f"{fcount} files processed, list of {'differences in' if diffsonly else 'all'}" " config keys and their values follows: ", ) @@ -90,7 +90,7 @@ def __init__(self, infiles: str, form: int = FORMAT_TXT, diffsonly: bool = True) if (diffsonly and diff) or not diffsonly: print(f"{key} ({'DIFFS!' if diff else None}); {str(vals).strip('{}')}") - self.logger.info(f"Total config keys: {kcount}. Total differences: {dcount}.") + print(f"Total config keys: {kcount}. Total differences: {dcount}.") def parse_line(self, line: str) -> UBXMessage: """ @@ -177,9 +177,9 @@ def parse_file(self, cfgdict: dict, filename: str, fileno: int, form: int): self.get_attrs(cfgdict, str(parsed), fileno) i += 1 except Exception as err: - self.logger.error(f"ERROR parsing {filename}! \n{err}") + print(f"ERROR parsing {filename}! \n{err}") - self.logger.info(f"\n{i} configuration commands processed in {filename}") + print(f"\n{i} configuration commands processed in {filename}") def main(): diff --git a/src/pyubxutils/ubxload.py b/src/pyubxutils/ubxload.py index f79461a..d453e70 100644 --- a/src/pyubxutils/ubxload.py +++ b/src/pyubxutils/ubxload.py @@ -169,7 +169,7 @@ def run(self): """ rc = 1 - self.logger.info( + print( f"Loading configuration from {self._filename} to {self._stream.port}. " "Press Ctrl-C to terminate early.", ) @@ -182,35 +182,29 @@ def run(self): try: sleep(1) except KeyboardInterrupt: # capture Ctrl-C - self.logger.warning( - "Terminated by user. Configuration may be incomplete." - ) + print("Terminated by user. Configuration may be incomplete.") self._stop_event.set() self._read_thread.join() if self._msg_ack == self._msg_load: - self.logger.info( + print( "Configuration successfully loaded. " f"{self._msg_load} CFG-VALSET messages sent and acknowledged." ) else: null = self._msg_load - self._msg_ack - self._msg_nak rc = 0 - self.logger.warning( + print( "Configuration may be incomplete. " f"{self._msg_load} CFG-VALSET messages sent, " f"{self._msg_ack} acknowledged, {self._msg_nak} rejected, " f"{null} null responses." ) if null: - self.logger.warning( - f"Consider increasing waittime to >{self._waittime} seconds." - ) + print(f"Consider increasing waittime to >{self._waittime} seconds.") if self._msg_nak: - self.logger.warning( - "Check device is compatible with this saved configuration." - ) + print("Check device is compatible with this saved configuration.") return rc diff --git a/src/pyubxutils/ubxsave.py b/src/pyubxutils/ubxsave.py index 191f156..a001663 100644 --- a/src/pyubxutils/ubxsave.py +++ b/src/pyubxutils/ubxsave.py @@ -203,7 +203,7 @@ def run(self): """ rc = 1 - self.logger.info( + print( f"Saving configuration from {self._stream.port} to {self._file.name}. " "Press Ctrl-C to terminate early." ) @@ -242,16 +242,16 @@ def run(self): except KeyboardInterrupt: # capture Ctrl-C self._stop_event.set() - self.logger.warning("Terminated by user. Configuration may be incomplete.") + print("Terminated by user. Configuration may be incomplete.") if self._msg_rcvd == self._cfgkeys: - self.logger.info( + print( "Configuration successfully saved. " f"{self._msg_save} CFG-VALSET messages saved to {self._file.name}" ) else: rc = 0 - self.logger.warning( + print( "Configuration may not be successfully saved. " f"{self._msg_sent} CFG-VALGET polls sent to {self._stream.port}, " f"{self._msg_rcvd} CFG-VALGET responses received, " diff --git a/src/pyubxutils/ubxsetrate.py b/src/pyubxutils/ubxsetrate.py index be98e9b..03f5eef 100644 --- a/src/pyubxutils/ubxsetrate.py +++ b/src/pyubxutils/ubxsetrate.py @@ -110,9 +110,7 @@ def apply(self): """ try: - self.logger.info( - f"Opening serial port {self._port} @ {self._baudrate} baud ..." - ) + print(f"Opening serial port {self._port} @ {self._baudrate} baud ...") self._serialOut = Serial(self._port, self._baudrate, timeout=self._timeout) if self._msgClass == ALLNMEA: # all available NMEA messages @@ -142,7 +140,7 @@ def apply(self): raise err from err finally: if self._serialOut is not None: - self.logger.info("Configuration message(s) sent.") + print("Configuration message(s) sent.") self._serialOut.close() def _sendmsg(self, msgClass: int, msgID: int): @@ -166,7 +164,7 @@ def _sendmsg(self, msgClass: int, msgID: int): rateSPI=self._rate, ) - self.logger.info(f"Sending configuration message {msg}...") + print(f"Sending configuration message {msg}...") self._serialOut.write(msg.serialize())