Skip to content

Commit 95e889a

Browse files
committed
updated
1 parent f8c0b39 commit 95e889a

File tree

5 files changed

+216
-98
lines changed

5 files changed

+216
-98
lines changed

python_hackrf/pyhackrf_tools/pyhackrf_info.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,24 +62,25 @@ def pyhackrf_info(print_to_console: bool = True, initialize: bool = True) -> Non
6262
else:
6363
print_info += 'No HackRF boards found.'
6464

65+
if initialize:
66+
pyhackrf.pyhackrf_exit()
67+
6568
if print_to_console:
6669
print(print_info)
6770
else:
6871
return print_info
6972

70-
if initialize:
71-
pyhackrf.pyhackrf_exit()
72-
7373

7474
def pyhackrf_serial_numbers_list_info(print_to_console: bool = True, initialize: bool = True) -> None | tuple[int, list]:
7575
if initialize:
7676
pyhackrf.pyhackrf_init()
7777

7878
device_list = pyhackrf.pyhackrf_device_list()
7979

80+
if initialize:
81+
pyhackrf.pyhackrf_exit()
82+
8083
if print_to_console:
8184
print(f'Serial numbers [{device_list.device_count}]: {device_list.serial_numbers}')
8285
else:
8386
return device_list.device_count, device_list.serial_numbers
84-
if initialize:
85-
pyhackrf.pyhackrf_exit()

python_hackrf/pyhackrf_tools/pyhackrf_sweep.pyx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def init_signals():
115115
pass
116116

117117

118-
cdef sweep_callback(buffer: np.ndarray[:], buffer_length: int, valid_length: int):
118+
cdef sweep_callback(device: pyhackrf.PyHackrfDevice, buffer: np.ndarray[:], buffer_length: int, valid_length: int):
119119
global fftSize, window, pwr_1_start, pwr_1_stop, pwr_2_start, pwr_2_stop, norm_factor, data_length, SAMPLE_RATE
120120
global start_frequency, sweep_count, sweep_started, max_num_sweeps, check_max_num_sweeps, accepted_bytes, one_shot_mode, run_available
121121
global binary_output_mode, file_object, queue_mode, SWEEP_STYLE
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
from threading import Event
2+
3+
try:
4+
from jnius import autoclass
5+
except ImportError:
6+
def autoclass(item):
7+
raise RuntimeError('autoclass not available')
8+
9+
try:
10+
from android.broadcast import BroadcastReceiver
11+
except ImportError:
12+
def BroadcastReceiver(item):
13+
raise RuntimeError('BroadcastReceiver not available')
14+
15+
hackrf_usb_vid = 0x1d50
16+
hackrf_usb_pids = (0x604b, 0x6089, 0xcc15)
17+
18+
class USBBroadcastReceiver:
19+
def __init__(self, events):
20+
self.events = events
21+
22+
def start(self):
23+
self.br = BroadcastReceiver(self.on_broadcast, actions=['libusb.android.USB_PERMISSION'])
24+
self.br.start()
25+
26+
def stop(self):
27+
self.br.stop()
28+
29+
def on_broadcast(self, context, intent):
30+
action = intent.getAction()
31+
if action == 'libusb.android.USB_PERMISSION':
32+
UsbManager = autoclass('android.hardware.usb.UsbManager')
33+
usb_device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
34+
granted = intent.getBooleanExtra(autoclass('android.content.Intent').EXTRA_PERMISSION_GRANTED, False)
35+
device_name = usb_device.getDeviceName()
36+
print(device_name, granted)
37+
if device_name in self.events:
38+
self.events[device_name]['granted'] = granted
39+
self.events[device_name]['device'] = usb_device
40+
self.events[device_name]['event'].set()
41+
42+
43+
def get_usb_devices_info(num_devices: int = None):
44+
events = {}
45+
device_file_descriptors = []
46+
47+
usb_broadcast_receiver = USBBroadcastReceiver(events)
48+
49+
Context = autoclass('android.content.Context')
50+
PendingIntent = autoclass('android.app.PendingIntent')
51+
52+
activity = autoclass('org.kivy.android.PythonActivity').mActivity
53+
usb_manager = activity.getSystemService(Context.USB_SERVICE)
54+
permission_intent = 'libusb.android.USB_PERMISSION'
55+
56+
flags = PendingIntent.FLAG_IMMUTABLE
57+
mPermissionIntent = PendingIntent.getBroadcast(activity, 0, autoclass('android.content.Intent')(permission_intent), flags)
58+
59+
device_list = usb_manager.getDeviceList()
60+
if device_list:
61+
for idx, usb_device in enumerate(device_list.values()):
62+
device_name = usb_device.getDeviceName()
63+
if (
64+
usb_device.getVendorId() == hackrf_usb_vid
65+
and usb_device.getProductId() in hackrf_usb_pids
66+
):
67+
68+
if usb_manager.hasPermission(usb_device):
69+
usb_device_connection = usb_manager.openDevice(usb_device)
70+
file_descriptor = usb_device_connection.getFileDescriptor()
71+
device_file_descriptors.append((file_descriptor, usb_device.getProductId(), usb_device.getSerialNumber()))
72+
else:
73+
events[device_name] = {'event': Event(), 'granted': False, 'device': None}
74+
usb_manager.requestPermission(usb_device, mPermissionIntent)
75+
76+
if num_devices is not None and idx + 1 == num_devices:
77+
break
78+
79+
if len(events):
80+
usb_broadcast_receiver.start()
81+
for device_name, info in events.items():
82+
info['event'].wait()
83+
usb_broadcast_receiver.stop()
84+
85+
for device_name, info in events.items():
86+
if info['granted']:
87+
usb_device = info['device']
88+
usb_device_connection = usb_manager.openDevice(usb_device)
89+
file_descriptor = usb_device_connection.getFileDescriptor()
90+
device_file_descriptors.append((file_descriptor, usb_device.getProductId(), usb_device.getSerialNumber()))
91+
92+
return device_file_descriptors

