pygnssutils 1.2.4__tar.gz → 1.2.5__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 (53) hide show
  1. {pygnssutils-1.2.4/src/pygnssutils.egg-info → pygnssutils-1.2.5}/PKG-INFO +4 -4
  2. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/README.md +3 -3
  3. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/_version.py +1 -1
  4. pygnssutils-1.2.5/src/pygnssutils/rawnav.py +340 -0
  5. pygnssutils-1.2.4/src/pygnssutils/rawnav.py → pygnssutils-1.2.5/src/pygnssutils/rawnav_reader.py +68 -393
  6. pygnssutils-1.2.4/src/pygnssutils/rinex_subframes_bds.py → pygnssutils-1.2.5/src/pygnssutils/rawnav_subframes_bds.py +7 -7
  7. pygnssutils-1.2.4/src/pygnssutils/rinex_subframes_gal.py → pygnssutils-1.2.5/src/pygnssutils/rawnav_subframes_gal.py +4 -2
  8. pygnssutils-1.2.4/src/pygnssutils/rinex_subframes_glo.py → pygnssutils-1.2.5/src/pygnssutils/rawnav_subframes_glo.py +9 -2
  9. pygnssutils-1.2.4/src/pygnssutils/rinex_subframes_gps.py → pygnssutils-1.2.5/src/pygnssutils/rawnav_subframes_gps.py +7 -17
  10. pygnssutils-1.2.5/src/pygnssutils/rawnav_subframes_irn.py +171 -0
  11. pygnssutils-1.2.5/src/pygnssutils/rawnav_subframes_qzs.py +518 -0
  12. pygnssutils-1.2.5/src/pygnssutils/rawnav_subframes_sba.py +144 -0
  13. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/rinex_conv.py +2 -4
  14. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/rinex_conv_met.py +0 -4
  15. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/rinex_conv_nav.py +406 -24
  16. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/rinex_conv_obs.py +2 -6
  17. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/rinex_globals.py +80 -27
  18. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/rinex_helpers.py +16 -32
  19. {pygnssutils-1.2.4 → pygnssutils-1.2.5/src/pygnssutils.egg-info}/PKG-INFO +4 -4
  20. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils.egg-info/SOURCES.txt +9 -4
  21. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/tests/test_rawnav.py +1 -1
  22. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/tests/test_rinex.py +23 -99
  23. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/tests/test_rinex_defs.py +70 -6
  24. pygnssutils-1.2.5/tests/test_rinex_parse.py +491 -0
  25. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/LICENSE +0 -0
  26. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/pyproject.toml +0 -0
  27. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/setup.cfg +0 -0
  28. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/__init__.py +0 -0
  29. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/exceptions.py +0 -0
  30. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/globals.py +0 -0
  31. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/gnssmqttclient.py +0 -0
  32. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/gnssmqttclient_cli.py +0 -0
  33. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/gnssntripclient.py +0 -0
  34. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/gnssntripclient_cli.py +0 -0
  35. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/gnssreader.py +0 -0
  36. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/gnssserver.py +0 -0
  37. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/gnssserver_cli.py +0 -0
  38. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/gnssstreamer.py +0 -0
  39. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/gnssstreamer_cli.py +0 -0
  40. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/helpers.py +0 -0
  41. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/mqttmessage.py +0 -0
  42. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/rinex_conv_cli.py +0 -0
  43. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils/socket_server.py +0 -0
  44. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils.egg-info/dependency_links.txt +0 -0
  45. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils.egg-info/entry_points.txt +0 -0
  46. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils.egg-info/requires.txt +0 -0
  47. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/src/pygnssutils.egg-info/top_level.txt +0 -0
  48. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/tests/test_cli.py +0 -0
  49. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/tests/test_gnssstreamer.py +0 -0
  50. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/tests/test_socketwrapper.py +0 -0
  51. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/tests/test_sourcetable.py +0 -0
  52. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/tests/test_static.py +0 -0
  53. {pygnssutils-1.2.4 → pygnssutils-1.2.5}/tests/test_stream.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pygnssutils
3
- Version: 1.2.4
3
+ Version: 1.2.5
4
4
  Summary: GNSS Command Line Utilities
5
5
  Author-email: Steve Smith <semuadmin@semuconsulting.com>
6
6
  Maintainer-email: Steve Smith <semuadmin@semuconsulting.com>
@@ -328,7 +328,7 @@ Streaming terminated, 93 messages processed with 0 errors.
328
328
 
