@@ -188,18 +188,20 @@ async def transmit_tone(
188188 self ._check_compliance (frequency_hz , occupied_bandwidth_hz = 25_000.0 )
189189 dev = self ._open ()
190190 loop = asyncio .get_running_loop ()
191- # Generate int8 interleaved I/Q for a tone (e.g. 1 kHz at sample_rate)
192- import numpy as np
193- tone_hz = 1000.0
194- num_samples = int (duration_sec * sample_rate )
195- t = np .arange (num_samples , dtype = np .float64 ) / sample_rate
196- i = (127 * 0.3 * np .cos (2 * np .pi * tone_hz * t )).astype (np .int8 )
197- q = (127 * 0.3 * np .sin (2 * np .pi * tone_hz * t )).astype (np .int8 )
198- iq = np .empty (2 * num_samples , dtype = np .int8 )
199- iq [0 ::2 ] = i
200- iq [1 ::2 ] = q
191+ success = False
201192
202193 def _blocking_tx () -> None :
194+ # Generate int8 interleaved I/Q for a tone (e.g. 1 kHz at sample_rate)
195+ # inside the executor to avoid blocking the event loop.
196+ tone_hz = 1000.0
197+ num_samples = int (duration_sec * sample_rate )
198+ t = np .arange (num_samples , dtype = np .float64 ) / sample_rate
199+ i = (127 * 0.3 * np .cos (2 * np .pi * tone_hz * t )).astype (np .int8 )
200+ q = (127 * 0.3 * np .sin (2 * np .pi * tone_hz * t )).astype (np .int8 )
201+ iq = np .empty (2 * num_samples , dtype = np .int8 )
202+ iq [0 ::2 ] = i
203+ iq [1 ::2 ] = q
204+
203205 try :
204206 dev .center_freq = int (frequency_hz )
205207 dev .sample_rate = sample_rate
@@ -210,11 +212,13 @@ def _blocking_tx() -> None:
210212 try :
211213 buf = iq .tobytes ()
212214 stream_hackrf_iq_bytes (dev , buf , duration_sec )
213- except (AttributeError , TypeError , RuntimeError ) as e :
215+ except (AttributeError , TypeError ) as e :
216+ # Stub/API mismatch: skip hardware TX but still allow audit trail to record attempt.
214217 logger .warning ("HackRF TX not available ({}); audit only" , repr (e ))
215218
216219 try :
217220 await loop .run_in_executor (None , _blocking_tx )
221+ success = True
218222 except RuntimeError as e :
219223 msg = str (e )
220224 if "HACKRF_ERROR_LIBUSB" in msg or "libusb" in msg .lower ():
@@ -225,7 +229,7 @@ def _blocking_tx() -> None:
225229 ) from e
226230 raise
227231 finally :
228- self ._audit (frequency_hz , duration_sec , "tone" )
232+ self ._audit (frequency_hz , duration_sec , "tone" , success = success )
229233
230234 async def transmit_iq (
231235 self ,
@@ -254,6 +258,7 @@ async def transmit_iq(
254258 duration_sec = len (iq ) / (2.0 * sample_rate )
255259 dev = self ._open ()
256260 loop = asyncio .get_running_loop ()
261+ success = False
257262
258263 def _blocking_tx () -> None :
259264 try :
@@ -266,11 +271,13 @@ def _blocking_tx() -> None:
266271 try :
267272 buf = iq .tobytes ()
268273 stream_hackrf_iq_bytes (dev , buf , duration_sec )
269- except (AttributeError , TypeError , RuntimeError ) as e :
274+ except (AttributeError , TypeError ) as e :
275+ # Stub/API mismatch: skip hardware TX but still allow audit trail to record attempt.
270276 logger .warning ("HackRF TX not available ({}); audit only" , repr (e ))
271277
272278 try :
273279 await loop .run_in_executor (None , _blocking_tx )
280+ success = True
274281 except RuntimeError as e :
275282 msg = str (e )
276283 if "HACKRF_ERROR_LIBUSB" in msg or "libusb" in msg .lower ():
@@ -281,7 +288,7 @@ def _blocking_tx() -> None:
281288 ) from e
282289 raise
283290 finally :
284- self ._audit (frequency_hz , duration_sec , "iq" )
291+ self ._audit (frequency_hz , duration_sec , "iq" , success = success )
285292
286293
287294class HackRFServiceClient (_ComplianceCheckedTransmitter ):
0 commit comments