python_hackrf/pylibhackrf/pyhackrf.pyx

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -74,18 +74,18 @@ cdef dict operacake_ports = {
7474
cdef int __rx_callback(chackrf.hackrf_transfer* transfer) nogil:
7575
global global_callbacks
7676
with gil:
77-
np_buffer = np.asarray(<uint8_t[:transfer.buffer_length]>transfer.buffer) # type: ignore
77+
np_buffer = np.asarray(<uint8_t[:transfer.buffer_length]> transfer.buffer) # type: ignore
7878
if global_callbacks[<size_t> transfer.device]['__rx_callback'] is not None:
79-
result = global_callbacks[<size_t> transfer.device]['__rx_callback'](np_buffer, transfer.buffer_length, transfer.valid_length)
79+
result = global_callbacks[<size_t> transfer.device]['__rx_callback'](global_callbacks[<size_t> transfer.device]['device'], np_buffer, transfer.buffer_length, transfer.valid_length)
8080
return result
8181
return -1
8282

8383
cdef int __tx_callback(chackrf.hackrf_transfer* transfer) nogil:
8484
global global_callbacks
8585
with gil:
86-
np_buffer = np.asarray(<uint8_t[:transfer.buffer_length]>transfer.buffer) # type: ignore
86+
np_buffer = np.asarray(<uint8_t[:transfer.buffer_length]> transfer.buffer) # type: ignore
8787
if global_callbacks[<size_t> transfer.device]['__tx_callback'] is not None:
88-
result, buffer, valid_length = global_callbacks[<size_t> transfer.device]['__tx_callback'](np_buffer, transfer.buffer_length, transfer.valid_length)
88+
result, buffer, valid_length = global_callbacks[<size_t> transfer.device]['__tx_callback'](global_callbacks[<size_t> transfer.device]['device'], np_buffer, transfer.buffer_length, transfer.valid_length)
8989

9090
for i in range(valid_length):
9191
transfer.buffer[i] = buffer[i]
@@ -97,24 +97,25 @@ cdef int __tx_callback(chackrf.hackrf_transfer* transfer) nogil:
9797
cdef int __sweep_callback(chackrf.hackrf_transfer* transfer) nogil:
9898
global global_callbacks
9999
with gil:
100-
np_buffer = np.asarray(<uint8_t[:transfer.buffer_length]>transfer.buffer) # type: ignore
100+
np_buffer = np.asarray(<uint8_t[:transfer.buffer_length]> transfer.buffer) # type: ignore
101101
if global_callbacks[<size_t> transfer.device]['__sweep_callback'] is not None:
102-
result = global_callbacks[<size_t> transfer.device]['__sweep_callback'](np_buffer, transfer.buffer_length, transfer.valid_length)
102+
result = global_callbacks[<size_t> transfer.device]['__sweep_callback'](global_callbacks[<size_t> transfer.device]['device'], np_buffer, transfer.buffer_length, transfer.valid_length)
103103
return result
104104
return -1
105105

106106
cdef void __tx_complete_callback(chackrf.hackrf_transfer* transfer, int success) nogil:
107107
global global_callbacks
108108
with gil:
109-
np_buffer = np.asarray(<uint8_t[:transfer.buffer_length]>transfer.buffer) # type: ignore
109+
np_buffer = np.asarray(<uint8_t[:transfer.buffer_length]> transfer.buffer) # type: ignore
110110
if global_callbacks[<size_t> transfer.device]['__tx_complete_callback'] is not None:
111-
global_callbacks[<size_t> transfer.device]['__tx_complete_callback'](np_buffer, transfer.buffer_length, transfer.valid_length, success)
111+
global_callbacks[<size_t> transfer.device]['__tx_complete_callback'](global_callbacks[<size_t> transfer.device]['device'], np_buffer, transfer.buffer_length, transfer.valid_length, success)
112112

113113
cdef void __tx_flush_callback(void* flush_ctx, int success) nogil:
114114
global global_callbacks
115+
cdef size_t device_ptr = <size_t> flush_ctx
115116
with gil:
116-
if global_callbacks['__tx_flush_callback'] is not None:
117-
global_callbacks['__tx_flush_callback'](success)
117+
if global_callbacks[device_ptr]['__tx_flush_callback'] is not None:
118+
global_callbacks[device_ptr]['__tx_flush_callback'](global_callbacks[device_ptr]['device'], success)
118119

119120

120121
cdef class PyHackRFDeviceList:
@@ -182,13 +183,14 @@ cdef class PyHackrfDevice:
182183
global global_callbacks
183184

184185
if self.__hackrf_device is not NULL:
185-
global_callbacks[<size_t>self.__hackrf_device] = {
186+
global_callbacks[<size_t> self.__hackrf_device] = {
186187
'__rx_callback': None,
187188
'__tx_callback': None,
188189
'__sweep_callback': None,
189190
'__tx_complete_callback': None,
191+
'__tx_flush_callback': None,
192+
'device': self,
190193
}
191-
global_callbacks['__tx_flush_callback'] = None
192194
return
193195

194196
raise RuntimeError(f'_setup_callbacks() failed: Device not initialized!')
@@ -342,7 +344,7 @@ cdef class PyHackrfDevice:
342344
) -> None:
343345

344346
cdef uint16_t* frequencies
345-
frequencies = <uint16_t*>malloc(chackrf.MAX_SWEEP_RANGES * 2 * sizeof(uint16_t))
347+
frequencies = <uint16_t*> malloc(chackrf.MAX_SWEEP_RANGES * 2 * sizeof(uint16_t))
346348

347349
for index, frequency in enumerate(frequency_list):
348350
frequencies[index] = frequency
@@ -392,7 +394,7 @@ cdef class PyHackrfDevice:
392394
raise RuntimeError(f'pyhackrf_set_tx_block_complete_callback() failed: {chackrf.hackrf_error_name(result).decode("utf-8")} ({result})')
393395

394396
def pyhackrf_enable_tx_flush(self) -> None:
395-
result = chackrf.hackrf_enable_tx_flush(self.__hackrf_device, __tx_flush_callback, NULL)
397+
result = chackrf.hackrf_enable_tx_flush(self.__hackrf_device, __tx_flush_callback, <void*> self.__hackrf_device)
396398
if result != chackrf.hackrf_error.HACKRF_SUCCESS:
397399
raise RuntimeError(f'pyhackrf_enable_tx_flush() failed: {chackrf.hackrf_error_name(result).decode("utf-8")} ({result})')
398400

@@ -459,74 +461,74 @@ cdef class PyHackrfDevice:
459461
def set_rx_callback(self, rx_callback_function) -> None:
460462
global global_callbacks
461463
"""
462-
Accept a 3 args that contains the buffer, the maximum length and the length of the buffer data.
463-
buffer: numpy.array(dtype=numpy.uint8), buffer_length: int, valid_length: int
464+
Accept a 4 args that contains the device, buffer, the maximum length and the length of the buffer data.
465+
device: PyHackrfDevice, buffer: numpy.array(dtype=numpy.uint8), buffer_length: int, valid_length: int
464466

465-
Should copy/process the contents of the transfer buffer's valid part.
467+
Should copy/process the contents of the buffer's valid part.
466468

467469
The callback should return 0 if it wants to be called again, and any other value otherwise.
468470
"""
469471
if self.__hackrf_device is not NULL:
470-
global_callbacks[<size_t>self.__hackrf_device]['__rx_callback'] = rx_callback_function
472+
global_callbacks[<size_t> self.__hackrf_device]['__rx_callback'] = rx_callback_function
471473
return
472474

473475
raise RuntimeError(f'set_rx_callback() failed: Device not initialized!')
474476

475477
def set_tx_callback(self, tx_callback_function) -> None:
476478
global global_callbacks
477479
"""
478-
Accept a 3 args that contains the buffer, the maximum length and the length of the buffer data.
479-
buffer: numpy.array(dtype=numpy.uint8), buffer_length: int, valid_length: int
480+
Accept a 4 args that contains the device, buffer, the maximum length and the length of the buffer data.
481+
device: PyHackrfDevice, buffer: numpy.array(dtype=numpy.uint8), buffer_length: int, valid_length: int
480482

481483

482484
The callback should return 0 if it wants to be called again, and any other value otherwise, numpy array(buffer) and new valid_length
483485
"""
484486
if self.__hackrf_device is not NULL:
485-
global_callbacks[<size_t>self.__hackrf_device]['__tx_callback'] = tx_callback_function
487+
global_callbacks[<size_t> self.__hackrf_device]['__tx_callback'] = tx_callback_function
486488
return
487489

488490
raise RuntimeError(f'set_tx_callback() failed: Device not initialized!')
489491

490492
def set_sweep_callback(self, sweep_callback_function) -> None:
491493
global global_callbacks
492494
"""
493-
Accept a 3 args that contains the buffer, the maximum length and the length of the buffer data.
494-
buffer: numpy.array(dtype=numpy.uint8), buffer_length: int, valid_length: int
495+
Accept a 4 args that contains the device, buffer, the maximum length and the length of the buffer data.
496+
device: PyHackrfDevice, buffer: numpy.array(dtype=numpy.uint8), buffer_length: int, valid_length: int
495497

496-
Must copy/process the contents of a valid portion of the send buffer.
498+
Should copy/process the contents of the buffer's valid part.
497499

498500
The callback should return 0 if it wants to be called again, and any other value otherwise.
499501
* In this mode, with one data transfer (one callback call)
500502
"""
501503
if self.__hackrf_device is not NULL:
502-
global_callbacks[<size_t>self.__hackrf_device]['__sweep_callback'] = sweep_callback_function
504+
global_callbacks[<size_t> self.__hackrf_device]['__sweep_callback'] = sweep_callback_function
503505
return
504506

505507
raise RuntimeError(f'set_sweep_callback() failed: Device not initialized!')
506508

507509
def set_tx_complete_callback(self, tx_complete_callback_function) -> None:
508510
global global_callbacks
509511
"""
510-
Accept a 4 args that contains the buffer, the maximum length and the length of the buffer data.
511-
buffer: numpy.array(dtype=numpy.uint8), buffer_length: int, valid_length: int
512+
Accept a 5 args that contains the device, buffer, the maximum length and the length of the buffer data.
513+
device: PyHackrfDevice, buffer: numpy.array(dtype=numpy.uint8), buffer_length: int, valid_length: int
512514
and
513515
success: int # if the transfer was successful or not
514516
"""
515517
if self.__hackrf_device is not NULL:
516-
global_callbacks[<size_t>self.__hackrf_device]['__tx_complete_callback'] = tx_complete_callback_function
518+
global_callbacks[<size_t> self.__hackrf_device]['__tx_complete_callback'] = tx_complete_callback_function
517519
return
518520

519521
raise RuntimeError(f'set_tx_complete_callback() failed: Device not initialized!')
520522

521523
def set_tx_flush_callback(self, tx_flush_callback_function) -> None:
522524
global global_callbacks
523525
"""
524-
Accept one argument of type int.
526+
Accept 2 args that contains device and success flag
527+
device: PyHackrfDevice, success: int
525528
This callback will be called when all the data was transmitted and all data transfers were completed.
526-
Prameter is success flag.
527529
"""
528530

529-
global_callbacks['__tx_flush_callback'] = tx_flush_callback_function
531+
global_callbacks[<size_t> self.__hackrf_device]['__tx_flush_callback'] = tx_flush_callback_function
530532

531533
# ---- library ---- #
532534
def pyhackrf_get_transfer_buffer_size(self) -> int:
@@ -538,7 +540,7 @@ cdef class PyHackrfDevice:
538540
# ---- operacake ---- #
539541
def pyhackrf_get_operacake_boards(self) -> list:
540542
self.pyoperacakes.clear()
541-
cdef uint8_t* operacakes = <uint8_t*>malloc(8 * sizeof(uint8_t))
543+
cdef uint8_t* operacakes = <uint8_t*> malloc(8 * sizeof(uint8_t))
542544
result = chackrf.hackrf_get_operacake_boards(self.__hackrf_device, &operacakes[0])
543545

544546
if result != chackrf.hackrf_error.HACKRF_SUCCESS:
@@ -577,7 +579,7 @@ cdef class PyHackrfDevice:
577579
raise RuntimeError(f'pyhackrf_set_operacake_ports() failed: {chackrf.hackrf_error_name(result).decode("utf-8")} ({result})')
578580

579581
def pyhackrf_set_operacake_dwell_times(self, dwell_times: list) -> None:
580-
cdef chackrf.hackrf_operacake_dwell_time* _dwell_times = <chackrf.hackrf_operacake_dwell_time*>malloc(PY_HACKRF_OPERACAKE_MAX_DWELL_TIMES * sizeof(chackrf.hackrf_operacake_dwell_time))
582+
cdef chackrf.hackrf_operacake_dwell_time* _dwell_times = <chackrf.hackrf_operacake_dwell_time*> malloc(PY_HACKRF_OPERACAKE_MAX_DWELL_TIMES * sizeof(chackrf.hackrf_operacake_dwell_time))
581583
for index, (dwell, port) in enumerate(dwell_times):
582584
_dwell_times[index].dwell = dwell
583585
_dwell_times[index].port = <uint8_t> operacake_ports[port]
@@ -589,7 +591,7 @@ cdef class PyHackrfDevice:
589591
raise RuntimeError(f'pyhackrf_set_operacake_dwell_times() failed: {chackrf.hackrf_error_name(result).decode("utf-8")} ({result})')
590592

591593
def pyhackrf_set_operacake_freq_ranges(self, freq_ranges: list) -> None:
592-
cdef chackrf.hackrf_operacake_freq_range* _freq_ranges = <chackrf.hackrf_operacake_freq_range*>malloc(PY_HACKRF_OPERACAKE_MAX_FREQ_RANGES * sizeof(chackrf.hackrf_operacake_freq_range))
594+
cdef chackrf.hackrf_operacake_freq_range* _freq_ranges = <chackrf.hackrf_operacake_freq_range*> malloc(PY_HACKRF_OPERACAKE_MAX_FREQ_RANGES * sizeof(chackrf.hackrf_operacake_freq_range))
593595
for index, (port, freq_min, freq_max) in enumerate(freq_ranges):
594596
_freq_ranges[index].freq_min = freq_min
595597
_freq_ranges[index].freq_max = freq_max

0 commit comments

Comments
 (0)