329
329
  ### <a name="gnssstreamerservice">Installing gnssstreamer as a systemd service on Linux</a>
330
330
 
331
- This example should work for most Linux distributions running `systemd` and `python3>=3.8`, including Raspberry Pi OS (*substitute `dnf` for `apt` as necessary*).
331
+ This example should work for most Linux distributions running `systemd` and `python3>=3.10`, including Raspberry Pi OS (*substitute `dnf` or `pacman` for `apt` as necessary*).
332
332
 
333
333
  The example `gnssstreamer.conf` file will set up `gnssstreamer` as a multi-client TCP socket server accessible on `hostip:50012` (*check TCP port 50012 is allowed through any active firewall*).
334
334
 
@@ -543,11 +543,11 @@ class pygnssutils.rinex_conv.RinexConvertor(app, rinex_version, rinex_type, gnss
543
543
 
544
544
  A command line utility and Python class `RinexConverter` to convert binary GNSS data logs to RINEX text file format.
545
545
 
546
- **NB: RINEX conversion is an experimental work in progress (*contributions and feedback welcome*). The current ALPHA release implements the following functionality:**
546
+ **NB: RINEX conversion is an experimental work in progress (*contributions and feedback welcome*). The current release implements the following functionality:**
547
547
 
548
548
  1. RINEX versions 3.05 and 4.02.
549
549
  1. Convert binary UBX RXM-RAW or RXM-RAWX (raw observation) data from u-blox receivers (e.g. ZED-F9P) to RINEX Observation file format.
550
- 1. Convert binary RXM-SFRBX (navigation subframe) data from u-blox receivers to RINEX Navigation file format. **Currently supports GPS LNAV/CNAV, GAL FNAV/INAV, BDS D1/D2 & GLO L1OF**, but the underlying `RinexConverterNavigation` class will be enhanced in future releases.
550
+ 1. Convert binary RXM-SFRBX (navigation subframe) data from u-blox receivers to RINEX Navigation file format.
551
551
  1. Convert RTCM3 Ephemerides messages (1019, 1020, 1041-1046) from any source (including NTRIP caster or RTK base station receiver) to RINEX Navigation file format.
552
552
  1. Convert NMEA MWD (wind speed and direction) and XDR (temperature and pressure) sensor data to RINEX Meteorology file format.
553
553
 
@@ -284,7 +284,7 @@ Streaming terminated, 93 messages processed with 0 errors.
284
284
 
285
285
  ### <a name="gnssstreamerservice">Installing gnssstreamer as a systemd service on Linux</a>
286
286
 
287
- This example should work for most Linux distributions running `systemd` and `python3>=3.8`, including Raspberry Pi OS (*substitute `dnf` for `apt` as necessary*).
287
+ This example should work for most Linux distributions running `systemd` and `python3>=3.10`, including Raspberry Pi OS (*substitute `dnf` or `pacman` for `apt` as necessary*).
288
288
 
289
289
  The example `gnssstreamer.conf` file will set up `gnssstreamer` as a multi-client TCP socket server accessible on `hostip:50012` (*check TCP port 50012 is allowed through any active firewall*).
290
290
 
@@ -499,11 +499,11 @@ class pygnssutils.rinex_conv.RinexConvertor(app, rinex_version, rinex_type, gnss
499
499
 
500
500
  A command line utility and Python class `RinexConverter` to convert binary GNSS data logs to RINEX text file format.
501
501
 
502
- **NB: RINEX conversion is an experimental work in progress (*contributions and feedback welcome*). The current ALPHA release implements the following functionality:**
502
+ **NB: RINEX conversion is an experimental work in progress (*contributions and feedback welcome*). The current release implements the following functionality:**
503
503
 
504
504
  1. RINEX versions 3.05 and 4.02.
505
505
  1. Convert binary UBX RXM-RAW or RXM-RAWX (raw observation) data from u-blox receivers (e.g. ZED-F9P) to RINEX Observation file format.
506
- 1. Convert binary RXM-SFRBX (navigation subframe) data from u-blox receivers to RINEX Navigation file format. **Currently supports GPS LNAV/CNAV, GAL FNAV/INAV, BDS D1/D2 & GLO L1OF**, but the underlying `RinexConverterNavigation` class will be enhanced in future releases.
506
+ 1. Convert binary RXM-SFRBX (navigation subframe) data from u-blox receivers to RINEX Navigation file format.
507
507
  1. Convert RTCM3 Ephemerides messages (1019, 1020, 1041-1046) from any source (including NTRIP caster or RTK base station receiver) to RINEX Navigation file format.
508
508
  1. Convert NMEA MWD (wind speed and direction) and XDR (temperature and pressure) sensor data to RINEX Meteorology file format.
509
509
 
@@ -8,4 +8,4 @@ Created on 2 Oct 2020
8
8
  :license: BSD 3-Clause
9
9
  """
10
10
 
11
- __version__ = "1.2.4"
11
+ __version__ = "1.2.5"
@@ -0,0 +1,340 @@
1
+ """
2
+ rawnav.py
3
+
4
+ The RawNav class parses and stores the individual attributes
5
+ (ephemerides, ionospheric & clock corrections, etc.) of one
6
+ or more raw GNSS NAV subframes.
7
+
8
+ Once a RawNav object is instantiated, the `parse` function can
9
+ be invoked repeatedly to collate data from separate sequential
10
+ subframes e.g. for GPS LNAV, subframe 1 contains clock corrections,
11
+ subframes 2 & 3 contain ephemerides and subframe 4 page 18 contains
12
+ ionospheric corrections.
13
+
14
+ An `subframeacq` bitfield signifies which subframe/page IDs have
15
+ been acquired, and hence whether or not the RawNav frame contains
16
+ sufficient information to be converted to a NAV record e.g. as a
17
+ precursor to RINEX conversion.
18
+
19
+ The objective is to handle any GNSS subframe format for which:
20
+
21
+ - the complete, unpadded subframe is represented as an unsigned little-endian
22
+ integer.
23
+ - the subframe definition dictionary has been transcribed from the relevant
24
+ GNSS ICD (Interface Control Document) with standardized ascii
25
+ field names e.g. `omegadot`, `sqrta`, `cus`, `tauc`, etc.
26
+
27
+ Format of subframe definition dictionary::
28
+
29
+ dict[field_name, tuple[offset, length, encoding, scaling]
30
+
31
+ where offset and length are in bits (see, for example,
32
+ `rawnav_subframes_gps.py`).
33
+
34
+ MSB, ISB (intermediate bits) and LSB field names MUST be suffixed "_msb",
35
+ "_isb" and "_lsb" respectively - the `parse` function will automatically
36
+ combine them.
37
+
38
+ Created on 20 Apr 2026
39
+
40
+ :author: semuadmin (Steve Smith)
41
+ :copyright: semuadmin © 2026
42
+ :license: BSD 3-Clause
43
+ """
44
+
45
+ # pylint: disable=too-many-arguments, too-many-positional-arguments
46
+
47
+ import struct
48
+ from logging import getLogger
49
+ from typing import Literal
50
+
51
+ from pygnssutils.exceptions import RINEXProcessingError
52
+ from pygnssutils.rinex_globals import GLO
53
+ from pygnssutils.rinex_helpers import get_svcode
54
+
55
+ IS1 = "_is1"
56
+ """IS1 field name suffix (between MSB and ISB)"""
57
+ ISB = "_isb"
58
+ """ISB field name suffix (between MSB/IS1 and LSB)"""
59
+ LSB = "_lsb"
60
+ """LSB field name suffix"""
61
+ MSB = "_msb"
62
+ """MSB field name suffix"""
63
+ TOC = "toc"
64
+ """TOC (time of clock) field name - used to establish epoch"""
65
+ TOW = "tow"
66
+ """HOW TOW field name"""
67
+ SID = "sid"
68
+ """subframe id field name"""
69
+ SPID = "spid"
70
+ """subframe page id field name"""
71
+ WN = "wn"
72
+ """WN (week number) field name - used to establish epoch"""
73
+
74
+ PREAMBLE = "_preamble"
75
+ VALPREAMBLE = "_valid_preamble"
76
+ D = "D" # IEEE 754 64-bit double float
77
+ F = "F" # IEEE 754 32-bit float
78
+ S = "S" # 2's complement signed integer
79
+ U = "U" # unsiged integer
80
+
81
+
82
+ class RawNav:
83
+ """
84
+ Raw Navigation Class.
85
+ """
86
+
87
+ # pylint: disable=too-many-instance-attributes
88
+
89
+ def __init__(
90
+ self,
91
+ gnss: Literal["G", "R", "E", "C", "J", "S", "I"],
92
+ svid: int,
93
+ sigcode: str,
94
+ **kwargs, # pylint: disable=unused-argument
95
+ ):
96
+ """
97
+ Constructor.
98
+
99
+ :param Literal["G","R","E","C","J","S","I"] gnss: GNSS code
100
+ :param int svid: RINEX SV id e.g. 14
101
+ :param str sigcode: RINEX signal code e.g. "1C"
102
+ :param dict kwargs: optional keyword arguments
103
+ """
104
+
105
+ self._logger = getLogger(__name__)
106
+ self._gnss = gnss
107
+ self._svid = svid
108
+ self._sigcode = sigcode
109
+ if gnss != GLO:
110
+ self.wn = -1
111
+ self.toc = -1
112
+ self.tow = -1
113
+ self._subframeacq = 0
114
+ self._msb = {}
115
+ self._isb = {}
116
+ self._is1 = {}
117
+ self._lsb = {}
118
+ self._firsttoc = 999999999
119
+ self._lasttoc = 0
120
+ self._firstwn = 999999999
121
+ self._lastwn = 0
122
+
123
+ def parse(
124
+ self,
125
+ data: int,
126
+ subframedef: dict[str, tuple[int, int, str, int]],
127
+ subframeacq: int,
128
+ sequence: bool = True,
129
+ ):
130
+ """
131
+ Parse raw subframe data into its constituent attributes.
132
+
133
+ :param int data: raw, unpadded input data
134
+ :param dict[str, tuple[int, int, str, int]] subframedef: subframe \
135
+ definition dictionary (from GNSS ICD)
136
+ :param int subframeacq: subframe acquisition bitmask
137
+ :param bool sequence: process subframe as part of a contiguous sequence (True)
138
+ :raises: RINEXProcessingError
139
+ """
140
+
141
+ try:
142
+
143
+ # get exemplary preamble value if one is available
144
+ valpre = subframedef.pop(VALPREAMBLE, 0)
145
+
146
+ # get total subframe length in bits
147
+ offset, bitlen, _, _ = list(subframedef.values())[-1]
148
+ sfrlen = offset + bitlen
149
+
150
+ # parse each attribute in subframe, combining MSB, ISB and
151
+ # LSB fields where appropriate
152
+ for att, (offset, length, encoding, scaling) in subframedef.items():
153
+
154
+ if att[0:1] == "_": # ignore non-data attributes
155
+ continue
156
+ bits = data >> (sfrlen - offset - length) & (2**length - 1)
157
+
158
+ # validate preamble if an exemplary value is available
159
+ if valpre and att == PREAMBLE and bits != valpre:
160
+ raise RINEXProcessingError(
161
+ f"Invalid preamble - expected 0b{valpre:b}, got 0b{bits:b}"
162
+ )
163
+
164
+ # recombine MSB, IS1, ISB and LSB bits
165
+ if att[-4:].lower() == MSB: # most significant bits
166
+ self._msb[att] = (bits, length, encoding, scaling)
167
+ continue
168
+ if att[-4:].lower() == IS1: # intermediate bits 1 (BDS)
169
+ self._is1[att] = (bits, length, encoding, scaling)
170
+ continue
171
+ if att[-4:].lower() == ISB: # intermediate bits (BDS)
172
+ self._isb[att] = (bits, length, encoding, scaling)
173
+ continue
174
+ if att[-4:].lower() == LSB: # least significant bits
175
+ attns = att[:-4]
176
+ msbbits, msblen, _, _ = self._msb.pop(f"{attns}{MSB}", (0, 0, 0, 0))
177
+ is1bits, is1len, _, _ = self._is1.pop(f"{attns}{IS1}", (0, 0, 0, 0))
178
+ isbbits, isblen, _, _ = self._isb.pop(f"{attns}{ISB}", (0, 0, 0, 0))
179
+ bits = (
180
+ (msbbits << (is1len + isblen + length))
181
+ + (is1bits << (isblen + length))
182
+ + (isbbits << length)
183
+ + bits
184
+ )
185
+ if msblen: # if combining with msb...
186
+ att = attns # strip "_lsb" suffix
187
+ length += msblen + is1len + isblen
188
+
189
+ val = self._bits2val(bits, length, encoding, scaling)
190
+ setattr(self, att, val)
191
+
192
+ if att in (SID, SPID): # update subframe acquisition status
193
+ self._subframeacq |= subframeacq
194
+
195
+ if not sequence:
196
+ self._store_orphaned_msb()
197
+
198
+ except (ValueError, TypeError, KeyError) as err:
199
+ raise RINEXProcessingError(
200
+ "Invalid subframe definition dictionary."
201
+ ) from err
202
+
203
+ def _store_orphaned_msb(self):
204
+ """
205
+ If not processing sequentially, store any 'orphaned' MSB/IS1 now rather
206
+ than waiting for associated ISB/LSB from next subframe in sequence.
207
+ """
208
+
209
+ for msb in (self._msb, self._is1):
210
+ for att, (bits, length, encoding, scaling) in msb.items():
211
+ val = self._bits2val(bits, length, encoding, scaling)
212
+ setattr(self, att, val)
213
+ msb = {}
214
+
215
+ def _bits2val(
216
+ self, vali: int, length: int, encoding: str, scaling: int
217
+ ) -> int | float:
218
+ """
219
+ Convert encoded bits to value.
220
+
221
+ :param int vali: value as raw integer
222
+ :param int length: length in bits
223
+ :param str encoding: bit encoding e.g. U, S, N, F
224
+ :param int scaling: scaling factor (0 = no scaling)
225
+ :return: decoded value
226
+ :rtype: int | float
227
+ :raises: RINEXProcessingError
228
+ """
229
+
230
+ val = vali
231
+ if encoding == "U": # unsigned integer
232
+ pass
233
+ elif encoding == "S": # 2's complement signed integer
234
+ if vali >= (1 << (length - 1)):
235
+ val = vali - (1 << length)
236
+ elif encoding == "F": # IEEE 754 32 bit floating point
237
+ valb = int.to_bytes(vali, 4, "little")
238
+ val = struct.unpack("<f", valb)[0]
239
+ elif encoding == "D": # IEEE 754 64 bit double floating point
240
+ valb = int.to_bytes(vali, 8, "little")
241
+ val = struct.unpack("<d", valb)[0]
242
+ else:
243
+ raise RINEXProcessingError(f"Unknown attribute type {encoding}")
244
+ if scaling not in (0, 1):
245
+ val *= scaling
246
+ return val
247
+
248
+ def __str__(self) -> str:
249
+ """
250
+ Human readable representation.
251
+
252
+ :return: human readable representation
253
+ :rtype: str
254
+ """
255
+
256
+ stg = (
257
+ f"<RAWNAV({self.identity}, gnss={self._gnss}, svid={self._svid}, "
258
+ f"sigid={self._sigcode}, sfracq={self._subframeacq}, "
259
+ )
260
+ for i, att in enumerate(self.__dict__):
261
+ if att[0] != "_": # only show public attributes
262
+ val = self.__dict__[att]
263
+ stg += att + "=" + str(val)
264
+ if i < len(self.__dict__) - 1:
265
+ stg += ", "
266
+ stg += ")>"
267
+ return stg
268
+
269
+ @property
270
+ def identity(self) -> str:
271
+ """
272
+ Getter for identity.
273
+
274
+ :return: identity
275
+ :rtype: str
276
+ """
277
+
278
+ svcode = get_svcode(self._gnss, self._svid, leadzero=True)
279
+ return f"{svcode}{self._sigcode}"
280
+
281
+ @property
282
+ def gnss(self) -> str:
283
+ """
284
+ Getter for GNSS code e.g. "G"
285
+
286
+ :return: gnss
287
+ :rtype: str
288
+ """
289
+
290
+ return self._gnss
291
+
292
+ @property
293
+ def svid(self) -> int:
294
+ """
295
+ Getter for SV id e.g. 14
296
+
297
+ :return: svid
298
+ :rtype: int
299
+ """
300
+
301
+ return self._svid
302
+
303
+ @property
304
+ def svcode(self) -> str:
305
+ """
306
+ Getter for SV code (gnss & prn).
307
+
308
+ :return: svcode e.g. "G14"
309
+ :rtype: str
310
+ """
311
+
312
+ return get_svcode(self._gnss, self._svid, leadzero=False)
313
+
314
+ @property
315
+ def sigcode(self) -> str:
316
+ """
317
+ Getter for signal code in RINEX format.
318
+
319
+ :return: signal code e.g. '1C'
320
+ :rtype: str
321
+ """
322
+
323
+ return self._sigcode
324
+
325
+ @property
326
+ def subframeacq(self) -> int:
327
+ """
328
+ Getter for subframe acquisition status.
329
+
330
+ Bitfield signifying which subframe IDs have been acquired:
331
+
332
+ - subframeacq & 0b001 => page 1
333
+ - subframeacq & 0b010 => page 2,
334
+ - subframeacq & 0b100 => page 3, etc.
335
+
336
+ :return: subframe acquisition status.
337
+ :rtype: int
338
+ """
339
+
340
+ return self._subframeacq