qzsl6tool 0.1.7__tar.gz

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.
Files changed (33) hide show
  1. qzsl6tool-0.1.7/PKG-INFO +133 -0
  2. qzsl6tool-0.1.7/license.txt +27 -0
  3. qzsl6tool-0.1.7/pyproject.toml +97 -0
  4. qzsl6tool-0.1.7/python/alstread.py +141 -0
  5. qzsl6tool-0.1.7/python/bdsb2read.py +527 -0
  6. qzsl6tool-0.1.7/python/ecef2llh.py +75 -0
  7. qzsl6tool-0.1.7/python/gale6read.py +526 -0
  8. qzsl6tool-0.1.7/python/galinavread.py +506 -0
  9. qzsl6tool-0.1.7/python/gps2utc.py +79 -0
  10. qzsl6tool-0.1.7/python/l6rtcm4050.py +85 -0
  11. qzsl6tool-0.1.7/python/libecef.py +75 -0
  12. qzsl6tool-0.1.7/python/libgnsstime.py +79 -0
  13. qzsl6tool-0.1.7/python/libnav.py +413 -0
  14. qzsl6tool-0.1.7/python/libqznma.py +94 -0
  15. qzsl6tool-0.1.7/python/libqzsl6tool.py +112 -0
  16. qzsl6tool-0.1.7/python/libssr.py +1202 -0
  17. qzsl6tool-0.1.7/python/libtrace.py +154 -0
  18. qzsl6tool-0.1.7/python/llh2ecef.py +75 -0
  19. qzsl6tool-0.1.7/python/novread.py +227 -0
  20. qzsl6tool-0.1.7/python/psdrread.py +147 -0
  21. qzsl6tool-0.1.7/python/qzsl1sread.py +410 -0
  22. qzsl6tool-0.1.7/python/qzsl6read.py +434 -0
  23. qzsl6tool-0.1.7/python/qzsl6tool.egg-info/PKG-INFO +133 -0
  24. qzsl6tool-0.1.7/python/qzsl6tool.egg-info/SOURCES.txt +31 -0
  25. qzsl6tool-0.1.7/python/qzsl6tool.egg-info/dependency_links.txt +1 -0
  26. qzsl6tool-0.1.7/python/qzsl6tool.egg-info/requires.txt +3 -0
  27. qzsl6tool-0.1.7/python/qzsl6tool.egg-info/top_level.txt +19 -0
  28. qzsl6tool-0.1.7/python/rtcmread.py +596 -0
  29. qzsl6tool-0.1.7/python/septread.py +209 -0
  30. qzsl6tool-0.1.7/python/ubxread.py +252 -0
  31. qzsl6tool-0.1.7/python/utc2gps.py +79 -0
  32. qzsl6tool-0.1.7/readme-en.md +98 -0
  33. qzsl6tool-0.1.7/setup.cfg +4 -0
