ka9q-python 3.2.0__tar.gz → 3.2.2__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 (55) hide show
  1. {ka9q_python-3.2.0/ka9q_python.egg-info → ka9q_python-3.2.2}/PKG-INFO +2 -2
  2. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/ka9q/__init__.py +1 -1
  3. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/ka9q/rtp_recorder.py +5 -1
  4. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/ka9q/types.py +8 -7
  5. {ka9q_python-3.2.0 → ka9q_python-3.2.2/ka9q_python.egg-info}/PKG-INFO +2 -2
  6. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/ka9q_python.egg-info/SOURCES.txt +1 -0
  7. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/pyproject.toml +2 -2
  8. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/setup.py +1 -1
  9. ka9q_python-3.2.2/tests/test_rtp_recorder.py +41 -0
  10. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/LICENSE +0 -0
  11. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/MANIFEST.in +0 -0
  12. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/README.md +0 -0
  13. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/examples/advanced_features_demo.py +0 -0
  14. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/examples/channel_cleanup_example.py +0 -0
  15. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/examples/codar_oceanography.py +0 -0
  16. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/examples/discover_example.py +0 -0
  17. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/examples/grape_integration_example.py +0 -0
  18. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/examples/hf_band_scanner.py +0 -0
  19. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/examples/rtp_recorder_example.py +0 -0
  20. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/examples/simple_am_radio.py +0 -0
  21. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/examples/stream_example.py +0 -0
  22. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/examples/superdarn_recorder.py +0 -0
  23. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/examples/test_channel_operations.py +0 -0
  24. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/examples/test_improvements.py +0 -0
  25. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/examples/test_timing_fields.py +0 -0
  26. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/examples/tune.py +0 -0
  27. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/examples/tune_example.py +0 -0
  28. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/ka9q/control.py +0 -0
  29. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/ka9q/discovery.py +0 -0
  30. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/ka9q/exceptions.py +0 -0
  31. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/ka9q/resequencer.py +0 -0
  32. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/ka9q/stream.py +0 -0
  33. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/ka9q/stream_quality.py +0 -0
  34. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/ka9q/utils.py +0 -0
  35. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/ka9q_python.egg-info/dependency_links.txt +0 -0
  36. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/ka9q_python.egg-info/requires.txt +0 -0
  37. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/ka9q_python.egg-info/top_level.txt +0 -0
  38. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/setup.cfg +0 -0
  39. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/__init__.py +0 -0
  40. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/conftest.py +0 -0
  41. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/test_decode_functions.py +0 -0
  42. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/test_encode_functions.py +0 -0
  43. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/test_encode_socket.py +0 -0
  44. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/test_integration.py +0 -0
  45. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/test_listen_multicast.py +0 -0
  46. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/test_multihomed.py +0 -0
  47. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/test_native_discovery.py +0 -0
  48. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/test_performance_fixes.py +0 -0
  49. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/test_remove_channel.py +0 -0
  50. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/test_security_features.py +0 -0
  51. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/test_tune.py +0 -0
  52. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/test_tune_cli.py +0 -0
  53. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/test_tune_debug.py +0 -0
  54. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/test_tune_live.py +0 -0
  55. {ka9q_python-3.2.0 → ka9q_python-3.2.2}/tests/test_tune_method.py +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ka9q-python
3
- Version: 3.2.0
3
+ Version: 3.2.2
4
4
  Summary: Python interface for ka9q-radio control and monitoring
5
5
  Home-page: https://github.com/mijahauan/ka9q-python
6
6
  Author: Michael Hauan AC0G
7
7
  Author-email: Michael Hauan AC0G <ac0g@hauan.org>
8
- License-Expression: MIT
8
+ License: MIT
9
9
  Project-URL: Homepage, https://github.com/mijahauan/ka9q-python
10
10
  Project-URL: Documentation, https://github.com/mijahauan/ka9q-python/blob/main/README.md
11
11
  Project-URL: Repository, https://github.com/mijahauan/ka9q-python
@@ -22,7 +22,7 @@ Basic usage:
22
22
  ssrc = allocate_ssrc(10.0e6, "iq", 16000)
