Parse a single NMEA sentence.
(self, line)
| 626 | pass |
| 627 | if self.fix_quality <= 0: |
| 628 | self.fix_quality = 1 |
| 629 | self.last_update = now |
| 630 | self._record_position(now) |
| 631 | self.last_sentence = now |
| 632 | self.connected = True |
| 633 | self.error = None |
| 634 | self._external_source = source |
| 635 | return True |
| 636 | |
| 637 | def _read_loop_gpsd(self): |
| 638 | """Background thread: read JSON objects from gpsd and parse position.""" |
| 639 | buf = '' |
| 640 | while self._running: |
| 641 | try: |
| 642 | if not self._gpsd_sock: |
| 643 | self._reconnect_gpsd() |
| 644 | continue |
| 645 | chunk = self._gpsd_sock.recv(4096).decode('utf-8', errors='ignore') |
| 646 | if not chunk: |
| 647 | raise ConnectionError("gpsd closed connection") |
| 648 | buf += chunk |
| 649 | while '\n' in buf: |
| 650 | line, buf = buf.split('\n', 1) |
| 651 | line = line.strip() |
| 652 | if not line: |
| 653 | continue |
| 654 | try: |
| 655 | obj = json.loads(line) |
| 656 | except json.JSONDecodeError: |
| 657 | continue |
| 658 | cls = obj.get('class') |
| 659 | if cls == 'TPV': |
| 660 | self._parse_tpv(obj) |
| 661 | elif cls == 'SKY': |
| 662 | self._parse_sky(obj) |
| 663 | except Exception as e: |
| 664 | if self._running: |
| 665 | logger.debug(f"gpsd read error: {e}") |
| 666 | if self._gpsd_sock: |
| 667 | try: |
| 668 | self._gpsd_sock.close() |
| 669 | except Exception: |
| 670 | pass |
| 671 | self._gpsd_sock = None |
| 672 | with self._lock: |
| 673 | self.connected = False |
| 674 | self._reconnect_gpsd() |
| 675 | |
| 676 | def _reconnect_gpsd(self): |
| 677 | """Attempt to reconnect to gpsd.""" |
| 678 | time.sleep(3) |
| 679 | if not self._running: |
| 680 | return |
| 681 | sock = _try_gpsd() |
| 682 | if sock: |
| 683 | self._gpsd_sock = sock |
| 684 | with self._lock: |
| 685 | self.connected = True |
no test coverage detected