@@ -0,0 +1,133 @@
1
+ Metadata-Version: 2.4
2
+ Name: qzsl6tool
3
+ Version: 0.1.7
4
+ Summary: Command-line tools for reading and converting GNSS messages, including QZSS L6, RTCM, Galileo HAS, and BeiDou PPP-B2b data.
5
+ Author-email: Satoshi Takahashi <git@s-taka.org>
6
+ License-Expression: BSD-2-Clause
7
+ Project-URL: Homepage, https://github.com/yoronneko/qzsl6tool
8
+ Project-URL: Repository, https://github.com/yoronneko/qzsl6tool
9
+ Project-URL: Documentation, https://github.com/yoronneko/qzsl6tool/tree/main/docs
10
+ Project-URL: Release Notes, https://github.com/yoronneko/qzsl6tool/blob/main/release_note.md
11
+ Project-URL: Bug Tracker, https://github.com/yoronneko/qzsl6tool/issues
12
+ Keywords: GNSS,QZSS,RTCM,CLAS,MADOCA,Galileo HAS,BeiDou
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Natural Language :: English
17
+ Classifier: Natural Language :: Japanese
18
+ Classifier: Operating System :: MacOS
19
+ Classifier: Operating System :: POSIX :: Linux
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.8
22
+ Classifier: Programming Language :: Python :: 3.9
23
+ Classifier: Programming Language :: Python :: 3.10
24
+ Classifier: Programming Language :: Python :: 3.11
25
+ Classifier: Programming Language :: Python :: 3.12
26
+ Classifier: Programming Language :: Python :: 3.13
27
+ Classifier: Topic :: Scientific/Engineering
28
+ Requires-Python: >=3.8
29
+ Description-Content-Type: text/markdown
30
+ License-File: license.txt
31
+ Requires-Dist: bitstring
32
+ Requires-Dist: galois
33
+ Requires-Dist: numpy
34
+ Dynamic: license-file
35
+
36
+ # QZS L6 Tool: quasi-zenith satellite L6-band tool, ver.0.1.7
37
+
38
+ ![QZS L6 Tool](docs/img/qzsl6tool.png)
39
+
40
+ [日本語](readme.md)
41
+
42
+ ## Summary
43
+
44
+ - This set of tools displays GNSS (Global Navigation Satellite System) messages and extracts specific formatted data from the raw data of GNSS receivers, for example, RTCM format and Michibiki L6 format.
45
+ - The suite consists of Python code that receives the messages via standard input, and the conversion results are sequentially outputted to the standard output. The use of standard error output is also possible as needed.
46
+ - It is designed to be used in conjunction with tools such as ``nc`` of netcat, and ``str2str`` of [RTKLIB](https://github.com/tomojitakasu/RTKLIB).
47
+ - Initially, it aimed to display the content of augmentation messages broadcasted by the quasi-zenith satellite Michibiki (QZS) in the L6 frequency band, including CLAS and MADO. However, it is now also capable of displaying Galileo HAS messages.
48
+ - [Semantic versioning](https://packaging.python.org/en/latest/discussions/versioning/#choosing-a-versioning-scheme) has been applied since 2024-08-11.
49
+ - [Release note](release_note.md)
50
+
51
+ ## Operating Environment
52
+
53
+ - It is intended for use on the command line of Linux or macOS.
54
+ - Python 3.8 or later is required. The ``bitstring`` module and the ``galois`` module are required.
55
+ ``pip3 install bitstring galois``
56
+ - With a Docker environment such as Docker Desktop, this tool can also be used on Windows, macOS, Linux, and Raspberry Pi OS inside a Linux container. The Docker image includes the Python runtime, ``nc``, and ``str2str`` from RTKLIB 2.4.3 b34.
57
+
58
+ Installing from PyPI
59
+
60
+ ```bash
61
+ python3 -m pip install qzsl6tool
62
+ ```
63
+
64
+ Building a Docker image
65
+
66
+ ```bash
67
+ docker build -t qzsl6tool .
68
+ ```
69
+
70
+ Executing a docker image
71
+
72
+ ```bash
73
+ docker run -it --rm qzsl6tool "cd /root/qzsl6tool/test; ./do_test.sh"
74
+ docker run -it --rm qzsl6tool "qzsl6read.py < /root/qzsl6tool/sample/2022001A.l6"
75
+ docker run -it --rm qzsl6tool "str2str -in ntrip://ntrip.rnav.info.hiroshima-cu.ac.jp:80/OEM7 2>/dev/null | rtcmread.py"
76
+ docker run -it --rm -v .:/mnt qzsl6tool "qzsl6read.py < my_l6_data.l6"
77
+ ```
78
+
79
+ When handling GNSS binary data on Windows, do not pass the binary stream through ``cmd.exe`` or PowerShell pipes. Keep input acquisition and the processing pipeline inside the container like above.
80
+
81
+ Those who use Windows Git CLI, please execute ``git config --global core.autocrlf input`` before cloning this repository. This is to avoid CR inclusion in line ends of a Python code.
82
+
83
+ ## Satellite Signal Display
84
+
85
+ | display | code |
86
+ |:----:|:-------:|
87
+ | RTCM |[rtcmread.py](docs/en/rtcmread.md) |
88
+ | QZSS L6 |[qzsl6read.py](docs/en/qzsl6read.md) |
89
+ | QZSS L1S | [qzsl1sread.py](docs/en/qzsl1sread.md) |
90
+ | Galileo I/NAV | [galinavread.py](docs/en/galinavread.md) |
91
+ | Galileo HAS |[gale6read.py](docs/en/gale6read.md) |
92
+ |BeiDou PPP-B2b | [bdsb2read.py](docs/en/bdsb2read.md)|
93
+
94
+ ## GNSS Receiver Data Conversion
95
+
96
+ | GNSS receiver | code | QZS L6 | QZS L1S | Galileo HAS | Galileo I/NAV | BeiDou B2b |
97
+ |:----:|:---:| :-------:|:-----------:|:--------:|:---:|:---:|
98
+ | Allystar HD9310 option C | [alstread.py](docs/en/alstread.md) |``-l`` option | | | | |
99
+ | [Pocket SDR](https://github.com/tomojitakasu/PocketSDR) | [psdrread.py](docs/en/psdrread.md) | ``-l`` option | ``-l1s`` option | ``-e`` option | ``-i`` option| ``-b`` option|
100
+ | NovAtel OEM729 | [novread.py](docs/en/novread.md) | | | ``-e`` option | | |
101
+ | Septentrio mosaic-X5 | [septread.py](docs/en/septread.md) | | | ``-e`` option | | ``-b`` option|
102
+ | Septentrio mosaic-CLAS | [septread.py](docs/en/septread.md) |``-l`` option | | | | |
103
+ | u-blox ZED-F9P | [ubxread.py](docs/en/ubxread.md) | | ``-l1s`` option | | ``-i`` option| |
104
+
105
+ ## Time & Coordinate Conversion
106
+
107
+ | conversion | code |
108
+ |:--:|:--:|
109
+ |GPS time, GST, BST &rarr; UTC time | [gps2utc.py](docs/en/gps2utc.md) |
110
+ |UTC time &rarr; GPS time, GST, BST | [utc2gps.py](docs/en/utc2gps.md)|
111
+ |LLH &rarr; ECEF | [llh2ecef.py](docs/en/llh2ecef.md)|
112
+ |ECEF &rarr; LLH | [ecef2llh.py](docs/en/ecef2llh.md)|
113
+
114
+ ## Directory Structure
115
+
116
+ ```text
117
+ ├── docs/ (documentation directory)
118
+ ├── license.txt (license description)
119
+ ├── python/ (code directory)
120
+ ├── readme-en.md (English document)
121
+ ├── readme.md (this file, Japanese document)
122
+ ├── sample/ (sample data directory)
123
+ └── test/ (directory to test the tools)
124
+ ```
125
+
126
+ ## License
127
+
128
+ This project is licensed under the [BSD 2-clause license](https://opensource.org/licenses/BSD-2-Clause).
129
+
130
+ Users are permitted to use this program for commercial and non-commercial purposes, with or without modification, but this copyright notice is required. The function rtk_crc24q() in ``librtcm.py`` utilizes the achievements of [RTKLIB](https://github.com/tomojitakasu/RTKLIB) ver.2.4.3b34.
131
+
132
+ Copyright (c) 2022-2024 by Satoshi Takahashi
133
+ Copyright (c) 2007-2020 by Tomoji TAKASU
@@ -0,0 +1,27 @@
1
+ --------------------------------------------------------------------------------
2
+ QZS L6 Tool: quasi-zenith satellite L6-band tool
3
+
4
+ Released under The 2-Clause BSD License
5
+ https://opensource.org/licenses/BSD-2-Clause
6
+
7
+ Redistribution and use in source and binary forms, with or without modification,
8
+ are permitted provided that the following conditions are met:
9
+
10
+ Redistributions of source code must retain the above copyright notice, this list
11
+ of conditions and the following disclaimer. Redistributions in binary form must
12
+ reproduce the above copyright notice, this list of conditions and the following
13
+ disclaimer in the documentation and/or other materials provided with the
14
+ distribution.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+
27
+ --------------------------------------------------------------------------------
@@ -0,0 +1,97 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "qzsl6tool"
7
+ version = "0.1.7"
8
+ description = "Command-line tools for reading and converting GNSS messages, including QZSS L6, RTCM, Galileo HAS, and BeiDou PPP-B2b data."
9
+ readme = "readme-en.md"
10
+ requires-python = ">=3.8"
11
+ license = "BSD-2-Clause"
12
+ license-files = ["license.txt"]
13
+ authors = [
14
+ { name = "Satoshi Takahashi", email = "git@s-taka.org" },
15
+ ]
16
+ dependencies = [
17
+ "bitstring",
18
+ "galois",
19
+ "numpy",
20
+ ]
21
+ keywords = [
22
+ "GNSS",
23
+ "QZSS",
24
+ "RTCM",
25
+ "CLAS",
26
+ "MADOCA",
27
+ "Galileo HAS",
28
+ "BeiDou",
29
+ ]
30
+ classifiers = [
31
+ "Development Status :: 3 - Alpha",
32
+ "Environment :: Console",
33
+ "Intended Audience :: Science/Research",
34
+ "Natural Language :: English",
35
+ "Natural Language :: Japanese",
36
+ "Operating System :: MacOS",
37
+ "Operating System :: POSIX :: Linux",
38
+ "Programming Language :: Python :: 3",
39
+ "Programming Language :: Python :: 3.8",
40
+ "Programming Language :: Python :: 3.9",
41
+ "Programming Language :: Python :: 3.10",
42
+ "Programming Language :: Python :: 3.11",
43
+ "Programming Language :: Python :: 3.12",
44
+ "Programming Language :: Python :: 3.13",
45
+ "Topic :: Scientific/Engineering",
46
+ ]
47
+
48
+ [project.urls]
49
+ Homepage = "https://github.com/yoronneko/qzsl6tool"
50
+ Repository = "https://github.com/yoronneko/qzsl6tool"
51
+ Documentation = "https://github.com/yoronneko/qzsl6tool/tree/main/docs"
52
+ "Release Notes" = "https://github.com/yoronneko/qzsl6tool/blob/main/release_note.md"
53
+ "Bug Tracker" = "https://github.com/yoronneko/qzsl6tool/issues"
54
+
55
+ [tool.setuptools]
56
+ py-modules = [
57
+ "alstread",
58
+ "bdsb2read",
59
+ "gale6read",
60
+ "galinavread",
61
+ "l6rtcm4050",
62
+ "libecef",
63
+ "libgnsstime",
64
+ "libnav",
65
+ "libqznma",
66
+ "libqzsl6tool",
67
+ "libssr",
68
+ "libtrace",
69
+ "novread",
70
+ "psdrread",
71
+ "qzsl1sread",
72
+ "qzsl6read",
73
+ "rtcmread",
74
+ "septread",
75
+ "ubxread",
76
+ ]
77
+ script-files = [
78
+ "python/alstread.py",
79
+ "python/bdsb2read.py",
80
+ "python/ecef2llh.py",
81
+ "python/gale6read.py",
82
+ "python/galinavread.py",
83
+ "python/gps2utc.py",
84
+ "python/l6rtcm4050.py",
85
+ "python/llh2ecef.py",
86
+ "python/novread.py",
87
+ "python/psdrread.py",
88
+ "python/qzsl1sread.py",
89
+ "python/qzsl6read.py",
90
+ "python/rtcmread.py",
91
+ "python/septread.py",
92
+ "python/ubxread.py",
93
+ "python/utc2gps.py",
94
+ ]
95
+
96
+ [tool.setuptools.package-dir]
97
+ "" = "python"
@@ -0,0 +1,141 @@
1
+ #! /usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ #
4
+ # alstread.py: Allystar HD9310 option C raw data read
5
+ # A part of QZS L6 Tool, https://github.com/yoronneko/qzsl6tool
6
+ #
7
+ # Copyright (c) 2022-2026 Satoshi Takahashi, all rights reserved.
8
+ #
9
+ # Released under BSD 2-clause license.
10
+ #
11
+ # References:
12
+ # [1] Justin Yang, QZSS L6 Enabled Multi-band Multi-GNSS Receiver
13
+ # https://docs.datagnss.com/rtk-board/firmware/L6/L6DE_tech_intro.pdf
14
+
15
+ import argparse
16
+ import os
17
+ import sys
18
+ from typing import TextIO
19
+
20
+ sys.path.append(os.path.dirname(__file__))
21
+ import libgnsstime
22
+ import libqzsl6tool
23
+ import libtrace
24
+
25
+ class AllystarReceiver:
26
+ dict_snr = {} # SNR dictionary
27
+ dict_data = {} # payload data dictionary
28
+ last_gpst = 0 # last received GPS time
29
+ l6 = b'' # L6 message
30
+
31
+ def __init__(self, trace: libtrace.Trace):
32
+ self.trace = trace
33
+
34
+ def read(self): # ref. [1]
35
+ sync = bytes(4)
36
+ while True:
37
+ b = sys.stdin.buffer.read(1)
38
+ if not b:
39
+ return False
40
+ sync = sync[1:4] + b
41
+ if sync == b'\xf1\xd9\x02\x10':
42
+ break
43
+ l6 = sys.stdin.buffer.read(266)
44
+ csum = sys.stdin.buffer.read(2)
45
+ if not l6 or not csum:
46
+ return False
47
+ l6 = b'\x02\x10' + l6
48
+ len_l6 = int.from_bytes(l6[ 2: 4], 'little')
49
+ self.prn = int.from_bytes(l6[ 4: 6], 'little') - 700
50
+ freqid = int.from_bytes(l6[ 6: 7], 'little')
51
+ len_data = int.from_bytes(l6[ 7: 8], 'little') - 2
52
+ self.gpsw = int.from_bytes(l6[ 8:10], 'big')
53
+ self.gpst = int.from_bytes(l6[10:14], 'big')
54
+ self.snr = int.from_bytes(l6[14:15], 'big')
55
+ flag = int.from_bytes(l6[15:16], 'big')
56
+ self.data = l6[16:268]
57
+ if self.last_gpst == 0:
58
+ self.last_gpst = self.gpst
59
+ self.err = ""
60
+ csum1, csum2 = libqzsl6tool.checksum(l6)
61
+ if csum[0] != csum1 or csum[1] != csum2: self.err += "CS "
62
+ if len_l6 != 264 : self.err += "Payload "
63
+ if len_data != 63 : self.err += "Data "
64
+ if flag & 0x01 : self.err += "RS "
65
+ if flag & 0x02 : self.err += "Week "
66
+ if flag & 0x04 : self.err += "TOW "
67
+ return True
68
+
69
+ def select_sat(self, s_prn: int) -> None:
70
+ ''' selects satellite and displays message '''
71
+ self.p_prn = 0 # PRN of satellite that has the strongest C/No
72
+ self.p_snr = 0 # C/No of satellite that has the strongest C/No
73
+ self.l6 = b'' # L6 msg of satellite that has the strongest C/No
74
+ disp_msg = ''
75
+ if self.last_gpst != self.gpst and len(self.dict_snr) != 0:
76
+ # A change in gpst means possible sats data correction is finished.
77
+ self.last_gpst = self.gpst
78
+ if s_prn: # if specified satellite is used
79
+ self.p_prn = s_prn
80
+ else: # otherwise, we use the satellite that has max C/No
81
+ self.p_prn = sorted(self.dict_snr.items(),
82
+ key=lambda x: x[1], reverse=True)[0][0]
83
+ self.p_snr = self.dict_snr.get (self.p_prn, 0)
84
+ self.l6 = self.dict_data.get(self.p_prn, b'')
85
+ disp_msg += f"---> prn {self.p_prn} (C/No {self.p_snr} dB)\n"
86
+ self.dict_snr.clear()
87
+ self.dict_data.clear()
88
+ # then, we add the current data to the dictionaries when no errors found
89
+ if not self.err:
90
+ self.dict_snr [self.prn] = self.snr
91
+ self.dict_data[self.prn] = self.data
92
+ disp_msg += \
93
+ self.trace.msg(0, f'{self.prn} ', fg='green') + \
94
+ self.trace.msg(0, libgnsstime.gps2utc(self.gpsw, self.gpst // 1000) , fg='yellow') + \
95
+ self.trace.msg(0, f' {self.snr}')
96
+ if self.err:
97
+ disp_msg += self.trace.msg(0, ' ' + self.err, fg='red')
98
+ self.trace.show(0, disp_msg)
99
+
100
+ if __name__ == '__main__':
101
+ parser = argparse.ArgumentParser(
102
+ description=f'Allystar HD9310 message read, QZS L6 Tool ver.{libqzsl6tool.VERSION}')
103
+ parser_group = parser.add_mutually_exclusive_group()
104
+ parser.add_argument(
105
+ '-c', '--color', action='store_true',
106
+ help='apply ANSI color escape sequences even for non-terminal.')
107
+ parser_group.add_argument(
108
+ '-l', '--l6', action='store_true',
109
+ help='send QZS L6 messages to stdout (it also turns off Allystar and u-blox messages).')
110
+ parser.add_argument(
111
+ '-m', '--message', action='store_true',
112
+ help='show Allystar messages to stderr.')
113
+ parser.add_argument(
114
+ '-p', '--prn', type=int, default=0,
115
+ help='satellite PRN to be specified (0, 193-211).')
116
+ args = parser.parse_args()
117
+ fp_disp, fp_raw = sys.stdout, None
118
+ if args.l6: # QZS L6 raw message output to stdout
119
+ fp_disp, fp_raw = None, sys.stdout
120
+ if args.message: # Allystar message to stderr
121
+ fp_disp = sys.stderr
122
+ if (args.prn < 193 or 211 < args.prn) and args.prn != 0:
123
+ libtrace.warn("QZS L6 PRN is in range of 193-211 or 0")
124
+ args.prn = 0
125
+ trace = libtrace.Trace(fp_disp, 0, args.color)
126
+ rcv = AllystarReceiver(trace)
127
+ try:
128
+ while rcv.read():
129
+ rcv.select_sat(args.prn)
130
+ if rcv.l6 and fp_raw:
131
+ fp_raw.buffer.write(rcv.l6)
132
+ fp_raw.flush()
133
+ except (BrokenPipeError, IOError):
134
+ devnull = os.open(os.devnull, os.O_WRONLY)
135
+ os.dup2(devnull, sys.stdout.fileno())
136
+ sys.exit(1)
137
+ except KeyboardInterrupt:
138
+ libtrace.warn("User break - terminated")
139
+ sys.exit()
140
+
141
+ # EOF