23
23
  """
24
24
 
25
- __version__ = '3.2.0'
25
+ __version__ = '3.2.1'
26
26
  __author__ = 'Michael Hauan AC0G'
27
27
 
28
28
  from .control import RadiodControl, allocate_ssrc
@@ -30,6 +30,7 @@ logger = logging.getLogger(__name__)
30
30
  GPS_UTC_OFFSET = 315964800 # GPS epoch (1980-01-06) - Unix epoch (1970-01-01)
31
31
  UNIX_EPOCH = 2208988800 # Unix epoch in NTP seconds
32
32
  BILLION = 1_000_000_000
33
+ GPS_LEAP_SECONDS = 18 # GPS time is ahead of UTC by 18 seconds (as of 2025)
33
34
 
34
35
 
35
36
  class RecorderState(Enum):
@@ -140,7 +141,10 @@ def rtp_to_wallclock(rtp_timestamp: int, channel: ChannelInfo) -> Optional[float
140
141
  return None
141
142
 
142
143
  # Convert GPS nanoseconds to Unix time
143
- sender_time = channel.gps_time + BILLION * (UNIX_EPOCH - GPS_UTC_OFFSET)
144
+ # GPS epoch is Jan 6, 1980; Unix epoch is Jan 1, 1970
145
+ # gps_time is nanoseconds since GPS epoch, so add GPS_UTC_OFFSET (in ns)
146
+ # AND subtract current GPS_LEAP_SECONDS (18s) to align with UTC
147
+ sender_time = channel.gps_time + BILLION * (GPS_UTC_OFFSET - GPS_LEAP_SECONDS)
144
148
 
145
149
  # Add offset from RTP timestamp difference
146
150
  # Cast to int32 for proper wrapping behavior
@@ -150,12 +150,13 @@ class StatusType:
150
150
  # Command packet type
151
151
  CMD = 1
152
152
 
153
- # Encoding types (from ka9q-radio)
153
+ # Encoding types - must match enum encoding in ka9q-radio/src/rtp.h
154
154
  class Encoding:
155
- """Output encoding types"""
155
+ """Output encoding types - values must match ka9q-radio/src/rtp.h enum encoding"""
156
156
  NO_ENCODING = 0
157
- S16BE = 1 # Signed 16-bit big-endian
158
- S16LE = 2 # Signed 16-bit little-endian
159
- F32 = 3 # 32-bit float
160
- F16 = 4 # 16-bit float
161
- OPUS = 5 # Opus codec
157
+ S16LE = 1 # Signed 16-bit little-endian
158
+ S16BE = 2 # Signed 16-bit big-endian
159
+ OPUS = 3 # Opus codec
160
+ F32 = 4 # 32-bit float (F32LE in C)
161
+ AX25 = 5 # AX.25 packet
162
+ F16 = 6 # 16-bit float (F16LE in C)
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ka9q-python
3
- Version: 3.2.0
3
+ Version: 3.2.2
4
4
  Summary: Python interface for ka9q-radio control and monitoring
5
5
  Home-page: https://github.com/mijahauan/ka9q-python
6
6
  Author: Michael Hauan AC0G
7
7
  Author-email: Michael Hauan AC0G <ac0g@hauan.org>
8
- License-Expression: MIT
8
+ License: MIT
9
9
  Project-URL: Homepage, https://github.com/mijahauan/ka9q-python
10
10
  Project-URL: Documentation, https://github.com/mijahauan/ka9q-python/blob/main/README.md
11
11
  Project-URL: Repository, https://github.com/mijahauan/ka9q-python
@@ -44,6 +44,7 @@ tests/test_multihomed.py
44
44
  tests/test_native_discovery.py
45
45
  tests/test_performance_fixes.py
46
46
  tests/test_remove_channel.py
47
+ tests/test_rtp_recorder.py
47
48
  tests/test_security_features.py
48
49
  tests/test_tune.py
49
50
  tests/test_tune_cli.py
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ka9q-python"
7
- version = "3.2.0"
7
+ version = "3.2.2"
8
8
  description = "Python interface for ka9q-radio control and monitoring"
9
9
  readme = "README.md"
10
10
  authors = [
11
11
  {name = "Michael Hauan AC0G", email = "ac0g@hauan.org"}
12
12
  ]
13
- license = "MIT"
13
+ license = {text = "MIT"}
14
14
  requires-python = ">=3.9"
15
15
  classifiers = [
16
16
  "Development Status :: 4 - Beta",
@@ -12,7 +12,7 @@ long_description = readme.read_text() if readme.exists() else ''
12
12
 
13
13
  setup(
14
14
  name='ka9q-python',
15
- version='3.2.0',
15
+ version='3.2.1',
16
16
  description='Python interface for ka9q-radio control and monitoring',
17
17
  long_description=long_description,
18
18
  long_description_content_type='text/markdown',
@@ -0,0 +1,41 @@
1
+ """
2
+ Tests for RTP recorder functionality
3
+ """
4
+ import pytest
5
+ from ka9q.rtp_recorder import rtp_to_wallclock
6
+ from ka9q.discovery import ChannelInfo
7
+
8
+ def test_rtp_to_wallclock():
9
+ """Test GPS time to Unix time conversion"""
10
+ # Channel info with mocked timing
11
+ # GPS Time: 1234567890000000000 ns (random recent-ish GPS time)
12
+ # This corresponds to some time around 2019
13
+ gps_time_ns = 1234567890000000000
14
+
15
+ # Constants from code
16
+ GPS_UTC_OFFSET = 315964800
17
+ BILLION = 1_000_000_000
18
+
19
+ channel = ChannelInfo(
20
+ ssrc=1234,
21
+ preset="test",
22
+ sample_rate=48000,
23
+ frequency=100.0,
24
+ snr=0.0,
25
+ multicast_address="239.1.2.3",
26
+ port=5004,
27
+ gps_time=gps_time_ns,
28
+ rtp_timesnap=1000
29
+ )
30
+
31
+ # Case 1: Same RTP timestamp as snapshot
32
+ # Result should be exactly GPS time + offset
33
+ # Expected Unix time = GPS time + Offset - Leap Seconds
34
+ expected_unix_ns = gps_time_ns + (BILLION * (GPS_UTC_OFFSET - 18))
35
+ expected_unix_sec = expected_unix_ns / BILLION
36
+
37
+ assert rtp_to_wallclock(1000, channel) == pytest.approx(expected_unix_sec)
38
+
39
+ # Case 2: One second later
40
+ # 48000 samples later
41
+ assert rtp_to_wallclock(1000 + 48000, channel) == pytest.approx(expected_unix_sec + 1.0)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes