ka9q-python 3.4.1__tar.gz → 3.4.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.
- {ka9q_python-3.4.1/ka9q_python.egg-info → ka9q_python-3.4.2}/PKG-INFO +2 -1
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/README.md +1 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/stream_example.py +4 -6
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q/__init__.py +1 -1
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q/control.py +2 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q/discovery.py +3 -1
- {ka9q_python-3.4.1 → ka9q_python-3.4.2/ka9q_python.egg-info}/PKG-INFO +2 -1
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q_python.egg-info/SOURCES.txt +1 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/pyproject.toml +1 -1
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/setup.py +1 -1
- ka9q_python-3.4.2/tests/test_decode_description.py +46 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/LICENSE +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/MANIFEST.in +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/advanced_features_demo.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/channel_cleanup_example.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/codar_oceanography.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/diagnostics/diagnose_packets.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/diagnostics/repro_utc_bug.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/discover_example.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/grape_integration_example.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/hf_band_scanner.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/rtp_recorder_example.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/simple_am_radio.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/superdarn_recorder.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/test_channel_operations.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/test_improvements.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/test_timing_fields.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/tune.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/examples/tune_example.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q/addressing.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q/exceptions.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q/managed_stream.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q/monitor.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q/resequencer.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q/rtp_recorder.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q/stream.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q/stream_quality.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q/types.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q/utils.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q_python.egg-info/dependency_links.txt +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q_python.egg-info/requires.txt +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/ka9q_python.egg-info/top_level.txt +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/setup.cfg +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/__init__.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/conftest.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_addressing.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_channel_verification.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_create_split_encoding.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_decode_functions.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_encode_functions.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_encode_socket.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_ensure_channel_encoding.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_integration.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_iq_20khz_f32.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_listen_multicast.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_managed_stream_recovery.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_monitor.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_multihomed.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_native_discovery.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_performance_fixes.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_remove_channel.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_rtp_recorder.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_security_features.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_ssrc_dest_unit.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_ssrc_encoding_unit.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_ttl_warning.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_tune.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_tune_cli.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_tune_debug.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_tune_live.py +0 -0
- {ka9q_python-3.4.1 → ka9q_python-3.4.2}/tests/test_tune_method.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ka9q-python
|
|
3
|
-
Version: 3.4.
|
|
3
|
+
Version: 3.4.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
|
|
@@ -48,6 +48,7 @@ Control radiod channels for any application: AM/FM/SSB radio, WSPR monitoring, S
|
|
|
48
48
|
|
|
49
49
|
- [Features](#features)
|
|
50
50
|
- [Installation](#installation)
|
|
51
|
+
- [Getting Started](docs/GETTING_STARTED.md)
|
|
51
52
|
- [Quick Start](#quick-start)
|
|
52
53
|
- [Documentation](#documentation)
|
|
53
54
|
- [Examples](#examples)
|
|
@@ -13,6 +13,7 @@ Control radiod channels for any application: AM/FM/SSB radio, WSPR monitoring, S
|
|
|
13
13
|
|
|
14
14
|
- [Features](#features)
|
|
15
15
|
- [Installation](#installation)
|
|
16
|
+
- [Getting Started](docs/GETTING_STARTED.md)
|
|
16
17
|
- [Quick Start](#quick-start)
|
|
17
18
|
- [Documentation](#documentation)
|
|
18
19
|
- [Examples](#examples)
|
|
@@ -123,15 +123,13 @@ def main():
|
|
|
123
123
|
if args.discover:
|
|
124
124
|
print("Discovering channels...")
|
|
125
125
|
channels = discover_channels(timeout=3.0)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
channel = ch
|
|
130
|
-
break
|
|
126
|
+
|
|
127
|
+
# FIX: Properly access the channel from the dictionary
|
|
128
|
+
channel = channels.get(args.ssrc)
|
|
131
129
|
|
|
132
130
|
if channel is None:
|
|
133
131
|
print(f"SSRC {args.ssrc} not found in discovered channels")
|
|
134
|
-
print(f"Available SSRCs: {
|
|
132
|
+
print(f"Available SSRCs: {list(channels.keys())}")
|
|
135
133
|
return 1
|
|
136
134
|
|
|
137
135
|
print(f"Found channel: {channel.frequency/1e6:.3f} MHz, {channel.sample_rate} Hz")
|
|
@@ -1972,6 +1972,8 @@ class RadiodControl:
|
|
|
1972
1972
|
status['rf_atten'] = decode_float(data, optlen)
|
|
1973
1973
|
elif type_val == StatusType.RF_AGC:
|
|
1974
1974
|
status['rf_agc'] = decode_int(data, optlen)
|
|
1975
|
+
elif type_val == StatusType.DESCRIPTION:
|
|
1976
|
+
status['description'] = decode_string(data, optlen)
|
|
1975
1977
|
elif type_val == StatusType.PRESET:
|
|
1976
1978
|
status['preset'] = decode_string(data, optlen)
|
|
1977
1979
|
elif type_val == StatusType.LOW_EDGE:
|
|
@@ -33,6 +33,7 @@ class ChannelInfo:
|
|
|
33
33
|
gps_time: Optional[int] = None # GPS nanoseconds when RTP_TIMESNAP was captured
|
|
34
34
|
rtp_timesnap: Optional[int] = None # RTP timestamp at GPS_TIME
|
|
35
35
|
encoding: int = 0 # stream encoding (0=none, 4=F32, etc)
|
|
36
|
+
description: Optional[str] = None # SDR hardware description
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
def _create_status_listener_socket(multicast_addr: str, interface: Optional[str] = None) -> socket.socket:
|
|
@@ -208,7 +209,8 @@ def discover_channels_native(status_address: str, listen_duration: float = 2.0,
|
|
|
208
209
|
port=port,
|
|
209
210
|
gps_time=status.get('gps_time'),
|
|
210
211
|
rtp_timesnap=status.get('rtp_timesnap'),
|
|
211
|
-
encoding=status.get('encoding', 0)
|
|
212
|
+
encoding=status.get('encoding', 0),
|
|
213
|
+
description=status.get('description')
|
|
212
214
|
)
|
|
213
215
|
|
|
214
216
|
# Store or update channel info
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ka9q-python
|
|
3
|
-
Version: 3.4.
|
|
3
|
+
Version: 3.4.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
|
|
@@ -48,6 +48,7 @@ Control radiod channels for any application: AM/FM/SSB radio, WSPR monitoring, S
|
|
|
48
48
|
|
|
49
49
|
- [Features](#features)
|
|
50
50
|
- [Installation](#installation)
|
|
51
|
+
- [Getting Started](docs/GETTING_STARTED.md)
|
|
51
52
|
- [Quick Start](#quick-start)
|
|
52
53
|
- [Documentation](#documentation)
|
|
53
54
|
- [Examples](#examples)
|
|
@@ -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.4.
|
|
15
|
+
version='3.4.2',
|
|
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,46 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import unittest
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from unittest.mock import patch, MagicMock
|
|
5
|
+
|
|
6
|
+
# Add parent directory to path
|
|
7
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
8
|
+
|
|
9
|
+
from ka9q.control import RadiodControl
|
|
10
|
+
from ka9q.types import StatusType
|
|
11
|
+
|
|
12
|
+
class TestDescriptionDecoding(unittest.TestCase):
|
|
13
|
+
"""Test SDR description decoding"""
|
|
14
|
+
|
|
15
|
+
@patch('ka9q.control.RadiodControl._connect', return_value=None)
|
|
16
|
+
def test_decode_description(self, mock_connect):
|
|
17
|
+
"""Verify that _decode_status_response decodes StatusType.DESCRIPTION correctly"""
|
|
18
|
+
# Create a RadiodControl instance (now safe due to mock)
|
|
19
|
+
control = RadiodControl("radiod.local")
|
|
20
|
+
|
|
21
|
+
# Manually set attributes that __init__ might not have set due to mocked _connect
|
|
22
|
+
control.status_mcast_addr = "239.1.1.1"
|
|
23
|
+
control.metrics = MagicMock()
|
|
24
|
+
# Create a dummy status packet with a description
|
|
25
|
+
# Format: Packet Type (0), Tag (4), Length (N), Data (SDR Name)
|
|
26
|
+
description = "AirspyHF+"
|
|
27
|
+
desc_bytes = description.encode('utf-8')
|
|
28
|
+
desc_len = len(desc_bytes)
|
|
29
|
+
|
|
30
|
+
# Construct buffer
|
|
31
|
+
# 0x00: Status packet type
|
|
32
|
+
# 0x04: StatusType.DESCRIPTION
|
|
33
|
+
# desc_len: Length
|
|
34
|
+
# desc_bytes: SDR Name
|
|
35
|
+
# 0xff: StatusType.EOL
|
|
36
|
+
buffer = bytes([0, StatusType.DESCRIPTION, desc_len]) + desc_bytes + bytes([StatusType.EOL])
|
|
37
|
+
|
|
38
|
+
# Decode
|
|
39
|
+
status = control._decode_status_response(buffer)
|
|
40
|
+
|
|
41
|
+
# Verify
|
|
42
|
+
self.assertIn('description', status)
|
|
43
|
+
self.assertEqual(status['description'], description)
|
|
44
|
+
|
|
45
|
+
if __name__ == "__main__":
|
|
46
|
+
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|