diff --git a/Readme.md b/Readme.md
index bc26669..45a46e1 100644
--- a/Readme.md
+++ b/Readme.md
@@ -9,10 +9,11 @@
- Optimized for only one purpose - to use HackRF as a spectrum analyzer
- All changes in settings restart hackrf_sweep automatically
- Easy retuning
-- hackrf_sweep integrated as a shared library
-- Peak display
+- Peak / Persistent display
+- Frequency allocation bands for EU
- High resolution waterfall plot
- Spur filter - removes spur artifacts from the spectrum
+- hackrf_sweep integrated as a shared library
### Why?
Other software is limited or hard to use
diff --git a/release/hackrf_spectrum_analyzer.zip b/release/hackrf_spectrum_analyzer.zip
index 9b4b71e..6d7df43 100644
Binary files a/release/hackrf_spectrum_analyzer.zip and b/release/hackrf_spectrum_analyzer.zip differ
diff --git a/screenshot.gif b/screenshot.gif
index eb97d17..d1a289d 100644
Binary files a/screenshot.gif and b/screenshot.gif differ
diff --git a/src/hackrf-sweep/.classpath b/src/hackrf-sweep/.classpath
index bf83daf..9ea6aee 100644
--- a/src/hackrf-sweep/.classpath
+++ b/src/hackrf-sweep/.classpath
@@ -8,7 +8,7 @@
-
+
diff --git a/src/hackrf-sweep/.depend b/src/hackrf-sweep/.depend
new file mode 100644
index 0000000..882174a
--- /dev/null
+++ b/src/hackrf-sweep/.depend
@@ -0,0 +1,2 @@
+hackrf_sweep.o: lib/hackrf/host/hackrf-tools/src/hackrf_sweep.c \
+ lib/hackrf/host/hackrf-tools/src/hackrf_sweep.h
diff --git a/src/hackrf-sweep/.gitignore b/src/hackrf-sweep/.gitignore
index f40cdfc..978b009 100644
--- a/src/hackrf-sweep/.gitignore
+++ b/src/hackrf-sweep/.gitignore
@@ -3,4 +3,5 @@
/bin
/build
/obj
-/res
\ No newline at end of file
+/res
+**.jrf
\ No newline at end of file
diff --git a/src/hackrf-sweep/Makefile b/src/hackrf-sweep/Makefile
index 2078f2e..70986d2 100644
--- a/src/hackrf-sweep/Makefile
+++ b/src/hackrf-sweep/Makefile
@@ -7,6 +7,12 @@ BUILD_PATH = obj
#where the resulting release zip will be copied
RELEASE_DIR = ../../release/
+JNA_LIB = lib/hackrf-sweep-jna.jar
+JNA_SWEEP_HEADER = $(CURDIR)/lib/hackrf/host/hackrf-tools/src/hackrf_sweep.h
+LIBUSB_DIR = lib/libusb-1.0.21
+MAIN_JAR = build/lib/hackrf_sweep_spectrum_analyzer.jar
+
+
ARCH_DEFINED = n
ifeq ($(ARCH), x86-64)
ARCH_DEFINED = y
@@ -18,7 +24,6 @@ IS_64BIT = n
endif
-
#SOURCES = \
# lib/hackrf-2017.02.1/host/libhackrf/src/hackrf.c \
# lib/hackrf-2017.02.1/host/hackrf-tools/src/hackrf_sweep.c
@@ -27,7 +32,7 @@ SOURCES = \
lib/hackrf/host/libhackrf/src/hackrf.c \
lib/hackrf/host/hackrf-tools/src/hackrf_sweep.c
-INCLUDE_PATHS = -Ilib/hackrf/host/libhackrf/src -Ilib/libusb-1.0.20/include/libusb-1.0
+INCLUDE_PATHS = -Ilib/hackrf/host/libhackrf/src -I$(LIBUSB_DIR)/include/libusb-1.0
#-Ilib/hackrf-2017.02.1/host/libhackrf/src
@@ -57,10 +62,10 @@ CC = gcc
CXX = g++
ifeq ($(IS_64BIT), y)
- LDPATHS = -L"lib/fftw-3.3.5-dll64" -L"lib/libusb-1.0.20/MinGW64/dll"
+ LDPATHS = -L"lib/fftw-3.3.5-dll64" -L"$(LIBUSB_DIR)/MinGW64/dll"
INCLUDE_PATHS += -Ilib/fftw-3.3.5-dll64
else
- LDPATHS = -L"lib/fftw-3.3.5-dll32" -L"lib/libusb-1.0.20/MinGW32/dll"
+ LDPATHS = -L"lib/fftw-3.3.5-dll32" -L"$(LIBUSB_DIR)/MinGW32/dll"
INCLUDE_PATHS += -Ilib/fftw-3.3.5-dll32
endif
@@ -78,27 +83,25 @@ endif
#paths
#path to build dlls
-OUTPUT_DIR = build/lib/$(LIB_DIR)
+OUTPUT_DLL_DIR = build/lib/$(LIB_DIR)
-JNA_LIB = lib/hackrf-sweep-jna.jar
-JNA_SWEEP_HEADER = $(CURDIR)/lib/hackrf/host/hackrf-tools/src/hackrf_sweep.h
DLL_LIB_PTHREAD = lib/$(LIB_DIR)/libwinpthread-1.dll
DLL_JNA = lib/$(LIB_DIR)/jnidispatch.dll
-DLL_LIB = $(OUTPUT_DIR)/hackrf-sweep.dll
+DLL_LIB = $(OUTPUT_DLL_DIR)/hackrf-sweep.dll
ifeq ($(IS_64BIT), y)
DLL_LIB_FFTW = lib/fftw-3.3.5-dll64/libfftw3f-3.dll
- DLL_LIB_USB = lib/libusb-1.0.20/MinGW64/dll/libusb-1.0.dll
+ DLL_LIB_USB = $(LIBUSB_DIR)/MinGW64/dll/libusb-1.0.dll
else
DLL_LIB_FFTW = lib/fftw-3.3.5-dll32/libfftw3f-3.dll
- DLL_LIB_USB = lib/libusb-1.0.20/MinGW32/dll/libusb-1.0.dll
+ DLL_LIB_USB = $(LIBUSB_DIR)/MinGW32/dll/libusb-1.0.dll
endif
JNAERATOR = $(CURDIR)/lib/jnaerator/jnaerator-0.13-20150328.111636-4-shaded.jar
ZIP_FILE = hackrf_spectrum_analyzer.zip
-ZIP_FILE_PATH = $(OUTPUT_DIR)/../../$(ZIP_FILE)
+ZIP_FILE_PATH = $(OUTPUT_DLL_DIR)/../../$(ZIP_FILE)
.NOTPARALLEL: all
@@ -122,16 +125,16 @@ dirs:
$(ZIP_FILE_PATH): $(DLL_LIB)
mkdir -p $(RELEASE_DIR)
- cd $(OUTPUT_DIR)/../../ && rm -rf $(ZIP_FILE) && zip -r $(ZIP_FILE) *
+ cd $(OUTPUT_DLL_DIR)/../../ && rm -rf $(ZIP_FILE) && zip -r $(ZIP_FILE) *
yes | cp -rf $(ZIP_FILE_PATH) $(RELEASE_DIR)
#cd $(CURDIR)
.PHONY: prepare
prepare: dirs $(OBJECTS) $(DLL_LIB_FFTW)
- mkdir -p $(OUTPUT_DIR)
- cp -f $(DLL_LIB_FFTW) $(DLL_LIB_PTHREAD) $(DLL_JNA) $(DLL_LIB_USB) $(OUTPUT_DIR)
- cp -f lib/zadig_2.2.exe lib/program.ico lib/program.png $(OUTPUT_DIR)/../
+ mkdir -p $(OUTPUT_DLL_DIR)
+ cp -f $(DLL_LIB_FFTW) $(DLL_LIB_PTHREAD) $(DLL_JNA) $(DLL_LIB_USB) $(OUTPUT_DLL_DIR)
+ cp -f lib/zadig_2.2.exe lib/program.ico lib/program.png $(OUTPUT_DLL_DIR)/../
$(DLL_LIB): $(OBJECTS) $(JNA_LIB)
echo "building " $(DLL_LIB)
@@ -153,6 +156,6 @@ $(BUILD_PATH)/%.c.$(OBJECT_SUFFIX): %.c
.PHONY: clean
clean:
- rm -f $(OBJECTS) $(DLL_LIB) #$(JNA_LIB)
- rm -rf $(OUTPUT_DIR) $(BUILD_PATH)
+ rm -f $(MAIN_JAR) $(OBJECTS) $(DLL_LIB) #$(JNA_LIB)
+ rm -rf $(OUTPUT_DLL_DIR) $(BUILD_PATH)
diff --git a/src/hackrf-sweep/lib/libusb-1.0.20/MinGW32/dll/libusb-1.0.dll b/src/hackrf-sweep/lib/libusb-1.0.20/MinGW32/dll/libusb-1.0.dll
deleted file mode 100644
index a2e99dd..0000000
Binary files a/src/hackrf-sweep/lib/libusb-1.0.20/MinGW32/dll/libusb-1.0.dll and /dev/null differ
diff --git a/src/hackrf-sweep/lib/libusb-1.0.20/MinGW64/dll/libusb-1.0.dll b/src/hackrf-sweep/lib/libusb-1.0.20/MinGW64/dll/libusb-1.0.dll
deleted file mode 100644
index 1330ae4..0000000
Binary files a/src/hackrf-sweep/lib/libusb-1.0.20/MinGW64/dll/libusb-1.0.dll and /dev/null differ
diff --git a/src/hackrf-sweep/lib/libusb-1.0.20/MinGW64/static/libusb-1.0.a b/src/hackrf-sweep/lib/libusb-1.0.20/MinGW64/static/libusb-1.0.a
deleted file mode 100644
index 7d3bb7b..0000000
Binary files a/src/hackrf-sweep/lib/libusb-1.0.20/MinGW64/static/libusb-1.0.a and /dev/null differ
diff --git a/src/hackrf-sweep/lib/libusb-1.0.20/libusb-1.0.def b/src/hackrf-sweep/lib/libusb-1.0.20/libusb-1.0.def
deleted file mode 100644
index c0b08a7..0000000
--- a/src/hackrf-sweep/lib/libusb-1.0.20/libusb-1.0.def
+++ /dev/null
@@ -1,168 +0,0 @@
-LIBRARY "libusb-1.0.dll"
-EXPORTS
- libusb_alloc_streams
- libusb_alloc_streams@16 = libusb_alloc_streams
- libusb_alloc_transfer
- libusb_alloc_transfer@4 = libusb_alloc_transfer
- libusb_attach_kernel_driver
- libusb_attach_kernel_driver@8 = libusb_attach_kernel_driver
- libusb_bulk_transfer
- libusb_bulk_transfer@24 = libusb_bulk_transfer
- libusb_cancel_transfer
- libusb_cancel_transfer@4 = libusb_cancel_transfer
- libusb_claim_interface
- libusb_claim_interface@8 = libusb_claim_interface
- libusb_clear_halt
- libusb_clear_halt@8 = libusb_clear_halt
- libusb_close
- libusb_close@4 = libusb_close
- libusb_control_transfer
- libusb_control_transfer@32 = libusb_control_transfer
- libusb_detach_kernel_driver
- libusb_detach_kernel_driver@8 = libusb_detach_kernel_driver
- libusb_error_name
- libusb_error_name@4 = libusb_error_name
- libusb_event_handler_active
- libusb_event_handler_active@4 = libusb_event_handler_active
- libusb_event_handling_ok
- libusb_event_handling_ok@4 = libusb_event_handling_ok
- libusb_exit
- libusb_exit@4 = libusb_exit
- libusb_free_bos_descriptor
- libusb_free_bos_descriptor@4 = libusb_free_bos_descriptor
- libusb_free_config_descriptor
- libusb_free_config_descriptor@4 = libusb_free_config_descriptor
- libusb_free_container_id_descriptor
- libusb_free_container_id_descriptor@4 = libusb_free_container_id_descriptor
- libusb_free_device_list
- libusb_free_device_list@8 = libusb_free_device_list
- libusb_free_ss_endpoint_companion_descriptor
- libusb_free_ss_endpoint_companion_descriptor@4 = libusb_free_ss_endpoint_companion_descriptor
- libusb_free_ss_usb_device_capability_descriptor
- libusb_free_ss_usb_device_capability_descriptor@4 = libusb_free_ss_usb_device_capability_descriptor
- libusb_free_streams
- libusb_free_streams@12 = libusb_free_streams
- libusb_free_transfer
- libusb_free_transfer@4 = libusb_free_transfer
- libusb_free_usb_2_0_extension_descriptor
- libusb_free_usb_2_0_extension_descriptor@4 = libusb_free_usb_2_0_extension_descriptor
- libusb_get_active_config_descriptor
- libusb_get_active_config_descriptor@8 = libusb_get_active_config_descriptor
- libusb_get_bos_descriptor
- libusb_get_bos_descriptor@8 = libusb_get_bos_descriptor
- libusb_get_bus_number
- libusb_get_bus_number@4 = libusb_get_bus_number
- libusb_get_config_descriptor
- libusb_get_config_descriptor@12 = libusb_get_config_descriptor
- libusb_get_config_descriptor_by_value
- libusb_get_config_descriptor_by_value@12 = libusb_get_config_descriptor_by_value
- libusb_get_configuration
- libusb_get_configuration@8 = libusb_get_configuration
- libusb_get_container_id_descriptor
- libusb_get_container_id_descriptor@12 = libusb_get_container_id_descriptor
- libusb_get_device
- libusb_get_device@4 = libusb_get_device
- libusb_get_device_address
- libusb_get_device_address@4 = libusb_get_device_address
- libusb_get_device_descriptor
- libusb_get_device_descriptor@8 = libusb_get_device_descriptor
- libusb_get_device_list
- libusb_get_device_list@8 = libusb_get_device_list
- libusb_get_device_speed
- libusb_get_device_speed@4 = libusb_get_device_speed
- libusb_get_max_iso_packet_size
- libusb_get_max_iso_packet_size@8 = libusb_get_max_iso_packet_size
- libusb_get_max_packet_size
- libusb_get_max_packet_size@8 = libusb_get_max_packet_size
- libusb_get_next_timeout
- libusb_get_next_timeout@8 = libusb_get_next_timeout
- libusb_get_parent
- libusb_get_parent@4 = libusb_get_parent
- libusb_get_pollfds
- libusb_get_pollfds@4 = libusb_get_pollfds
- libusb_free_pollfds
- libusb_free_pollfds@4 = libusb_free_pollfds
- libusb_get_port_number
- libusb_get_port_number@4 = libusb_get_port_number
- libusb_get_port_numbers
- libusb_get_port_numbers@12 = libusb_get_port_numbers
- libusb_get_port_path
- libusb_get_port_path@16 = libusb_get_port_path
- libusb_get_ss_endpoint_companion_descriptor
- libusb_get_ss_endpoint_companion_descriptor@12 = libusb_get_ss_endpoint_companion_descriptor
- libusb_get_ss_usb_device_capability_descriptor
- libusb_get_ss_usb_device_capability_descriptor@12 = libusb_get_ss_usb_device_capability_descriptor
- libusb_get_string_descriptor_ascii
- libusb_get_string_descriptor_ascii@16 = libusb_get_string_descriptor_ascii
- libusb_get_usb_2_0_extension_descriptor
- libusb_get_usb_2_0_extension_descriptor@12 = libusb_get_usb_2_0_extension_descriptor
- libusb_get_version
- libusb_get_version@0 = libusb_get_version
- libusb_handle_events
- libusb_handle_events@4 = libusb_handle_events
- libusb_handle_events_completed
- libusb_handle_events_completed@8 = libusb_handle_events_completed
- libusb_handle_events_locked
- libusb_handle_events_locked@8 = libusb_handle_events_locked
- libusb_handle_events_timeout
- libusb_handle_events_timeout@8 = libusb_handle_events_timeout
- libusb_handle_events_timeout_completed
- libusb_handle_events_timeout_completed@12 = libusb_handle_events_timeout_completed
- libusb_has_capability
- libusb_has_capability@4 = libusb_has_capability
- libusb_hotplug_deregister_callback
- libusb_hotplug_deregister_callback@8 = libusb_hotplug_deregister_callback
- libusb_hotplug_register_callback
- libusb_hotplug_register_callback@36 = libusb_hotplug_register_callback
- libusb_init
- libusb_init@4 = libusb_init
- libusb_interrupt_transfer
- libusb_interrupt_transfer@24 = libusb_interrupt_transfer
- libusb_kernel_driver_active
- libusb_kernel_driver_active@8 = libusb_kernel_driver_active
- libusb_lock_event_waiters
- libusb_lock_event_waiters@4 = libusb_lock_event_waiters
- libusb_lock_events
- libusb_lock_events@4 = libusb_lock_events
- libusb_open
- libusb_open@8 = libusb_open
- libusb_open_device_with_vid_pid
- libusb_open_device_with_vid_pid@12 = libusb_open_device_with_vid_pid
- libusb_pollfds_handle_timeouts
- libusb_pollfds_handle_timeouts@4 = libusb_pollfds_handle_timeouts
- libusb_ref_device
- libusb_ref_device@4 = libusb_ref_device
- libusb_release_interface
- libusb_release_interface@8 = libusb_release_interface
- libusb_reset_device
- libusb_reset_device@4 = libusb_reset_device
- libusb_set_auto_detach_kernel_driver
- libusb_set_auto_detach_kernel_driver@8 = libusb_set_auto_detach_kernel_driver
- libusb_set_configuration
- libusb_set_configuration@8 = libusb_set_configuration
- libusb_set_debug
- libusb_set_debug@8 = libusb_set_debug
- libusb_set_interface_alt_setting
- libusb_set_interface_alt_setting@12 = libusb_set_interface_alt_setting
- libusb_set_pollfd_notifiers
- libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers
- libusb_setlocale
- libusb_setlocale@4 = libusb_setlocale
- libusb_strerror
- libusb_strerror@4 = libusb_strerror
- libusb_submit_transfer
- libusb_submit_transfer@4 = libusb_submit_transfer
- libusb_transfer_get_stream_id
- libusb_transfer_get_stream_id@4 = libusb_transfer_get_stream_id
- libusb_transfer_set_stream_id
- libusb_transfer_set_stream_id@8 = libusb_transfer_set_stream_id
- libusb_try_lock_events
- libusb_try_lock_events@4 = libusb_try_lock_events
- libusb_unlock_event_waiters
- libusb_unlock_event_waiters@4 = libusb_unlock_event_waiters
- libusb_unlock_events
- libusb_unlock_events@4 = libusb_unlock_events
- libusb_unref_device
- libusb_unref_device@4 = libusb_unref_device
- libusb_wait_for_event
- libusb_wait_for_event@8 = libusb_wait_for_event
diff --git a/src/hackrf-sweep/lib/libusb-1.0.21/MinGW32/dll/libusb-1.0.dll b/src/hackrf-sweep/lib/libusb-1.0.21/MinGW32/dll/libusb-1.0.dll
new file mode 100644
index 0000000..a9803c1
Binary files /dev/null and b/src/hackrf-sweep/lib/libusb-1.0.21/MinGW32/dll/libusb-1.0.dll differ
diff --git a/src/hackrf-sweep/lib/libusb-1.0.20/MinGW32/dll/libusb-1.0.dll.a b/src/hackrf-sweep/lib/libusb-1.0.21/MinGW32/dll/libusb-1.0.dll.a
similarity index 71%
rename from src/hackrf-sweep/lib/libusb-1.0.20/MinGW32/dll/libusb-1.0.dll.a
rename to src/hackrf-sweep/lib/libusb-1.0.21/MinGW32/dll/libusb-1.0.dll.a
index 5131b51..fc6c5eb 100644
Binary files a/src/hackrf-sweep/lib/libusb-1.0.20/MinGW32/dll/libusb-1.0.dll.a and b/src/hackrf-sweep/lib/libusb-1.0.21/MinGW32/dll/libusb-1.0.dll.a differ
diff --git a/src/hackrf-sweep/lib/libusb-1.0.21/MinGW32/static/libusb-1.0.a b/src/hackrf-sweep/lib/libusb-1.0.21/MinGW32/static/libusb-1.0.a
new file mode 100644
index 0000000..c6120a3
Binary files /dev/null and b/src/hackrf-sweep/lib/libusb-1.0.21/MinGW32/static/libusb-1.0.a differ
diff --git a/src/hackrf-sweep/lib/libusb-1.0.21/MinGW64/dll/libusb-1.0.dll b/src/hackrf-sweep/lib/libusb-1.0.21/MinGW64/dll/libusb-1.0.dll
new file mode 100644
index 0000000..f02d3b7
Binary files /dev/null and b/src/hackrf-sweep/lib/libusb-1.0.21/MinGW64/dll/libusb-1.0.dll differ
diff --git a/src/hackrf-sweep/lib/libusb-1.0.20/MinGW64/dll/libusb-1.0.dll.a b/src/hackrf-sweep/lib/libusb-1.0.21/MinGW64/dll/libusb-1.0.dll.a
similarity index 74%
rename from src/hackrf-sweep/lib/libusb-1.0.20/MinGW64/dll/libusb-1.0.dll.a
rename to src/hackrf-sweep/lib/libusb-1.0.21/MinGW64/dll/libusb-1.0.dll.a
index 66bae34..86b67a5 100644
Binary files a/src/hackrf-sweep/lib/libusb-1.0.20/MinGW64/dll/libusb-1.0.dll.a and b/src/hackrf-sweep/lib/libusb-1.0.21/MinGW64/dll/libusb-1.0.dll.a differ
diff --git a/src/hackrf-sweep/lib/libusb-1.0.21/MinGW64/static/libusb-1.0.a b/src/hackrf-sweep/lib/libusb-1.0.21/MinGW64/static/libusb-1.0.a
new file mode 100644
index 0000000..847c130
Binary files /dev/null and b/src/hackrf-sweep/lib/libusb-1.0.21/MinGW64/static/libusb-1.0.a differ
diff --git a/src/hackrf-sweep/lib/libusb-1.0.20/README.txt b/src/hackrf-sweep/lib/libusb-1.0.21/README.txt
similarity index 98%
rename from src/hackrf-sweep/lib/libusb-1.0.20/README.txt
rename to src/hackrf-sweep/lib/libusb-1.0.21/README.txt
index 6231f6b..2ad8395 100644
--- a/src/hackrf-sweep/lib/libusb-1.0.20/README.txt
+++ b/src/hackrf-sweep/lib/libusb-1.0.21/README.txt
@@ -1,61 +1,61 @@
- libusb 1.0 Windows binary snapshot - README
-
- *********************************************************************
- * The latest version of this snapshot can always be downloaded at: *
- * https://sourceforge.net/projects/libusb/files/ *
- *********************************************************************
-
-o Visual Studio:
- - Open existing or create a new project for your application
- - Copy libusb.h, from the include\libusb-1.0\ directory, into your project and
- make sure that the location where the file reside appears in the 'Additional
- Include Directories' section (Configuration Properties -> C/C++ -> General).
- - Copy the relevant .lib file from MS32\ or MS64\ and add 'libusb-1.0.lib' to
- your 'Additional Dependencies' (Configuration Properties -> Linker -> Input)
- Also make sure that the directory where libusb-1.0.lib resides is added to
- 'Additional Library Directories' (Configuration Properties -> Linker
- -> General)
- - If you use the static version of the libusb library, make sure that
- 'Runtime Library' is set to 'Multi-threaded DLL (/MD)' (Configuration
- Properties -> C/C++ -> Code Generation).
- NB: If your application requires /MT (Multi-threaded/libCMT), you need to
- recompile a static libusb 1.0 library from source.
- - Compile and run your application. If you use the DLL version of libusb-1.0,
- remember that you need to have a copy of the DLL either in the runtime
- directory or in system32
-
-o WDK/DDK:
- - The following is an example of a sources files that you can use to compile
- a libusb 1.0 based console application. In this sample ..\libusb\ is the
- directory where you would have copied libusb.h as well as the relevant
- libusb-1.0.lib
-
- TARGETNAME=your_app
- TARGETTYPE=PROGRAM
- USE_MSVCRT=1
- UMTYPE=console
- INCLUDES=..\libusb;$(DDK_INC_PATH)
- TARGETLIBS=..\libusb\libusb-1.0.lib
- SOURCES=your_app.c
-
- - Note that if you plan to use libCMT instead of MSVCRT (USE_LIBCMT=1 instead
- of USE_MSVCRT=1), you will need to recompile libusb to use libCMT. This can
- easily be achieved, in the DDK environment, by running 'ddk_build /MT'
-
-o MinGW/cygwin
- - Copy libusb.h, from include/libusb-1.0/ to your default include directory,
- and copy the MinGW32/ or MinGW64/ .a files to your default library directory.
- Or, if you don't want to use the default locations, make sure that you feed
- the relevant -I and -L options to the compiler.
- - Add the '-lusb-1.0' linker option when compiling.
-
-o Additional information:
- - The libusb 1.0 API documentation can be accessed at:
- http://api.libusb.info
- - For some libusb samples (including source), please have a look in examples/
- - For additional information on the libusb 1.0 Windows backend please visit:
- http://windows.libusb.info
- - The MinGW and MS generated DLLs are fully interchangeable, provided that you
- use the import libs provided or generate one from the .def also provided.
- - If you find any issue, please visit http://libusb.info/ and check the
- Support section
+ libusb 1.0 Windows binary snapshot - README
+
+ *********************************************************************
+ * The latest version of this snapshot can always be downloaded at: *
+ * https://sourceforge.net/projects/libusb/files/ *
+ *********************************************************************
+
+o Visual Studio:
+ - Open existing or create a new project for your application
+ - Copy libusb.h, from the include\libusb-1.0\ directory, into your project and
+ make sure that the location where the file reside appears in the 'Additional
+ Include Directories' section (Configuration Properties -> C/C++ -> General).
+ - Copy the relevant .lib file from MS32\ or MS64\ and add 'libusb-1.0.lib' to
+ your 'Additional Dependencies' (Configuration Properties -> Linker -> Input)
+ Also make sure that the directory where libusb-1.0.lib resides is added to
+ 'Additional Library Directories' (Configuration Properties -> Linker
+ -> General)
+ - If you use the static version of the libusb library, make sure that
+ 'Runtime Library' is set to 'Multi-threaded DLL (/MD)' (Configuration
+ Properties -> C/C++ -> Code Generation).
+ NB: If your application requires /MT (Multi-threaded/libCMT), you need to
+ recompile a static libusb 1.0 library from source.
+ - Compile and run your application. If you use the DLL version of libusb-1.0,
+ remember that you need to have a copy of the DLL either in the runtime
+ directory or in system32
+
+o WDK/DDK:
+ - The following is an example of a sources files that you can use to compile
+ a libusb 1.0 based console application. In this sample ..\libusb\ is the
+ directory where you would have copied libusb.h as well as the relevant
+ libusb-1.0.lib
+
+ TARGETNAME=your_app
+ TARGETTYPE=PROGRAM
+ USE_MSVCRT=1
+ UMTYPE=console
+ INCLUDES=..\libusb;$(DDK_INC_PATH)
+ TARGETLIBS=..\libusb\libusb-1.0.lib
+ SOURCES=your_app.c
+
+ - Note that if you plan to use libCMT instead of MSVCRT (USE_LIBCMT=1 instead
+ of USE_MSVCRT=1), you will need to recompile libusb to use libCMT. This can
+ easily be achieved, in the DDK environment, by running 'ddk_build /MT'
+
+o MinGW/cygwin
+ - Copy libusb.h, from include/libusb-1.0/ to your default include directory,
+ and copy the MinGW32/ or MinGW64/ .a files to your default library directory.
+ Or, if you don't want to use the default locations, make sure that you feed
+ the relevant -I and -L options to the compiler.
+ - Add the '-lusb-1.0' linker option when compiling.
+
+o Additional information:
+ - The libusb 1.0 API documentation can be accessed at:
+ http://api.libusb.info
+ - For some libusb samples (including source), please have a look in examples/
+ - For additional information on the libusb 1.0 Windows backend please visit:
+ http://windows.libusb.info
+ - The MinGW and MS generated DLLs are fully interchangeable, provided that you
+ use the import libs provided or generate one from the .def also provided.
+ - If you find any issue, please visit http://libusb.info/ and check the
+ Support section
diff --git a/src/hackrf-sweep/lib/libusb-1.0.20/include/libusb-1.0/libusb.h b/src/hackrf-sweep/lib/libusb-1.0.21/include/libusb-1.0/libusb.h
similarity index 94%
rename from src/hackrf-sweep/lib/libusb-1.0.20/include/libusb-1.0/libusb.h
rename to src/hackrf-sweep/lib/libusb-1.0.21/include/libusb-1.0/libusb.h
index c165a76..f73e31c 100644
--- a/src/hackrf-sweep/lib/libusb-1.0.20/include/libusb-1.0/libusb.h
+++ b/src/hackrf-sweep/lib/libusb-1.0.21/include/libusb-1.0/libusb.h
@@ -1,1999 +1,2008 @@
-/*
- * Public libusb header file
- * Copyright © 2001 Johannes Erdfelt
- * Copyright © 2007-2008 Daniel Drake
- * Copyright © 2012 Pete Batard
- * Copyright © 2012 Nathan Hjelm
- * For more information, please visit: http://libusb.info
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef LIBUSB_H
-#define LIBUSB_H
-
-#ifdef _MSC_VER
-/* on MS environments, the inline keyword is available in C++ only */
-#if !defined(__cplusplus)
-#define inline __inline
-#endif
-/* ssize_t is also not available (copy/paste from MinGW) */
-#ifndef _SSIZE_T_DEFINED
-#define _SSIZE_T_DEFINED
-#undef ssize_t
-#ifdef _WIN64
- typedef __int64 ssize_t;
-#else
- typedef int ssize_t;
-#endif /* _WIN64 */
-#endif /* _SSIZE_T_DEFINED */
-#endif /* _MSC_VER */
-
-/* stdint.h is not available on older MSVC */
-#if defined(_MSC_VER) && (_MSC_VER < 1600) && (!defined(_STDINT)) && (!defined(_STDINT_H))
-typedef unsigned __int8 uint8_t;
-typedef unsigned __int16 uint16_t;
-typedef unsigned __int32 uint32_t;
-#else
-#include
-#endif
-
-#if !defined(_WIN32_WCE)
-#include
-#endif
-
-#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__HAIKU__)
-#include
-#endif
-
-#include
-#include
-
-/* 'interface' might be defined as a macro on Windows, so we need to
- * undefine it so as not to break the current libusb API, because
- * libusb_config_descriptor has an 'interface' member
- * As this can be problematic if you include windows.h after libusb.h
- * in your sources, we force windows.h to be included first. */
-#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
-#include
-#if defined(interface)
-#undef interface
-#endif
-#if !defined(__CYGWIN__)
-#include
-#endif
-#endif
-
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
-#define LIBUSB_DEPRECATED_FOR(f) \
- __attribute__((deprecated("Use " #f " instead")))
-#else
-#define LIBUSB_DEPRECATED_FOR(f)
-#endif /* __GNUC__ */
-
-/** \def LIBUSB_CALL
- * \ingroup misc
- * libusb's Windows calling convention.
- *
- * Under Windows, the selection of available compilers and configurations
- * means that, unlike other platforms, there is not one true calling
- * convention (calling convention: the manner in which parameters are
- * passed to functions in the generated assembly code).
- *
- * Matching the Windows API itself, libusb uses the WINAPI convention (which
- * translates to the stdcall convention) and guarantees that the
- * library is compiled in this way. The public header file also includes
- * appropriate annotations so that your own software will use the right
- * convention, even if another convention is being used by default within
- * your codebase.
- *
- * The one consideration that you must apply in your software is to mark
- * all functions which you use as libusb callbacks with this LIBUSB_CALL
- * annotation, so that they too get compiled for the correct calling
- * convention.
- *
- * On non-Windows operating systems, this macro is defined as nothing. This
- * means that you can apply it to your code without worrying about
- * cross-platform compatibility.
- */
-/* LIBUSB_CALL must be defined on both definition and declaration of libusb
- * functions. You'd think that declaration would be enough, but cygwin will
- * complain about conflicting types unless both are marked this way.
- * The placement of this macro is important too; it must appear after the
- * return type, before the function name. See internal documentation for
- * API_EXPORTED.
- */
-#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
-#define LIBUSB_CALL WINAPI
-#else
-#define LIBUSB_CALL
-#endif
-
-/** \def LIBUSB_API_VERSION
- * \ingroup misc
- * libusb's API version.
- *
- * Since version 1.0.13, to help with feature detection, libusb defines
- * a LIBUSB_API_VERSION macro that gets increased every time there is a
- * significant change to the API, such as the introduction of a new call,
- * the definition of a new macro/enum member, or any other element that
- * libusb applications may want to detect at compilation time.
- *
- * The macro is typically used in an application as follows:
- * \code
- * #if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01001234)
- * // Use one of the newer features from the libusb API
- * #endif
- * \endcode
- *
- * Internally, LIBUSB_API_VERSION is defined as follows:
- * (libusb major << 24) | (libusb minor << 16) | (16 bit incremental)
- */
-#define LIBUSB_API_VERSION 0x01000104
-
-/* The following is kept for compatibility, but will be deprecated in the future */
-#define LIBUSBX_API_VERSION LIBUSB_API_VERSION
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * \ingroup misc
- * Convert a 16-bit value from host-endian to little-endian format. On
- * little endian systems, this function does nothing. On big endian systems,
- * the bytes are swapped.
- * \param x the host-endian value to convert
- * \returns the value in little-endian byte order
- */
-static inline uint16_t libusb_cpu_to_le16(const uint16_t x)
-{
- union {
- uint8_t b8[2];
- uint16_t b16;
- } _tmp;
- _tmp.b8[1] = (uint8_t) (x >> 8);
- _tmp.b8[0] = (uint8_t) (x & 0xff);
- return _tmp.b16;
-}
-
-/** \def libusb_le16_to_cpu
- * \ingroup misc
- * Convert a 16-bit value from little-endian to host-endian format. On
- * little endian systems, this function does nothing. On big endian systems,
- * the bytes are swapped.
- * \param x the little-endian value to convert
- * \returns the value in host-endian byte order
- */
-#define libusb_le16_to_cpu libusb_cpu_to_le16
-
-/* standard USB stuff */
-
-/** \ingroup desc
- * Device and/or Interface Class codes */
-enum libusb_class_code {
- /** In the context of a \ref libusb_device_descriptor "device descriptor",
- * this bDeviceClass value indicates that each interface specifies its
- * own class information and all interfaces operate independently.
- */
- LIBUSB_CLASS_PER_INTERFACE = 0,
-
- /** Audio class */
- LIBUSB_CLASS_AUDIO = 1,
-
- /** Communications class */
- LIBUSB_CLASS_COMM = 2,
-
- /** Human Interface Device class */
- LIBUSB_CLASS_HID = 3,
-
- /** Physical */
- LIBUSB_CLASS_PHYSICAL = 5,
-
- /** Printer class */
- LIBUSB_CLASS_PRINTER = 7,
-
- /** Image class */
- LIBUSB_CLASS_PTP = 6, /* legacy name from libusb-0.1 usb.h */
- LIBUSB_CLASS_IMAGE = 6,
-
- /** Mass storage class */
- LIBUSB_CLASS_MASS_STORAGE = 8,
-
- /** Hub class */
- LIBUSB_CLASS_HUB = 9,
-
- /** Data class */
- LIBUSB_CLASS_DATA = 10,
-
- /** Smart Card */
- LIBUSB_CLASS_SMART_CARD = 0x0b,
-
- /** Content Security */
- LIBUSB_CLASS_CONTENT_SECURITY = 0x0d,
-
- /** Video */
- LIBUSB_CLASS_VIDEO = 0x0e,
-
- /** Personal Healthcare */
- LIBUSB_CLASS_PERSONAL_HEALTHCARE = 0x0f,
-
- /** Diagnostic Device */
- LIBUSB_CLASS_DIAGNOSTIC_DEVICE = 0xdc,
-
- /** Wireless class */
- LIBUSB_CLASS_WIRELESS = 0xe0,
-
- /** Application class */
- LIBUSB_CLASS_APPLICATION = 0xfe,
-
- /** Class is vendor-specific */
- LIBUSB_CLASS_VENDOR_SPEC = 0xff
-};
-
-/** \ingroup desc
- * Descriptor types as defined by the USB specification. */
-enum libusb_descriptor_type {
- /** Device descriptor. See libusb_device_descriptor. */
- LIBUSB_DT_DEVICE = 0x01,
-
- /** Configuration descriptor. See libusb_config_descriptor. */
- LIBUSB_DT_CONFIG = 0x02,
-
- /** String descriptor */
- LIBUSB_DT_STRING = 0x03,
-
- /** Interface descriptor. See libusb_interface_descriptor. */
- LIBUSB_DT_INTERFACE = 0x04,
-
- /** Endpoint descriptor. See libusb_endpoint_descriptor. */
- LIBUSB_DT_ENDPOINT = 0x05,
-
- /** BOS descriptor */
- LIBUSB_DT_BOS = 0x0f,
-
- /** Device Capability descriptor */
- LIBUSB_DT_DEVICE_CAPABILITY = 0x10,
-
- /** HID descriptor */
- LIBUSB_DT_HID = 0x21,
-
- /** HID report descriptor */
- LIBUSB_DT_REPORT = 0x22,
-
- /** Physical descriptor */
- LIBUSB_DT_PHYSICAL = 0x23,
-
- /** Hub descriptor */
- LIBUSB_DT_HUB = 0x29,
-
- /** SuperSpeed Hub descriptor */
- LIBUSB_DT_SUPERSPEED_HUB = 0x2a,
-
- /** SuperSpeed Endpoint Companion descriptor */
- LIBUSB_DT_SS_ENDPOINT_COMPANION = 0x30
-};
-
-/* Descriptor sizes per descriptor type */
-#define LIBUSB_DT_DEVICE_SIZE 18
-#define LIBUSB_DT_CONFIG_SIZE 9
-#define LIBUSB_DT_INTERFACE_SIZE 9
-#define LIBUSB_DT_ENDPOINT_SIZE 7
-#define LIBUSB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
-#define LIBUSB_DT_HUB_NONVAR_SIZE 7
-#define LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE 6
-#define LIBUSB_DT_BOS_SIZE 5
-#define LIBUSB_DT_DEVICE_CAPABILITY_SIZE 3
-
-/* BOS descriptor sizes */
-#define LIBUSB_BT_USB_2_0_EXTENSION_SIZE 7
-#define LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE 10
-#define LIBUSB_BT_CONTAINER_ID_SIZE 20
-
-/* We unwrap the BOS => define its max size */
-#define LIBUSB_DT_BOS_MAX_SIZE ((LIBUSB_DT_BOS_SIZE) +\
- (LIBUSB_BT_USB_2_0_EXTENSION_SIZE) +\
- (LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) +\
- (LIBUSB_BT_CONTAINER_ID_SIZE))
-
-#define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */
-#define LIBUSB_ENDPOINT_DIR_MASK 0x80
-
-/** \ingroup desc
- * Endpoint direction. Values for bit 7 of the
- * \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme.
- */
-enum libusb_endpoint_direction {
- /** In: device-to-host */
- LIBUSB_ENDPOINT_IN = 0x80,
-
- /** Out: host-to-device */
- LIBUSB_ENDPOINT_OUT = 0x00
-};
-
-#define LIBUSB_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */
-
-/** \ingroup desc
- * Endpoint transfer type. Values for bits 0:1 of the
- * \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field.
- */
-enum libusb_transfer_type {
- /** Control endpoint */
- LIBUSB_TRANSFER_TYPE_CONTROL = 0,
-
- /** Isochronous endpoint */
- LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1,
-
- /** Bulk endpoint */
- LIBUSB_TRANSFER_TYPE_BULK = 2,
-
- /** Interrupt endpoint */
- LIBUSB_TRANSFER_TYPE_INTERRUPT = 3,
-
- /** Stream endpoint */
- LIBUSB_TRANSFER_TYPE_BULK_STREAM = 4,
-};
-
-/** \ingroup misc
- * Standard requests, as defined in table 9-5 of the USB 3.0 specifications */
-enum libusb_standard_request {
- /** Request status of the specific recipient */
- LIBUSB_REQUEST_GET_STATUS = 0x00,
-
- /** Clear or disable a specific feature */
- LIBUSB_REQUEST_CLEAR_FEATURE = 0x01,
-
- /* 0x02 is reserved */
-
- /** Set or enable a specific feature */
- LIBUSB_REQUEST_SET_FEATURE = 0x03,
-
- /* 0x04 is reserved */
-
- /** Set device address for all future accesses */
- LIBUSB_REQUEST_SET_ADDRESS = 0x05,
-
- /** Get the specified descriptor */
- LIBUSB_REQUEST_GET_DESCRIPTOR = 0x06,
-
- /** Used to update existing descriptors or add new descriptors */
- LIBUSB_REQUEST_SET_DESCRIPTOR = 0x07,
-
- /** Get the current device configuration value */
- LIBUSB_REQUEST_GET_CONFIGURATION = 0x08,
-
- /** Set device configuration */
- LIBUSB_REQUEST_SET_CONFIGURATION = 0x09,
-
- /** Return the selected alternate setting for the specified interface */
- LIBUSB_REQUEST_GET_INTERFACE = 0x0A,
-
- /** Select an alternate interface for the specified interface */
- LIBUSB_REQUEST_SET_INTERFACE = 0x0B,
-
- /** Set then report an endpoint's synchronization frame */
- LIBUSB_REQUEST_SYNCH_FRAME = 0x0C,
-
- /** Sets both the U1 and U2 Exit Latency */
- LIBUSB_REQUEST_SET_SEL = 0x30,
-
- /** Delay from the time a host transmits a packet to the time it is
- * received by the device. */
- LIBUSB_SET_ISOCH_DELAY = 0x31,
-};
-
-/** \ingroup misc
- * Request type bits of the
- * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control
- * transfers. */
-enum libusb_request_type {
- /** Standard */
- LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5),
-
- /** Class */
- LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5),
-
- /** Vendor */
- LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5),
-
- /** Reserved */
- LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5)
-};
-
-/** \ingroup misc
- * Recipient bits of the
- * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control
- * transfers. Values 4 through 31 are reserved. */
-enum libusb_request_recipient {
- /** Device */
- LIBUSB_RECIPIENT_DEVICE = 0x00,
-
- /** Interface */
- LIBUSB_RECIPIENT_INTERFACE = 0x01,
-
- /** Endpoint */
- LIBUSB_RECIPIENT_ENDPOINT = 0x02,
-
- /** Other */
- LIBUSB_RECIPIENT_OTHER = 0x03,
-};
-
-#define LIBUSB_ISO_SYNC_TYPE_MASK 0x0C
-
-/** \ingroup desc
- * Synchronization type for isochronous endpoints. Values for bits 2:3 of the
- * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in
- * libusb_endpoint_descriptor.
- */
-enum libusb_iso_sync_type {
- /** No synchronization */
- LIBUSB_ISO_SYNC_TYPE_NONE = 0,
-
- /** Asynchronous */
- LIBUSB_ISO_SYNC_TYPE_ASYNC = 1,
-
- /** Adaptive */
- LIBUSB_ISO_SYNC_TYPE_ADAPTIVE = 2,
-
- /** Synchronous */
- LIBUSB_ISO_SYNC_TYPE_SYNC = 3
-};
-
-#define LIBUSB_ISO_USAGE_TYPE_MASK 0x30
-
-/** \ingroup desc
- * Usage type for isochronous endpoints. Values for bits 4:5 of the
- * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in
- * libusb_endpoint_descriptor.
- */
-enum libusb_iso_usage_type {
- /** Data endpoint */
- LIBUSB_ISO_USAGE_TYPE_DATA = 0,
-
- /** Feedback endpoint */
- LIBUSB_ISO_USAGE_TYPE_FEEDBACK = 1,
-
- /** Implicit feedback Data endpoint */
- LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2,
-};
-
-/** \ingroup desc
- * A structure representing the standard USB device descriptor. This
- * descriptor is documented in section 9.6.1 of the USB 3.0 specification.
- * All multiple-byte fields are represented in host-endian format.
- */
-struct libusb_device_descriptor {
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
-
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this
- * context. */
- uint8_t bDescriptorType;
-
- /** USB specification release number in binary-coded decimal. A value of
- * 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. */
- uint16_t bcdUSB;
-
- /** USB-IF class code for the device. See \ref libusb_class_code. */
- uint8_t bDeviceClass;
-
- /** USB-IF subclass code for the device, qualified by the bDeviceClass
- * value */
- uint8_t bDeviceSubClass;
-
- /** USB-IF protocol code for the device, qualified by the bDeviceClass and
- * bDeviceSubClass values */
- uint8_t bDeviceProtocol;
-
- /** Maximum packet size for endpoint 0 */
- uint8_t bMaxPacketSize0;
-
- /** USB-IF vendor ID */
- uint16_t idVendor;
-
- /** USB-IF product ID */
- uint16_t idProduct;
-
- /** Device release number in binary-coded decimal */
- uint16_t bcdDevice;
-
- /** Index of string descriptor describing manufacturer */
- uint8_t iManufacturer;
-
- /** Index of string descriptor describing product */
- uint8_t iProduct;
-
- /** Index of string descriptor containing device serial number */
- uint8_t iSerialNumber;
-
- /** Number of possible configurations */
- uint8_t bNumConfigurations;
-};
-
-/** \ingroup desc
- * A structure representing the standard USB endpoint descriptor. This
- * descriptor is documented in section 9.6.6 of the USB 3.0 specification.
- * All multiple-byte fields are represented in host-endian format.
- */
-struct libusb_endpoint_descriptor {
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
-
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_ENDPOINT LIBUSB_DT_ENDPOINT in
- * this context. */
- uint8_t bDescriptorType;
-
- /** The address of the endpoint described by this descriptor. Bits 0:3 are
- * the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction,
- * see \ref libusb_endpoint_direction.
- */
- uint8_t bEndpointAddress;
-
- /** Attributes which apply to the endpoint when it is configured using
- * the bConfigurationValue. Bits 0:1 determine the transfer type and
- * correspond to \ref libusb_transfer_type. Bits 2:3 are only used for
- * isochronous endpoints and correspond to \ref libusb_iso_sync_type.
- * Bits 4:5 are also only used for isochronous endpoints and correspond to
- * \ref libusb_iso_usage_type. Bits 6:7 are reserved.
- */
- uint8_t bmAttributes;
-
- /** Maximum packet size this endpoint is capable of sending/receiving. */
- uint16_t wMaxPacketSize;
-
- /** Interval for polling endpoint for data transfers. */
- uint8_t bInterval;
-
- /** For audio devices only: the rate at which synchronization feedback
- * is provided. */
- uint8_t bRefresh;
-
- /** For audio devices only: the address if the synch endpoint */
- uint8_t bSynchAddress;
-
- /** Extra descriptors. If libusb encounters unknown endpoint descriptors,
- * it will store them here, should you wish to parse them. */
- const unsigned char *extra;
-
- /** Length of the extra descriptors, in bytes. */
- int extra_length;
-};
-
-/** \ingroup desc
- * A structure representing the standard USB interface descriptor. This
- * descriptor is documented in section 9.6.5 of the USB 3.0 specification.
- * All multiple-byte fields are represented in host-endian format.
- */
-struct libusb_interface_descriptor {
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
-
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE LIBUSB_DT_INTERFACE
- * in this context. */
- uint8_t bDescriptorType;
-
- /** Number of this interface */
- uint8_t bInterfaceNumber;
-
- /** Value used to select this alternate setting for this interface */
- uint8_t bAlternateSetting;
-
- /** Number of endpoints used by this interface (excluding the control
- * endpoint). */
- uint8_t bNumEndpoints;
-
- /** USB-IF class code for this interface. See \ref libusb_class_code. */
- uint8_t bInterfaceClass;
-
- /** USB-IF subclass code for this interface, qualified by the
- * bInterfaceClass value */
- uint8_t bInterfaceSubClass;
-
- /** USB-IF protocol code for this interface, qualified by the
- * bInterfaceClass and bInterfaceSubClass values */
- uint8_t bInterfaceProtocol;
-
- /** Index of string descriptor describing this interface */
- uint8_t iInterface;
-
- /** Array of endpoint descriptors. This length of this array is determined
- * by the bNumEndpoints field. */
- const struct libusb_endpoint_descriptor *endpoint;
-
- /** Extra descriptors. If libusb encounters unknown interface descriptors,
- * it will store them here, should you wish to parse them. */
- const unsigned char *extra;
-
- /** Length of the extra descriptors, in bytes. */
- int extra_length;
-};
-
-/** \ingroup desc
- * A collection of alternate settings for a particular USB interface.
- */
-struct libusb_interface {
- /** Array of interface descriptors. The length of this array is determined
- * by the num_altsetting field. */
- const struct libusb_interface_descriptor *altsetting;
-
- /** The number of alternate settings that belong to this interface */
- int num_altsetting;
-};
-
-/** \ingroup desc
- * A structure representing the standard USB configuration descriptor. This
- * descriptor is documented in section 9.6.3 of the USB 3.0 specification.
- * All multiple-byte fields are represented in host-endian format.
- */
-struct libusb_config_descriptor {
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
-
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_CONFIG LIBUSB_DT_CONFIG
- * in this context. */
- uint8_t bDescriptorType;
-
- /** Total length of data returned for this configuration */
- uint16_t wTotalLength;
-
- /** Number of interfaces supported by this configuration */
- uint8_t bNumInterfaces;
-
- /** Identifier value for this configuration */
- uint8_t bConfigurationValue;
-
- /** Index of string descriptor describing this configuration */
- uint8_t iConfiguration;
-
- /** Configuration characteristics */
- uint8_t bmAttributes;
-
- /** Maximum power consumption of the USB device from this bus in this
- * configuration when the device is fully operation. Expressed in units
- * of 2 mA when the device is operating in high-speed mode and in units
- * of 8 mA when the device is operating in super-speed mode. */
- uint8_t MaxPower;
-
- /** Array of interfaces supported by this configuration. The length of
- * this array is determined by the bNumInterfaces field. */
- const struct libusb_interface *interface;
-
- /** Extra descriptors. If libusb encounters unknown configuration
- * descriptors, it will store them here, should you wish to parse them. */
- const unsigned char *extra;
-
- /** Length of the extra descriptors, in bytes. */
- int extra_length;
-};
-
-/** \ingroup desc
- * A structure representing the superspeed endpoint companion
- * descriptor. This descriptor is documented in section 9.6.7 of
- * the USB 3.0 specification. All multiple-byte fields are represented in
- * host-endian format.
- */
-struct libusb_ss_endpoint_companion_descriptor {
-
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
-
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_SS_ENDPOINT_COMPANION in
- * this context. */
- uint8_t bDescriptorType;
-
-
- /** The maximum number of packets the endpoint can send or
- * recieve as part of a burst. */
- uint8_t bMaxBurst;
-
- /** In bulk EP: bits 4:0 represents the maximum number of
- * streams the EP supports. In isochronous EP: bits 1:0
- * represents the Mult - a zero based value that determines
- * the maximum number of packets within a service interval */
- uint8_t bmAttributes;
-
- /** The total number of bytes this EP will transfer every
- * service interval. valid only for periodic EPs. */
- uint16_t wBytesPerInterval;
-};
-
-/** \ingroup desc
- * A generic representation of a BOS Device Capability descriptor. It is
- * advised to check bDevCapabilityType and call the matching
- * libusb_get_*_descriptor function to get a structure fully matching the type.
- */
-struct libusb_bos_dev_capability_descriptor {
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
- * LIBUSB_DT_DEVICE_CAPABILITY in this context. */
- uint8_t bDescriptorType;
- /** Device Capability type */
- uint8_t bDevCapabilityType;
- /** Device Capability data (bLength - 3 bytes) */
- uint8_t dev_capability_data
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
- [] /* valid C99 code */
-#else
- [0] /* non-standard, but usually working code */
-#endif
- ;
-};
-
-/** \ingroup desc
- * A structure representing the Binary Device Object Store (BOS) descriptor.
- * This descriptor is documented in section 9.6.2 of the USB 3.0 specification.
- * All multiple-byte fields are represented in host-endian format.
- */
-struct libusb_bos_descriptor {
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
-
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_BOS LIBUSB_DT_BOS
- * in this context. */
- uint8_t bDescriptorType;
-
- /** Length of this descriptor and all of its sub descriptors */
- uint16_t wTotalLength;
-
- /** The number of separate device capability descriptors in
- * the BOS */
- uint8_t bNumDeviceCaps;
-
- /** bNumDeviceCap Device Capability Descriptors */
- struct libusb_bos_dev_capability_descriptor *dev_capability
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
- [] /* valid C99 code */
-#else
- [0] /* non-standard, but usually working code */
-#endif
- ;
-};
-
-/** \ingroup desc
- * A structure representing the USB 2.0 Extension descriptor
- * This descriptor is documented in section 9.6.2.1 of the USB 3.0 specification.
- * All multiple-byte fields are represented in host-endian format.
- */
-struct libusb_usb_2_0_extension_descriptor {
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
-
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
- * LIBUSB_DT_DEVICE_CAPABILITY in this context. */
- uint8_t bDescriptorType;
-
- /** Capability type. Will have value
- * \ref libusb_capability_type::LIBUSB_BT_USB_2_0_EXTENSION
- * LIBUSB_BT_USB_2_0_EXTENSION in this context. */
- uint8_t bDevCapabilityType;
-
- /** Bitmap encoding of supported device level features.
- * A value of one in a bit location indicates a feature is
- * supported; a value of zero indicates it is not supported.
- * See \ref libusb_usb_2_0_extension_attributes. */
- uint32_t bmAttributes;
-};
-
-/** \ingroup desc
- * A structure representing the SuperSpeed USB Device Capability descriptor
- * This descriptor is documented in section 9.6.2.2 of the USB 3.0 specification.
- * All multiple-byte fields are represented in host-endian format.
- */
-struct libusb_ss_usb_device_capability_descriptor {
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
-
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
- * LIBUSB_DT_DEVICE_CAPABILITY in this context. */
- uint8_t bDescriptorType;
-
- /** Capability type. Will have value
- * \ref libusb_capability_type::LIBUSB_BT_SS_USB_DEVICE_CAPABILITY
- * LIBUSB_BT_SS_USB_DEVICE_CAPABILITY in this context. */
- uint8_t bDevCapabilityType;
-
- /** Bitmap encoding of supported device level features.
- * A value of one in a bit location indicates a feature is
- * supported; a value of zero indicates it is not supported.
- * See \ref libusb_ss_usb_device_capability_attributes. */
- uint8_t bmAttributes;
-
- /** Bitmap encoding of the speed supported by this device when
- * operating in SuperSpeed mode. See \ref libusb_supported_speed. */
- uint16_t wSpeedSupported;
-
- /** The lowest speed at which all the functionality supported
- * by the device is available to the user. For example if the
- * device supports all its functionality when connected at
- * full speed and above then it sets this value to 1. */
- uint8_t bFunctionalitySupport;
-
- /** U1 Device Exit Latency. */
- uint8_t bU1DevExitLat;
-
- /** U2 Device Exit Latency. */
- uint16_t bU2DevExitLat;
-};
-
-/** \ingroup desc
- * A structure representing the Container ID descriptor.
- * This descriptor is documented in section 9.6.2.3 of the USB 3.0 specification.
- * All multiple-byte fields, except UUIDs, are represented in host-endian format.
- */
-struct libusb_container_id_descriptor {
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
-
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
- * LIBUSB_DT_DEVICE_CAPABILITY in this context. */
- uint8_t bDescriptorType;
-
- /** Capability type. Will have value
- * \ref libusb_capability_type::LIBUSB_BT_CONTAINER_ID
- * LIBUSB_BT_CONTAINER_ID in this context. */
- uint8_t bDevCapabilityType;
-
- /** Reserved field */
- uint8_t bReserved;
-
- /** 128 bit UUID */
- uint8_t ContainerID[16];
-};
-
-/** \ingroup asyncio
- * Setup packet for control transfers. */
-struct libusb_control_setup {
- /** Request type. Bits 0:4 determine recipient, see
- * \ref libusb_request_recipient. Bits 5:6 determine type, see
- * \ref libusb_request_type. Bit 7 determines data transfer direction, see
- * \ref libusb_endpoint_direction.
- */
- uint8_t bmRequestType;
-
- /** Request. If the type bits of bmRequestType are equal to
- * \ref libusb_request_type::LIBUSB_REQUEST_TYPE_STANDARD
- * "LIBUSB_REQUEST_TYPE_STANDARD" then this field refers to
- * \ref libusb_standard_request. For other cases, use of this field is
- * application-specific. */
- uint8_t bRequest;
-
- /** Value. Varies according to request */
- uint16_t wValue;
-
- /** Index. Varies according to request, typically used to pass an index
- * or offset */
- uint16_t wIndex;
-
- /** Number of bytes to transfer */
- uint16_t wLength;
-};
-
-#define LIBUSB_CONTROL_SETUP_SIZE (sizeof(struct libusb_control_setup))
-
-/* libusb */
-
-struct libusb_context;
-struct libusb_device;
-struct libusb_device_handle;
-
-/** \ingroup lib
- * Structure providing the version of the libusb runtime
- */
-struct libusb_version {
- /** Library major version. */
- const uint16_t major;
-
- /** Library minor version. */
- const uint16_t minor;
-
- /** Library micro version. */
- const uint16_t micro;
-
- /** Library nano version. */
- const uint16_t nano;
-
- /** Library release candidate suffix string, e.g. "-rc4". */
- const char *rc;
-
- /** For ABI compatibility only. */
- const char* describe;
-};
-
-/** \ingroup lib
- * Structure representing a libusb session. The concept of individual libusb
- * sessions allows for your program to use two libraries (or dynamically
- * load two modules) which both independently use libusb. This will prevent
- * interference between the individual libusb users - for example
- * libusb_set_debug() will not affect the other user of the library, and
- * libusb_exit() will not destroy resources that the other user is still
- * using.
- *
- * Sessions are created by libusb_init() and destroyed through libusb_exit().
- * If your application is guaranteed to only ever include a single libusb
- * user (i.e. you), you do not have to worry about contexts: pass NULL in
- * every function call where a context is required. The default context
- * will be used.
- *
- * For more information, see \ref contexts.
- */
-typedef struct libusb_context libusb_context;
-
-/** \ingroup dev
- * Structure representing a USB device detected on the system. This is an
- * opaque type for which you are only ever provided with a pointer, usually
- * originating from libusb_get_device_list().
- *
- * Certain operations can be performed on a device, but in order to do any
- * I/O you will have to first obtain a device handle using libusb_open().
- *
- * Devices are reference counted with libusb_ref_device() and
- * libusb_unref_device(), and are freed when the reference count reaches 0.
- * New devices presented by libusb_get_device_list() have a reference count of
- * 1, and libusb_free_device_list() can optionally decrease the reference count
- * on all devices in the list. libusb_open() adds another reference which is
- * later destroyed by libusb_close().
- */
-typedef struct libusb_device libusb_device;
-
-
-/** \ingroup dev
- * Structure representing a handle on a USB device. This is an opaque type for
- * which you are only ever provided with a pointer, usually originating from
- * libusb_open().
- *
- * A device handle is used to perform I/O and other operations. When finished
- * with a device handle, you should call libusb_close().
- */
-typedef struct libusb_device_handle libusb_device_handle;
-
-/** \ingroup dev
- * Speed codes. Indicates the speed at which the device is operating.
- */
-enum libusb_speed {
- /** The OS doesn't report or know the device speed. */
- LIBUSB_SPEED_UNKNOWN = 0,
-
- /** The device is operating at low speed (1.5MBit/s). */
- LIBUSB_SPEED_LOW = 1,
-
- /** The device is operating at full speed (12MBit/s). */
- LIBUSB_SPEED_FULL = 2,
-
- /** The device is operating at high speed (480MBit/s). */
- LIBUSB_SPEED_HIGH = 3,
-
- /** The device is operating at super speed (5000MBit/s). */
- LIBUSB_SPEED_SUPER = 4,
-};
-
-/** \ingroup dev
- * Supported speeds (wSpeedSupported) bitfield. Indicates what
- * speeds the device supports.
- */
-enum libusb_supported_speed {
- /** Low speed operation supported (1.5MBit/s). */
- LIBUSB_LOW_SPEED_OPERATION = 1,
-
- /** Full speed operation supported (12MBit/s). */
- LIBUSB_FULL_SPEED_OPERATION = 2,
-
- /** High speed operation supported (480MBit/s). */
- LIBUSB_HIGH_SPEED_OPERATION = 4,
-
- /** Superspeed operation supported (5000MBit/s). */
- LIBUSB_SUPER_SPEED_OPERATION = 8,
-};
-
-/** \ingroup dev
- * Masks for the bits of the
- * \ref libusb_usb_2_0_extension_descriptor::bmAttributes "bmAttributes" field
- * of the USB 2.0 Extension descriptor.
- */
-enum libusb_usb_2_0_extension_attributes {
- /** Supports Link Power Management (LPM) */
- LIBUSB_BM_LPM_SUPPORT = 2,
-};
-
-/** \ingroup dev
- * Masks for the bits of the
- * \ref libusb_ss_usb_device_capability_descriptor::bmAttributes "bmAttributes" field
- * field of the SuperSpeed USB Device Capability descriptor.
- */
-enum libusb_ss_usb_device_capability_attributes {
- /** Supports Latency Tolerance Messages (LTM) */
- LIBUSB_BM_LTM_SUPPORT = 2,
-};
-
-/** \ingroup dev
- * USB capability types
- */
-enum libusb_bos_type {
- /** Wireless USB device capability */
- LIBUSB_BT_WIRELESS_USB_DEVICE_CAPABILITY = 1,
-
- /** USB 2.0 extensions */
- LIBUSB_BT_USB_2_0_EXTENSION = 2,
-
- /** SuperSpeed USB device capability */
- LIBUSB_BT_SS_USB_DEVICE_CAPABILITY = 3,
-
- /** Container ID type */
- LIBUSB_BT_CONTAINER_ID = 4,
-};
-
-/** \ingroup misc
- * Error codes. Most libusb functions return 0 on success or one of these
- * codes on failure.
- * You can call libusb_error_name() to retrieve a string representation of an
- * error code or libusb_strerror() to get an end-user suitable description of
- * an error code.
- */
-enum libusb_error {
- /** Success (no error) */
- LIBUSB_SUCCESS = 0,
-
- /** Input/output error */
- LIBUSB_ERROR_IO = -1,
-
- /** Invalid parameter */
- LIBUSB_ERROR_INVALID_PARAM = -2,
-
- /** Access denied (insufficient permissions) */
- LIBUSB_ERROR_ACCESS = -3,
-
- /** No such device (it may have been disconnected) */
- LIBUSB_ERROR_NO_DEVICE = -4,
-
- /** Entity not found */
- LIBUSB_ERROR_NOT_FOUND = -5,
-
- /** Resource busy */
- LIBUSB_ERROR_BUSY = -6,
-
- /** Operation timed out */
- LIBUSB_ERROR_TIMEOUT = -7,
-
- /** Overflow */
- LIBUSB_ERROR_OVERFLOW = -8,
-
- /** Pipe error */
- LIBUSB_ERROR_PIPE = -9,
-
- /** System call interrupted (perhaps due to signal) */
- LIBUSB_ERROR_INTERRUPTED = -10,
-
- /** Insufficient memory */
- LIBUSB_ERROR_NO_MEM = -11,
-
- /** Operation not supported or unimplemented on this platform */
- LIBUSB_ERROR_NOT_SUPPORTED = -12,
-
- /* NB: Remember to update LIBUSB_ERROR_COUNT below as well as the
- message strings in strerror.c when adding new error codes here. */
-
- /** Other error */
- LIBUSB_ERROR_OTHER = -99,
-};
-
-/* Total number of error codes in enum libusb_error */
-#define LIBUSB_ERROR_COUNT 14
-
-/** \ingroup asyncio
- * Transfer status codes */
-enum libusb_transfer_status {
- /** Transfer completed without error. Note that this does not indicate
- * that the entire amount of requested data was transferred. */
- LIBUSB_TRANSFER_COMPLETED,
-
- /** Transfer failed */
- LIBUSB_TRANSFER_ERROR,
-
- /** Transfer timed out */
- LIBUSB_TRANSFER_TIMED_OUT,
-
- /** Transfer was cancelled */
- LIBUSB_TRANSFER_CANCELLED,
-
- /** For bulk/interrupt endpoints: halt condition detected (endpoint
- * stalled). For control endpoints: control request not supported. */
- LIBUSB_TRANSFER_STALL,
-
- /** Device was disconnected */
- LIBUSB_TRANSFER_NO_DEVICE,
-
- /** Device sent more data than requested */
- LIBUSB_TRANSFER_OVERFLOW,
-
- /* NB! Remember to update libusb_error_name()
- when adding new status codes here. */
-};
-
-/** \ingroup asyncio
- * libusb_transfer.flags values */
-enum libusb_transfer_flags {
- /** Report short frames as errors */
- LIBUSB_TRANSFER_SHORT_NOT_OK = 1<<0,
-
- /** Automatically free() transfer buffer during libusb_free_transfer() */
- LIBUSB_TRANSFER_FREE_BUFFER = 1<<1,
-
- /** Automatically call libusb_free_transfer() after callback returns.
- * If this flag is set, it is illegal to call libusb_free_transfer()
- * from your transfer callback, as this will result in a double-free
- * when this flag is acted upon. */
- LIBUSB_TRANSFER_FREE_TRANSFER = 1<<2,
-
- /** Terminate transfers that are a multiple of the endpoint's
- * wMaxPacketSize with an extra zero length packet. This is useful
- * when a device protocol mandates that each logical request is
- * terminated by an incomplete packet (i.e. the logical requests are
- * not separated by other means).
- *
- * This flag only affects host-to-device transfers to bulk and interrupt
- * endpoints. In other situations, it is ignored.
- *
- * This flag only affects transfers with a length that is a multiple of
- * the endpoint's wMaxPacketSize. On transfers of other lengths, this
- * flag has no effect. Therefore, if you are working with a device that
- * needs a ZLP whenever the end of the logical request falls on a packet
- * boundary, then it is sensible to set this flag on every
- * transfer (you do not have to worry about only setting it on transfers
- * that end on the boundary).
- *
- * This flag is currently only supported on Linux.
- * On other systems, libusb_submit_transfer() will return
- * LIBUSB_ERROR_NOT_SUPPORTED for every transfer where this flag is set.
- *
- * Available since libusb-1.0.9.
- */
- LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1 << 3,
-};
-
-/** \ingroup asyncio
- * Isochronous packet descriptor. */
-struct libusb_iso_packet_descriptor {
- /** Length of data to request in this packet */
- unsigned int length;
-
- /** Amount of data that was actually transferred */
- unsigned int actual_length;
-
- /** Status code for this packet */
- enum libusb_transfer_status status;
-};
-
-struct libusb_transfer;
-
-/** \ingroup asyncio
- * Asynchronous transfer callback function type. When submitting asynchronous
- * transfers, you pass a pointer to a callback function of this type via the
- * \ref libusb_transfer::callback "callback" member of the libusb_transfer
- * structure. libusb will call this function later, when the transfer has
- * completed or failed. See \ref asyncio for more information.
- * \param transfer The libusb_transfer struct the callback function is being
- * notified about.
- */
-typedef void (LIBUSB_CALL *libusb_transfer_cb_fn)(struct libusb_transfer *transfer);
-
-/** \ingroup asyncio
- * The generic USB transfer structure. The user populates this structure and
- * then submits it in order to request a transfer. After the transfer has
- * completed, the library populates the transfer with the results and passes
- * it back to the user.
- */
-struct libusb_transfer {
- /** Handle of the device that this transfer will be submitted to */
- libusb_device_handle *dev_handle;
-
- /** A bitwise OR combination of \ref libusb_transfer_flags. */
- uint8_t flags;
-
- /** Address of the endpoint where this transfer will be sent. */
- unsigned char endpoint;
-
- /** Type of the endpoint from \ref libusb_transfer_type */
- unsigned char type;
-
- /** Timeout for this transfer in millseconds. A value of 0 indicates no
- * timeout. */
- unsigned int timeout;
-
- /** The status of the transfer. Read-only, and only for use within
- * transfer callback function.
- *
- * If this is an isochronous transfer, this field may read COMPLETED even
- * if there were errors in the frames. Use the
- * \ref libusb_iso_packet_descriptor::status "status" field in each packet
- * to determine if errors occurred. */
- enum libusb_transfer_status status;
-
- /** Length of the data buffer */
- int length;
-
- /** Actual length of data that was transferred. Read-only, and only for
- * use within transfer callback function. Not valid for isochronous
- * endpoint transfers. */
- int actual_length;
-
- /** Callback function. This will be invoked when the transfer completes,
- * fails, or is cancelled. */
- libusb_transfer_cb_fn callback;
-
- /** User context data to pass to the callback function. */
- void *user_data;
-
- /** Data buffer */
- unsigned char *buffer;
-
- /** Number of isochronous packets. Only used for I/O with isochronous
- * endpoints. */
- int num_iso_packets;
-
- /** Isochronous packet descriptors, for isochronous transfers only. */
- struct libusb_iso_packet_descriptor iso_packet_desc
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
- [] /* valid C99 code */
-#else
- [0] /* non-standard, but usually working code */
-#endif
- ;
-};
-
-/** \ingroup misc
- * Capabilities supported by an instance of libusb on the current running
- * platform. Test if the loaded library supports a given capability by calling
- * \ref libusb_has_capability().
- */
-enum libusb_capability {
- /** The libusb_has_capability() API is available. */
- LIBUSB_CAP_HAS_CAPABILITY = 0x0000,
- /** Hotplug support is available on this platform. */
- LIBUSB_CAP_HAS_HOTPLUG = 0x0001,
- /** The library can access HID devices without requiring user intervention.
- * Note that before being able to actually access an HID device, you may
- * still have to call additional libusb functions such as
- * \ref libusb_detach_kernel_driver(). */
- LIBUSB_CAP_HAS_HID_ACCESS = 0x0100,
- /** The library supports detaching of the default USB driver, using
- * \ref libusb_detach_kernel_driver(), if one is set by the OS kernel */
- LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER = 0x0101
-};
-
-/** \ingroup lib
- * Log message levels.
- * - LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library (default)
- * - LIBUSB_LOG_LEVEL_ERROR (1) : error messages are printed to stderr
- * - LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to stderr
- * - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stdout, warning
- * and error messages are printed to stderr
- * - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stdout,
- * warnings and errors to stderr
- */
-enum libusb_log_level {
- LIBUSB_LOG_LEVEL_NONE = 0,
- LIBUSB_LOG_LEVEL_ERROR,
- LIBUSB_LOG_LEVEL_WARNING,
- LIBUSB_LOG_LEVEL_INFO,
- LIBUSB_LOG_LEVEL_DEBUG,
-};
-
-int LIBUSB_CALL libusb_init(libusb_context **ctx);
-void LIBUSB_CALL libusb_exit(libusb_context *ctx);
-void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level);
-const struct libusb_version * LIBUSB_CALL libusb_get_version(void);
-int LIBUSB_CALL libusb_has_capability(uint32_t capability);
-const char * LIBUSB_CALL libusb_error_name(int errcode);
-int LIBUSB_CALL libusb_setlocale(const char *locale);
-const char * LIBUSB_CALL libusb_strerror(enum libusb_error errcode);
-
-ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context *ctx,
- libusb_device ***list);
-void LIBUSB_CALL libusb_free_device_list(libusb_device **list,
- int unref_devices);
-libusb_device * LIBUSB_CALL libusb_ref_device(libusb_device *dev);
-void LIBUSB_CALL libusb_unref_device(libusb_device *dev);
-
-int LIBUSB_CALL libusb_get_configuration(libusb_device_handle *dev,
- int *config);
-int LIBUSB_CALL libusb_get_device_descriptor(libusb_device *dev,
- struct libusb_device_descriptor *desc);
-int LIBUSB_CALL libusb_get_active_config_descriptor(libusb_device *dev,
- struct libusb_config_descriptor **config);
-int LIBUSB_CALL libusb_get_config_descriptor(libusb_device *dev,
- uint8_t config_index, struct libusb_config_descriptor **config);
-int LIBUSB_CALL libusb_get_config_descriptor_by_value(libusb_device *dev,
- uint8_t bConfigurationValue, struct libusb_config_descriptor **config);
-void LIBUSB_CALL libusb_free_config_descriptor(
- struct libusb_config_descriptor *config);
-int LIBUSB_CALL libusb_get_ss_endpoint_companion_descriptor(
- struct libusb_context *ctx,
- const struct libusb_endpoint_descriptor *endpoint,
- struct libusb_ss_endpoint_companion_descriptor **ep_comp);
-void LIBUSB_CALL libusb_free_ss_endpoint_companion_descriptor(
- struct libusb_ss_endpoint_companion_descriptor *ep_comp);
-int LIBUSB_CALL libusb_get_bos_descriptor(libusb_device_handle *handle,
- struct libusb_bos_descriptor **bos);
-void LIBUSB_CALL libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos);
-int LIBUSB_CALL libusb_get_usb_2_0_extension_descriptor(
- struct libusb_context *ctx,
- struct libusb_bos_dev_capability_descriptor *dev_cap,
- struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension);
-void LIBUSB_CALL libusb_free_usb_2_0_extension_descriptor(
- struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension);
-int LIBUSB_CALL libusb_get_ss_usb_device_capability_descriptor(
- struct libusb_context *ctx,
- struct libusb_bos_dev_capability_descriptor *dev_cap,
- struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_cap);
-void LIBUSB_CALL libusb_free_ss_usb_device_capability_descriptor(
- struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap);
-int LIBUSB_CALL libusb_get_container_id_descriptor(struct libusb_context *ctx,
- struct libusb_bos_dev_capability_descriptor *dev_cap,
- struct libusb_container_id_descriptor **container_id);
-void LIBUSB_CALL libusb_free_container_id_descriptor(
- struct libusb_container_id_descriptor *container_id);
-uint8_t LIBUSB_CALL libusb_get_bus_number(libusb_device *dev);
-uint8_t LIBUSB_CALL libusb_get_port_number(libusb_device *dev);
-int LIBUSB_CALL libusb_get_port_numbers(libusb_device *dev, uint8_t* port_numbers, int port_numbers_len);
-LIBUSB_DEPRECATED_FOR(libusb_get_port_numbers)
-int LIBUSB_CALL libusb_get_port_path(libusb_context *ctx, libusb_device *dev, uint8_t* path, uint8_t path_length);
-libusb_device * LIBUSB_CALL libusb_get_parent(libusb_device *dev);
-uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device *dev);
-int LIBUSB_CALL libusb_get_device_speed(libusb_device *dev);
-int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev,
- unsigned char endpoint);
-int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev,
- unsigned char endpoint);
-
-int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **handle);
-void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle);
-libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle);
-
-int LIBUSB_CALL libusb_set_configuration(libusb_device_handle *dev,
- int configuration);
-int LIBUSB_CALL libusb_claim_interface(libusb_device_handle *dev,
- int interface_number);
-int LIBUSB_CALL libusb_release_interface(libusb_device_handle *dev,
- int interface_number);
-
-libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid(
- libusb_context *ctx, uint16_t vendor_id, uint16_t product_id);
-
-int LIBUSB_CALL libusb_set_interface_alt_setting(libusb_device_handle *dev,
- int interface_number, int alternate_setting);
-int LIBUSB_CALL libusb_clear_halt(libusb_device_handle *dev,
- unsigned char endpoint);
-int LIBUSB_CALL libusb_reset_device(libusb_device_handle *dev);
-
-int LIBUSB_CALL libusb_alloc_streams(libusb_device_handle *dev,
- uint32_t num_streams, unsigned char *endpoints, int num_endpoints);
-int LIBUSB_CALL libusb_free_streams(libusb_device_handle *dev,
- unsigned char *endpoints, int num_endpoints);
-
-int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle *dev,
- int interface_number);
-int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle *dev,
- int interface_number);
-int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle *dev,
- int interface_number);
-int LIBUSB_CALL libusb_set_auto_detach_kernel_driver(
- libusb_device_handle *dev, int enable);
-
-/* async I/O */
-
-/** \ingroup asyncio
- * Get the data section of a control transfer. This convenience function is here
- * to remind you that the data does not start until 8 bytes into the actual
- * buffer, as the setup packet comes first.
- *
- * Calling this function only makes sense from a transfer callback function,
- * or situations where you have already allocated a suitably sized buffer at
- * transfer->buffer.
- *
- * \param transfer a transfer
- * \returns pointer to the first byte of the data section
- */
-static inline unsigned char *libusb_control_transfer_get_data(
- struct libusb_transfer *transfer)
-{
- return transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
-}
-
-/** \ingroup asyncio
- * Get the control setup packet of a control transfer. This convenience
- * function is here to remind you that the control setup occupies the first
- * 8 bytes of the transfer data buffer.
- *
- * Calling this function only makes sense from a transfer callback function,
- * or situations where you have already allocated a suitably sized buffer at
- * transfer->buffer.
- *
- * \param transfer a transfer
- * \returns a casted pointer to the start of the transfer data buffer
- */
-static inline struct libusb_control_setup *libusb_control_transfer_get_setup(
- struct libusb_transfer *transfer)
-{
- return (struct libusb_control_setup *)(void *) transfer->buffer;
-}
-
-/** \ingroup asyncio
- * Helper function to populate the setup packet (first 8 bytes of the data
- * buffer) for a control transfer. The wIndex, wValue and wLength values should
- * be given in host-endian byte order.
- *
- * \param buffer buffer to output the setup packet into
- * This pointer must be aligned to at least 2 bytes boundary.
- * \param bmRequestType see the
- * \ref libusb_control_setup::bmRequestType "bmRequestType" field of
- * \ref libusb_control_setup
- * \param bRequest see the
- * \ref libusb_control_setup::bRequest "bRequest" field of
- * \ref libusb_control_setup
- * \param wValue see the
- * \ref libusb_control_setup::wValue "wValue" field of
- * \ref libusb_control_setup
- * \param wIndex see the
- * \ref libusb_control_setup::wIndex "wIndex" field of
- * \ref libusb_control_setup
- * \param wLength see the
- * \ref libusb_control_setup::wLength "wLength" field of
- * \ref libusb_control_setup
- */
-static inline void libusb_fill_control_setup(unsigned char *buffer,
- uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
- uint16_t wLength)
-{
- struct libusb_control_setup *setup = (struct libusb_control_setup *)(void *) buffer;
- setup->bmRequestType = bmRequestType;
- setup->bRequest = bRequest;
- setup->wValue = libusb_cpu_to_le16(wValue);
- setup->wIndex = libusb_cpu_to_le16(wIndex);
- setup->wLength = libusb_cpu_to_le16(wLength);
-}
-
-struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(int iso_packets);
-int LIBUSB_CALL libusb_submit_transfer(struct libusb_transfer *transfer);
-int LIBUSB_CALL libusb_cancel_transfer(struct libusb_transfer *transfer);
-void LIBUSB_CALL libusb_free_transfer(struct libusb_transfer *transfer);
-void LIBUSB_CALL libusb_transfer_set_stream_id(
- struct libusb_transfer *transfer, uint32_t stream_id);
-uint32_t LIBUSB_CALL libusb_transfer_get_stream_id(
- struct libusb_transfer *transfer);
-
-/** \ingroup asyncio
- * Helper function to populate the required \ref libusb_transfer fields
- * for a control transfer.
- *
- * If you pass a transfer buffer to this function, the first 8 bytes will
- * be interpreted as a control setup packet, and the wLength field will be
- * used to automatically populate the \ref libusb_transfer::length "length"
- * field of the transfer. Therefore the recommended approach is:
- * -# Allocate a suitably sized data buffer (including space for control setup)
- * -# Call libusb_fill_control_setup()
- * -# If this is a host-to-device transfer with a data stage, put the data
- * in place after the setup packet
- * -# Call this function
- * -# Call libusb_submit_transfer()
- *
- * It is also legal to pass a NULL buffer to this function, in which case this
- * function will not attempt to populate the length field. Remember that you
- * must then populate the buffer and length fields later.
- *
- * \param transfer the transfer to populate
- * \param dev_handle handle of the device that will handle the transfer
- * \param buffer data buffer. If provided, this function will interpret the
- * first 8 bytes as a setup packet and infer the transfer length from that.
- * This pointer must be aligned to at least 2 bytes boundary.
- * \param callback callback function to be invoked on transfer completion
- * \param user_data user data to pass to callback function
- * \param timeout timeout for the transfer in milliseconds
- */
-static inline void libusb_fill_control_transfer(
- struct libusb_transfer *transfer, libusb_device_handle *dev_handle,
- unsigned char *buffer, libusb_transfer_cb_fn callback, void *user_data,
- unsigned int timeout)
-{
- struct libusb_control_setup *setup = (struct libusb_control_setup *)(void *) buffer;
- transfer->dev_handle = dev_handle;
- transfer->endpoint = 0;
- transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL;
- transfer->timeout = timeout;
- transfer->buffer = buffer;
- if (setup)
- transfer->length = (int) (LIBUSB_CONTROL_SETUP_SIZE
- + libusb_le16_to_cpu(setup->wLength));
- transfer->user_data = user_data;
- transfer->callback = callback;
-}
-
-/** \ingroup asyncio
- * Helper function to populate the required \ref libusb_transfer fields
- * for a bulk transfer.
- *
- * \param transfer the transfer to populate
- * \param dev_handle handle of the device that will handle the transfer
- * \param endpoint address of the endpoint where this transfer will be sent
- * \param buffer data buffer
- * \param length length of data buffer
- * \param callback callback function to be invoked on transfer completion
- * \param user_data user data to pass to callback function
- * \param timeout timeout for the transfer in milliseconds
- */
-static inline void libusb_fill_bulk_transfer(struct libusb_transfer *transfer,
- libusb_device_handle *dev_handle, unsigned char endpoint,
- unsigned char *buffer, int length, libusb_transfer_cb_fn callback,
- void *user_data, unsigned int timeout)
-{
- transfer->dev_handle = dev_handle;
- transfer->endpoint = endpoint;
- transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
- transfer->timeout = timeout;
- transfer->buffer = buffer;
- transfer->length = length;
- transfer->user_data = user_data;
- transfer->callback = callback;
-}
-
-/** \ingroup asyncio
- * Helper function to populate the required \ref libusb_transfer fields
- * for a bulk transfer using bulk streams.
- *
- * Since version 1.0.19, \ref LIBUSB_API_VERSION >= 0x01000103
- *
- * \param transfer the transfer to populate
- * \param dev_handle handle of the device that will handle the transfer
- * \param endpoint address of the endpoint where this transfer will be sent
- * \param stream_id bulk stream id for this transfer
- * \param buffer data buffer
- * \param length length of data buffer
- * \param callback callback function to be invoked on transfer completion
- * \param user_data user data to pass to callback function
- * \param timeout timeout for the transfer in milliseconds
- */
-static inline void libusb_fill_bulk_stream_transfer(
- struct libusb_transfer *transfer, libusb_device_handle *dev_handle,
- unsigned char endpoint, uint32_t stream_id,
- unsigned char *buffer, int length, libusb_transfer_cb_fn callback,
- void *user_data, unsigned int timeout)
-{
- libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer,
- length, callback, user_data, timeout);
- transfer->type = LIBUSB_TRANSFER_TYPE_BULK_STREAM;
- libusb_transfer_set_stream_id(transfer, stream_id);
-}
-
-/** \ingroup asyncio
- * Helper function to populate the required \ref libusb_transfer fields
- * for an interrupt transfer.
- *
- * \param transfer the transfer to populate
- * \param dev_handle handle of the device that will handle the transfer
- * \param endpoint address of the endpoint where this transfer will be sent
- * \param buffer data buffer
- * \param length length of data buffer
- * \param callback callback function to be invoked on transfer completion
- * \param user_data user data to pass to callback function
- * \param timeout timeout for the transfer in milliseconds
- */
-static inline void libusb_fill_interrupt_transfer(
- struct libusb_transfer *transfer, libusb_device_handle *dev_handle,
- unsigned char endpoint, unsigned char *buffer, int length,
- libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout)
-{
- transfer->dev_handle = dev_handle;
- transfer->endpoint = endpoint;
- transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
- transfer->timeout = timeout;
- transfer->buffer = buffer;
- transfer->length = length;
- transfer->user_data = user_data;
- transfer->callback = callback;
-}
-
-/** \ingroup asyncio
- * Helper function to populate the required \ref libusb_transfer fields
- * for an isochronous transfer.
- *
- * \param transfer the transfer to populate
- * \param dev_handle handle of the device that will handle the transfer
- * \param endpoint address of the endpoint where this transfer will be sent
- * \param buffer data buffer
- * \param length length of data buffer
- * \param num_iso_packets the number of isochronous packets
- * \param callback callback function to be invoked on transfer completion
- * \param user_data user data to pass to callback function
- * \param timeout timeout for the transfer in milliseconds
- */
-static inline void libusb_fill_iso_transfer(struct libusb_transfer *transfer,
- libusb_device_handle *dev_handle, unsigned char endpoint,
- unsigned char *buffer, int length, int num_iso_packets,
- libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout)
-{
- transfer->dev_handle = dev_handle;
- transfer->endpoint = endpoint;
- transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
- transfer->timeout = timeout;
- transfer->buffer = buffer;
- transfer->length = length;
- transfer->num_iso_packets = num_iso_packets;
- transfer->user_data = user_data;
- transfer->callback = callback;
-}
-
-/** \ingroup asyncio
- * Convenience function to set the length of all packets in an isochronous
- * transfer, based on the num_iso_packets field in the transfer structure.
- *
- * \param transfer a transfer
- * \param length the length to set in each isochronous packet descriptor
- * \see libusb_get_max_packet_size()
- */
-static inline void libusb_set_iso_packet_lengths(
- struct libusb_transfer *transfer, unsigned int length)
-{
- int i;
- for (i = 0; i < transfer->num_iso_packets; i++)
- transfer->iso_packet_desc[i].length = length;
-}
-
-/** \ingroup asyncio
- * Convenience function to locate the position of an isochronous packet
- * within the buffer of an isochronous transfer.
- *
- * This is a thorough function which loops through all preceding packets,
- * accumulating their lengths to find the position of the specified packet.
- * Typically you will assign equal lengths to each packet in the transfer,
- * and hence the above method is sub-optimal. You may wish to use
- * libusb_get_iso_packet_buffer_simple() instead.
- *
- * \param transfer a transfer
- * \param packet the packet to return the address of
- * \returns the base address of the packet buffer inside the transfer buffer,
- * or NULL if the packet does not exist.
- * \see libusb_get_iso_packet_buffer_simple()
- */
-static inline unsigned char *libusb_get_iso_packet_buffer(
- struct libusb_transfer *transfer, unsigned int packet)
-{
- int i;
- size_t offset = 0;
- int _packet;
-
- /* oops..slight bug in the API. packet is an unsigned int, but we use
- * signed integers almost everywhere else. range-check and convert to
- * signed to avoid compiler warnings. FIXME for libusb-2. */
- if (packet > INT_MAX)
- return NULL;
- _packet = (int) packet;
-
- if (_packet >= transfer->num_iso_packets)
- return NULL;
-
- for (i = 0; i < _packet; i++)
- offset += transfer->iso_packet_desc[i].length;
-
- return transfer->buffer + offset;
-}
-
-/** \ingroup asyncio
- * Convenience function to locate the position of an isochronous packet
- * within the buffer of an isochronous transfer, for transfers where each
- * packet is of identical size.
- *
- * This function relies on the assumption that every packet within the transfer
- * is of identical size to the first packet. Calculating the location of
- * the packet buffer is then just a simple calculation:
- * buffer + (packet_size * packet)
- *
- * Do not use this function on transfers other than those that have identical
- * packet lengths for each packet.
- *
- * \param transfer a transfer
- * \param packet the packet to return the address of
- * \returns the base address of the packet buffer inside the transfer buffer,
- * or NULL if the packet does not exist.
- * \see libusb_get_iso_packet_buffer()
- */
-static inline unsigned char *libusb_get_iso_packet_buffer_simple(
- struct libusb_transfer *transfer, unsigned int packet)
-{
- int _packet;
-
- /* oops..slight bug in the API. packet is an unsigned int, but we use
- * signed integers almost everywhere else. range-check and convert to
- * signed to avoid compiler warnings. FIXME for libusb-2. */
- if (packet > INT_MAX)
- return NULL;
- _packet = (int) packet;
-
- if (_packet >= transfer->num_iso_packets)
- return NULL;
-
- return transfer->buffer + ((int) transfer->iso_packet_desc[0].length * _packet);
-}
-
-/* sync I/O */
-
-int LIBUSB_CALL libusb_control_transfer(libusb_device_handle *dev_handle,
- uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
- unsigned char *data, uint16_t wLength, unsigned int timeout);
-
-int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle *dev_handle,
- unsigned char endpoint, unsigned char *data, int length,
- int *actual_length, unsigned int timeout);
-
-int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle,
- unsigned char endpoint, unsigned char *data, int length,
- int *actual_length, unsigned int timeout);
-
-/** \ingroup desc
- * Retrieve a descriptor from the default control pipe.
- * This is a convenience function which formulates the appropriate control
- * message to retrieve the descriptor.
- *
- * \param dev a device handle
- * \param desc_type the descriptor type, see \ref libusb_descriptor_type
- * \param desc_index the index of the descriptor to retrieve
- * \param data output buffer for descriptor
- * \param length size of data buffer
- * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure
- */
-static inline int libusb_get_descriptor(libusb_device_handle *dev,
- uint8_t desc_type, uint8_t desc_index, unsigned char *data, int length)
-{
- return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN,
- LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t) ((desc_type << 8) | desc_index),
- 0, data, (uint16_t) length, 1000);
-}
-
-/** \ingroup desc
- * Retrieve a descriptor from a device.
- * This is a convenience function which formulates the appropriate control
- * message to retrieve the descriptor. The string returned is Unicode, as
- * detailed in the USB specifications.
- *
- * \param dev a device handle
- * \param desc_index the index of the descriptor to retrieve
- * \param langid the language ID for the string descriptor
- * \param data output buffer for descriptor
- * \param length size of data buffer
- * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure
- * \see libusb_get_string_descriptor_ascii()
- */
-static inline int libusb_get_string_descriptor(libusb_device_handle *dev,
- uint8_t desc_index, uint16_t langid, unsigned char *data, int length)
-{
- return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN,
- LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t)((LIBUSB_DT_STRING << 8) | desc_index),
- langid, data, (uint16_t) length, 1000);
-}
-
-int LIBUSB_CALL libusb_get_string_descriptor_ascii(libusb_device_handle *dev,
- uint8_t desc_index, unsigned char *data, int length);
-
-/* polling and timeouts */
-
-int LIBUSB_CALL libusb_try_lock_events(libusb_context *ctx);
-void LIBUSB_CALL libusb_lock_events(libusb_context *ctx);
-void LIBUSB_CALL libusb_unlock_events(libusb_context *ctx);
-int LIBUSB_CALL libusb_event_handling_ok(libusb_context *ctx);
-int LIBUSB_CALL libusb_event_handler_active(libusb_context *ctx);
-void LIBUSB_CALL libusb_lock_event_waiters(libusb_context *ctx);
-void LIBUSB_CALL libusb_unlock_event_waiters(libusb_context *ctx);
-int LIBUSB_CALL libusb_wait_for_event(libusb_context *ctx, struct timeval *tv);
-
-int LIBUSB_CALL libusb_handle_events_timeout(libusb_context *ctx,
- struct timeval *tv);
-int LIBUSB_CALL libusb_handle_events_timeout_completed(libusb_context *ctx,
- struct timeval *tv, int *completed);
-int LIBUSB_CALL libusb_handle_events(libusb_context *ctx);
-int LIBUSB_CALL libusb_handle_events_completed(libusb_context *ctx, int *completed);
-int LIBUSB_CALL libusb_handle_events_locked(libusb_context *ctx,
- struct timeval *tv);
-int LIBUSB_CALL libusb_pollfds_handle_timeouts(libusb_context *ctx);
-int LIBUSB_CALL libusb_get_next_timeout(libusb_context *ctx,
- struct timeval *tv);
-
-/** \ingroup poll
- * File descriptor for polling
- */
-struct libusb_pollfd {
- /** Numeric file descriptor */
- int fd;
-
- /** Event flags to poll for from . POLLIN indicates that you
- * should monitor this file descriptor for becoming ready to read from,
- * and POLLOUT indicates that you should monitor this file descriptor for
- * nonblocking write readiness. */
- short events;
-};
-
-/** \ingroup poll
- * Callback function, invoked when a new file descriptor should be added
- * to the set of file descriptors monitored for events.
- * \param fd the new file descriptor
- * \param events events to monitor for, see \ref libusb_pollfd for a
- * description
- * \param user_data User data pointer specified in
- * libusb_set_pollfd_notifiers() call
- * \see libusb_set_pollfd_notifiers()
- */
-typedef void (LIBUSB_CALL *libusb_pollfd_added_cb)(int fd, short events,
- void *user_data);
-
-/** \ingroup poll
- * Callback function, invoked when a file descriptor should be removed from
- * the set of file descriptors being monitored for events. After returning
- * from this callback, do not use that file descriptor again.
- * \param fd the file descriptor to stop monitoring
- * \param user_data User data pointer specified in
- * libusb_set_pollfd_notifiers() call
- * \see libusb_set_pollfd_notifiers()
- */
-typedef void (LIBUSB_CALL *libusb_pollfd_removed_cb)(int fd, void *user_data);
-
-const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds(
- libusb_context *ctx);
-void LIBUSB_CALL libusb_free_pollfds(const struct libusb_pollfd **pollfds);
-void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx,
- libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
- void *user_data);
-
-/** \ingroup hotplug
- * Callback handle.
- *
- * Callbacks handles are generated by libusb_hotplug_register_callback()
- * and can be used to deregister callbacks. Callback handles are unique
- * per libusb_context and it is safe to call libusb_hotplug_deregister_callback()
- * on an already deregisted callback.
- *
- * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
- *
- * For more information, see \ref hotplug.
- */
-typedef int libusb_hotplug_callback_handle;
-
-/** \ingroup hotplug
- *
- * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
- *
- * Flags for hotplug events */
-typedef enum {
- /** Default value when not using any flags. */
- LIBUSB_HOTPLUG_NO_FLAGS = 0,
-
- /** Arm the callback and fire it for all matching currently attached devices. */
- LIBUSB_HOTPLUG_ENUMERATE = 1<<0,
-} libusb_hotplug_flag;
-
-/** \ingroup hotplug
- *
- * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
- *
- * Hotplug events */
-typedef enum {
- /** A device has been plugged in and is ready to use */
- LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED = 0x01,
-
- /** A device has left and is no longer available.
- * It is the user's responsibility to call libusb_close on any handle associated with a disconnected device.
- * It is safe to call libusb_get_device_descriptor on a device that has left */
- LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT = 0x02,
-} libusb_hotplug_event;
-
-/** \ingroup hotplug
- * Wildcard matching for hotplug events */
-#define LIBUSB_HOTPLUG_MATCH_ANY -1
-
-/** \ingroup hotplug
- * Hotplug callback function type. When requesting hotplug event notifications,
- * you pass a pointer to a callback function of this type.
- *
- * This callback may be called by an internal event thread and as such it is
- * recommended the callback do minimal processing before returning.
- *
- * libusb will call this function later, when a matching event had happened on
- * a matching device. See \ref hotplug for more information.
- *
- * It is safe to call either libusb_hotplug_register_callback() or
- * libusb_hotplug_deregister_callback() from within a callback function.
- *
- * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
- *
- * \param ctx context of this notification
- * \param device libusb_device this event occurred on
- * \param event event that occurred
- * \param user_data user data provided when this callback was registered
- * \returns bool whether this callback is finished processing events.
- * returning 1 will cause this callback to be deregistered
- */
-typedef int (LIBUSB_CALL *libusb_hotplug_callback_fn)(libusb_context *ctx,
- libusb_device *device,
- libusb_hotplug_event event,
- void *user_data);
-
-/** \ingroup hotplug
- * Register a hotplug callback function
- *
- * Register a callback with the libusb_context. The callback will fire
- * when a matching event occurs on a matching device. The callback is
- * armed until either it is deregistered with libusb_hotplug_deregister_callback()
- * or the supplied callback returns 1 to indicate it is finished processing events.
- *
- * If the \ref LIBUSB_HOTPLUG_ENUMERATE is passed the callback will be
- * called with a \ref LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED for all devices
- * already plugged into the machine. Note that libusb modifies its internal
- * device list from a separate thread, while calling hotplug callbacks from
- * libusb_handle_events(), so it is possible for a device to already be present
- * on, or removed from, its internal device list, while the hotplug callbacks
- * still need to be dispatched. This means that when using \ref
- * LIBUSB_HOTPLUG_ENUMERATE, your callback may be called twice for the arrival
- * of the same device, once from libusb_hotplug_register_callback() and once
- * from libusb_handle_events(); and/or your callback may be called for the
- * removal of a device for which an arrived call was never made.
- *
- * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
- *
- * \param[in] ctx context to register this callback with
- * \param[in] events bitwise or of events that will trigger this callback. See \ref
- * libusb_hotplug_event
- * \param[in] flags hotplug callback flags. See \ref libusb_hotplug_flag
- * \param[in] vendor_id the vendor id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
- * \param[in] product_id the product id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
- * \param[in] dev_class the device class to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
- * \param[in] cb_fn the function to be invoked on a matching event/device
- * \param[in] user_data user data to pass to the callback function
- * \param[out] handle pointer to store the handle of the allocated callback (can be NULL)
- * \returns LIBUSB_SUCCESS on success LIBUSB_ERROR code on failure
- */
-int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx,
- libusb_hotplug_event events,
- libusb_hotplug_flag flags,
- int vendor_id, int product_id,
- int dev_class,
- libusb_hotplug_callback_fn cb_fn,
- void *user_data,
- libusb_hotplug_callback_handle *handle);
-
-/** \ingroup hotplug
- * Deregisters a hotplug callback.
- *
- * Deregister a callback from a libusb_context. This function is safe to call from within
- * a hotplug callback.
- *
- * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
- *
- * \param[in] ctx context this callback is registered with
- * \param[in] handle the handle of the callback to deregister
- */
-void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context *ctx,
- libusb_hotplug_callback_handle handle);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+/*
+ * Public libusb header file
+ * Copyright © 2001 Johannes Erdfelt
+ * Copyright © 2007-2008 Daniel Drake
+ * Copyright © 2012 Pete Batard
+ * Copyright © 2012 Nathan Hjelm
+ * For more information, please visit: http://libusb.info
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBUSB_H
+#define LIBUSB_H
+
+#ifdef _MSC_VER
+/* on MS environments, the inline keyword is available in C++ only */
+#if !defined(__cplusplus)
+#define inline __inline
+#endif
+/* ssize_t is also not available (copy/paste from MinGW) */
+#ifndef _SSIZE_T_DEFINED
+#define _SSIZE_T_DEFINED
+#undef ssize_t
+#ifdef _WIN64
+ typedef __int64 ssize_t;
+#else
+ typedef int ssize_t;
+#endif /* _WIN64 */
+#endif /* _SSIZE_T_DEFINED */
+#endif /* _MSC_VER */
+
+/* stdint.h is not available on older MSVC */
+#if defined(_MSC_VER) && (_MSC_VER < 1600) && (!defined(_STDINT)) && (!defined(_STDINT_H))
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+#else
+#include
+#endif
+
+#if !defined(_WIN32_WCE)
+#include
+#endif
+
+#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__HAIKU__)
+#include
+#endif
+
+#include
+#include
+
+/* 'interface' might be defined as a macro on Windows, so we need to
+ * undefine it so as not to break the current libusb API, because
+ * libusb_config_descriptor has an 'interface' member
+ * As this can be problematic if you include windows.h after libusb.h
+ * in your sources, we force windows.h to be included first. */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+#include
+#if defined(interface)
+#undef interface
+#endif
+#if !defined(__CYGWIN__)
+#include
+#endif
+#endif
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+#define LIBUSB_DEPRECATED_FOR(f) \
+ __attribute__((deprecated("Use " #f " instead")))
+#else
+#define LIBUSB_DEPRECATED_FOR(f)
+#endif /* __GNUC__ */
+
+/** \def LIBUSB_CALL
+ * \ingroup libusb_misc
+ * libusb's Windows calling convention.
+ *
+ * Under Windows, the selection of available compilers and configurations
+ * means that, unlike other platforms, there is not one true calling
+ * convention (calling convention: the manner in which parameters are
+ * passed to functions in the generated assembly code).
+ *
+ * Matching the Windows API itself, libusb uses the WINAPI convention (which
+ * translates to the stdcall convention) and guarantees that the
+ * library is compiled in this way. The public header file also includes
+ * appropriate annotations so that your own software will use the right
+ * convention, even if another convention is being used by default within
+ * your codebase.
+ *
+ * The one consideration that you must apply in your software is to mark
+ * all functions which you use as libusb callbacks with this LIBUSB_CALL
+ * annotation, so that they too get compiled for the correct calling
+ * convention.
+ *
+ * On non-Windows operating systems, this macro is defined as nothing. This
+ * means that you can apply it to your code without worrying about
+ * cross-platform compatibility.
+ */
+/* LIBUSB_CALL must be defined on both definition and declaration of libusb
+ * functions. You'd think that declaration would be enough, but cygwin will
+ * complain about conflicting types unless both are marked this way.
+ * The placement of this macro is important too; it must appear after the
+ * return type, before the function name. See internal documentation for
+ * API_EXPORTED.
+ */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+#define LIBUSB_CALL WINAPI
+#else
+#define LIBUSB_CALL
+#endif
+
+/** \def LIBUSB_API_VERSION
+ * \ingroup libusb_misc
+ * libusb's API version.
+ *
+ * Since version 1.0.13, to help with feature detection, libusb defines
+ * a LIBUSB_API_VERSION macro that gets increased every time there is a
+ * significant change to the API, such as the introduction of a new call,
+ * the definition of a new macro/enum member, or any other element that
+ * libusb applications may want to detect at compilation time.
+ *
+ * The macro is typically used in an application as follows:
+ * \code
+ * #if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01001234)
+ * // Use one of the newer features from the libusb API
+ * #endif
+ * \endcode
+ *
+ * Internally, LIBUSB_API_VERSION is defined as follows:
+ * (libusb major << 24) | (libusb minor << 16) | (16 bit incremental)
+ */
+#define LIBUSB_API_VERSION 0x01000105
+
+/* The following is kept for compatibility, but will be deprecated in the future */
+#define LIBUSBX_API_VERSION LIBUSB_API_VERSION
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \ingroup libusb_misc
+ * Convert a 16-bit value from host-endian to little-endian format. On
+ * little endian systems, this function does nothing. On big endian systems,
+ * the bytes are swapped.
+ * \param x the host-endian value to convert
+ * \returns the value in little-endian byte order
+ */
+static inline uint16_t libusb_cpu_to_le16(const uint16_t x)
+{
+ union {
+ uint8_t b8[2];
+ uint16_t b16;
+ } _tmp;
+ _tmp.b8[1] = (uint8_t) (x >> 8);
+ _tmp.b8[0] = (uint8_t) (x & 0xff);
+ return _tmp.b16;
+}
+
+/** \def libusb_le16_to_cpu
+ * \ingroup libusb_misc
+ * Convert a 16-bit value from little-endian to host-endian format. On
+ * little endian systems, this function does nothing. On big endian systems,
+ * the bytes are swapped.
+ * \param x the little-endian value to convert
+ * \returns the value in host-endian byte order
+ */
+#define libusb_le16_to_cpu libusb_cpu_to_le16
+
+/* standard USB stuff */
+
+/** \ingroup libusb_desc
+ * Device and/or Interface Class codes */
+enum libusb_class_code {
+ /** In the context of a \ref libusb_device_descriptor "device descriptor",
+ * this bDeviceClass value indicates that each interface specifies its
+ * own class information and all interfaces operate independently.
+ */
+ LIBUSB_CLASS_PER_INTERFACE = 0,
+
+ /** Audio class */
+ LIBUSB_CLASS_AUDIO = 1,
+
+ /** Communications class */
+ LIBUSB_CLASS_COMM = 2,
+
+ /** Human Interface Device class */
+ LIBUSB_CLASS_HID = 3,
+
+ /** Physical */
+ LIBUSB_CLASS_PHYSICAL = 5,
+
+ /** Printer class */
+ LIBUSB_CLASS_PRINTER = 7,
+
+ /** Image class */
+ LIBUSB_CLASS_PTP = 6, /* legacy name from libusb-0.1 usb.h */
+ LIBUSB_CLASS_IMAGE = 6,
+
+ /** Mass storage class */
+ LIBUSB_CLASS_MASS_STORAGE = 8,
+
+ /** Hub class */
+ LIBUSB_CLASS_HUB = 9,
+
+ /** Data class */
+ LIBUSB_CLASS_DATA = 10,
+
+ /** Smart Card */
+ LIBUSB_CLASS_SMART_CARD = 0x0b,
+
+ /** Content Security */
+ LIBUSB_CLASS_CONTENT_SECURITY = 0x0d,
+
+ /** Video */
+ LIBUSB_CLASS_VIDEO = 0x0e,
+
+ /** Personal Healthcare */
+ LIBUSB_CLASS_PERSONAL_HEALTHCARE = 0x0f,
+
+ /** Diagnostic Device */
+ LIBUSB_CLASS_DIAGNOSTIC_DEVICE = 0xdc,
+
+ /** Wireless class */
+ LIBUSB_CLASS_WIRELESS = 0xe0,
+
+ /** Application class */
+ LIBUSB_CLASS_APPLICATION = 0xfe,
+
+ /** Class is vendor-specific */
+ LIBUSB_CLASS_VENDOR_SPEC = 0xff
+};
+
+/** \ingroup libusb_desc
+ * Descriptor types as defined by the USB specification. */
+enum libusb_descriptor_type {
+ /** Device descriptor. See libusb_device_descriptor. */
+ LIBUSB_DT_DEVICE = 0x01,
+
+ /** Configuration descriptor. See libusb_config_descriptor. */
+ LIBUSB_DT_CONFIG = 0x02,
+
+ /** String descriptor */
+ LIBUSB_DT_STRING = 0x03,
+
+ /** Interface descriptor. See libusb_interface_descriptor. */
+ LIBUSB_DT_INTERFACE = 0x04,
+
+ /** Endpoint descriptor. See libusb_endpoint_descriptor. */
+ LIBUSB_DT_ENDPOINT = 0x05,
+
+ /** BOS descriptor */
+ LIBUSB_DT_BOS = 0x0f,
+
+ /** Device Capability descriptor */
+ LIBUSB_DT_DEVICE_CAPABILITY = 0x10,
+
+ /** HID descriptor */
+ LIBUSB_DT_HID = 0x21,
+
+ /** HID report descriptor */
+ LIBUSB_DT_REPORT = 0x22,
+
+ /** Physical descriptor */
+ LIBUSB_DT_PHYSICAL = 0x23,
+
+ /** Hub descriptor */
+ LIBUSB_DT_HUB = 0x29,
+
+ /** SuperSpeed Hub descriptor */
+ LIBUSB_DT_SUPERSPEED_HUB = 0x2a,
+
+ /** SuperSpeed Endpoint Companion descriptor */
+ LIBUSB_DT_SS_ENDPOINT_COMPANION = 0x30
+};
+
+/* Descriptor sizes per descriptor type */
+#define LIBUSB_DT_DEVICE_SIZE 18
+#define LIBUSB_DT_CONFIG_SIZE 9
+#define LIBUSB_DT_INTERFACE_SIZE 9
+#define LIBUSB_DT_ENDPOINT_SIZE 7
+#define LIBUSB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
+#define LIBUSB_DT_HUB_NONVAR_SIZE 7
+#define LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE 6
+#define LIBUSB_DT_BOS_SIZE 5
+#define LIBUSB_DT_DEVICE_CAPABILITY_SIZE 3
+
+/* BOS descriptor sizes */
+#define LIBUSB_BT_USB_2_0_EXTENSION_SIZE 7
+#define LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE 10
+#define LIBUSB_BT_CONTAINER_ID_SIZE 20
+
+/* We unwrap the BOS => define its max size */
+#define LIBUSB_DT_BOS_MAX_SIZE ((LIBUSB_DT_BOS_SIZE) +\
+ (LIBUSB_BT_USB_2_0_EXTENSION_SIZE) +\
+ (LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) +\
+ (LIBUSB_BT_CONTAINER_ID_SIZE))
+
+#define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */
+#define LIBUSB_ENDPOINT_DIR_MASK 0x80
+
+/** \ingroup libusb_desc
+ * Endpoint direction. Values for bit 7 of the
+ * \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme.
+ */
+enum libusb_endpoint_direction {
+ /** In: device-to-host */
+ LIBUSB_ENDPOINT_IN = 0x80,
+
+ /** Out: host-to-device */
+ LIBUSB_ENDPOINT_OUT = 0x00
+};
+
+#define LIBUSB_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */
+
+/** \ingroup libusb_desc
+ * Endpoint transfer type. Values for bits 0:1 of the
+ * \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field.
+ */
+enum libusb_transfer_type {
+ /** Control endpoint */
+ LIBUSB_TRANSFER_TYPE_CONTROL = 0,
+
+ /** Isochronous endpoint */
+ LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1,
+
+ /** Bulk endpoint */
+ LIBUSB_TRANSFER_TYPE_BULK = 2,
+
+ /** Interrupt endpoint */
+ LIBUSB_TRANSFER_TYPE_INTERRUPT = 3,
+
+ /** Stream endpoint */
+ LIBUSB_TRANSFER_TYPE_BULK_STREAM = 4,
+};
+
+/** \ingroup libusb_misc
+ * Standard requests, as defined in table 9-5 of the USB 3.0 specifications */
+enum libusb_standard_request {
+ /** Request status of the specific recipient */
+ LIBUSB_REQUEST_GET_STATUS = 0x00,
+
+ /** Clear or disable a specific feature */
+ LIBUSB_REQUEST_CLEAR_FEATURE = 0x01,
+
+ /* 0x02 is reserved */
+
+ /** Set or enable a specific feature */
+ LIBUSB_REQUEST_SET_FEATURE = 0x03,
+
+ /* 0x04 is reserved */
+
+ /** Set device address for all future accesses */
+ LIBUSB_REQUEST_SET_ADDRESS = 0x05,
+
+ /** Get the specified descriptor */
+ LIBUSB_REQUEST_GET_DESCRIPTOR = 0x06,
+
+ /** Used to update existing descriptors or add new descriptors */
+ LIBUSB_REQUEST_SET_DESCRIPTOR = 0x07,
+
+ /** Get the current device configuration value */
+ LIBUSB_REQUEST_GET_CONFIGURATION = 0x08,
+
+ /** Set device configuration */
+ LIBUSB_REQUEST_SET_CONFIGURATION = 0x09,
+
+ /** Return the selected alternate setting for the specified interface */
+ LIBUSB_REQUEST_GET_INTERFACE = 0x0A,
+
+ /** Select an alternate interface for the specified interface */
+ LIBUSB_REQUEST_SET_INTERFACE = 0x0B,
+
+ /** Set then report an endpoint's synchronization frame */
+ LIBUSB_REQUEST_SYNCH_FRAME = 0x0C,
+
+ /** Sets both the U1 and U2 Exit Latency */
+ LIBUSB_REQUEST_SET_SEL = 0x30,
+
+ /** Delay from the time a host transmits a packet to the time it is
+ * received by the device. */
+ LIBUSB_SET_ISOCH_DELAY = 0x31,
+};
+
+/** \ingroup libusb_misc
+ * Request type bits of the
+ * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control
+ * transfers. */
+enum libusb_request_type {
+ /** Standard */
+ LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5),
+
+ /** Class */
+ LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5),
+
+ /** Vendor */
+ LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5),
+
+ /** Reserved */
+ LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5)
+};
+
+/** \ingroup libusb_misc
+ * Recipient bits of the
+ * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control
+ * transfers. Values 4 through 31 are reserved. */
+enum libusb_request_recipient {
+ /** Device */
+ LIBUSB_RECIPIENT_DEVICE = 0x00,
+
+ /** Interface */
+ LIBUSB_RECIPIENT_INTERFACE = 0x01,
+
+ /** Endpoint */
+ LIBUSB_RECIPIENT_ENDPOINT = 0x02,
+
+ /** Other */
+ LIBUSB_RECIPIENT_OTHER = 0x03,
+};
+
+#define LIBUSB_ISO_SYNC_TYPE_MASK 0x0C
+
+/** \ingroup libusb_desc
+ * Synchronization type for isochronous endpoints. Values for bits 2:3 of the
+ * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in
+ * libusb_endpoint_descriptor.
+ */
+enum libusb_iso_sync_type {
+ /** No synchronization */
+ LIBUSB_ISO_SYNC_TYPE_NONE = 0,
+
+ /** Asynchronous */
+ LIBUSB_ISO_SYNC_TYPE_ASYNC = 1,
+
+ /** Adaptive */
+ LIBUSB_ISO_SYNC_TYPE_ADAPTIVE = 2,
+
+ /** Synchronous */
+ LIBUSB_ISO_SYNC_TYPE_SYNC = 3
+};
+
+#define LIBUSB_ISO_USAGE_TYPE_MASK 0x30
+
+/** \ingroup libusb_desc
+ * Usage type for isochronous endpoints. Values for bits 4:5 of the
+ * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in
+ * libusb_endpoint_descriptor.
+ */
+enum libusb_iso_usage_type {
+ /** Data endpoint */
+ LIBUSB_ISO_USAGE_TYPE_DATA = 0,
+
+ /** Feedback endpoint */
+ LIBUSB_ISO_USAGE_TYPE_FEEDBACK = 1,
+
+ /** Implicit feedback Data endpoint */
+ LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2,
+};
+
+/** \ingroup libusb_desc
+ * A structure representing the standard USB device descriptor. This
+ * descriptor is documented in section 9.6.1 of the USB 3.0 specification.
+ * All multiple-byte fields are represented in host-endian format.
+ */
+struct libusb_device_descriptor {
+ /** Size of this descriptor (in bytes) */
+ uint8_t bLength;
+
+ /** Descriptor type. Will have value
+ * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this
+ * context. */
+ uint8_t bDescriptorType;
+
+ /** USB specification release number in binary-coded decimal. A value of
+ * 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. */
+ uint16_t bcdUSB;
+
+ /** USB-IF class code for the device. See \ref libusb_class_code. */
+ uint8_t bDeviceClass;
+
+ /** USB-IF subclass code for the device, qualified by the bDeviceClass
+ * value */
+ uint8_t bDeviceSubClass;
+
+ /** USB-IF protocol code for the device, qualified by the bDeviceClass and
+ * bDeviceSubClass values */
+ uint8_t bDeviceProtocol;
+
+ /** Maximum packet size for endpoint 0 */
+ uint8_t bMaxPacketSize0;
+
+ /** USB-IF vendor ID */
+ uint16_t idVendor;
+
+ /** USB-IF product ID */
+ uint16_t idProduct;
+
+ /** Device release number in binary-coded decimal */
+ uint16_t bcdDevice;
+
+ /** Index of string descriptor describing manufacturer */
+ uint8_t iManufacturer;
+
+ /** Index of string descriptor describing product */
+ uint8_t iProduct;
+
+ /** Index of string descriptor containing device serial number */
+ uint8_t iSerialNumber;
+
+ /** Number of possible configurations */
+ uint8_t bNumConfigurations;
+};
+
+/** \ingroup libusb_desc
+ * A structure representing the standard USB endpoint descriptor. This
+ * descriptor is documented in section 9.6.6 of the USB 3.0 specification.
+ * All multiple-byte fields are represented in host-endian format.
+ */
+struct libusb_endpoint_descriptor {
+ /** Size of this descriptor (in bytes) */
+ uint8_t bLength;
+
+ /** Descriptor type. Will have value
+ * \ref libusb_descriptor_type::LIBUSB_DT_ENDPOINT LIBUSB_DT_ENDPOINT in
+ * this context. */
+ uint8_t bDescriptorType;
+
+ /** The address of the endpoint described by this descriptor. Bits 0:3 are
+ * the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction,
+ * see \ref libusb_endpoint_direction.
+ */
+ uint8_t bEndpointAddress;
+
+ /** Attributes which apply to the endpoint when it is configured using
+ * the bConfigurationValue. Bits 0:1 determine the transfer type and
+ * correspond to \ref libusb_transfer_type. Bits 2:3 are only used for
+ * isochronous endpoints and correspond to \ref libusb_iso_sync_type.
+ * Bits 4:5 are also only used for isochronous endpoints and correspond to
+ * \ref libusb_iso_usage_type. Bits 6:7 are reserved.
+ */
+ uint8_t bmAttributes;
+
+ /** Maximum packet size this endpoint is capable of sending/receiving. */
+ uint16_t wMaxPacketSize;
+
+ /** Interval for polling endpoint for data transfers. */
+ uint8_t bInterval;
+
+ /** For audio devices only: the rate at which synchronization feedback
+ * is provided. */
+ uint8_t bRefresh;
+
+ /** For audio devices only: the address if the synch endpoint */
+ uint8_t bSynchAddress;
+
+ /** Extra descriptors. If libusb encounters unknown endpoint descriptors,
+ * it will store them here, should you wish to parse them. */
+ const unsigned char *extra;
+
+ /** Length of the extra descriptors, in bytes. */
+ int extra_length;
+};
+
+/** \ingroup libusb_desc
+ * A structure representing the standard USB interface descriptor. This
+ * descriptor is documented in section 9.6.5 of the USB 3.0 specification.
+ * All multiple-byte fields are represented in host-endian format.
+ */
+struct libusb_interface_descriptor {
+ /** Size of this descriptor (in bytes) */
+ uint8_t bLength;
+
+ /** Descriptor type. Will have value
+ * \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE LIBUSB_DT_INTERFACE
+ * in this context. */
+ uint8_t bDescriptorType;
+
+ /** Number of this interface */
+ uint8_t bInterfaceNumber;
+
+ /** Value used to select this alternate setting for this interface */
+ uint8_t bAlternateSetting;
+
+ /** Number of endpoints used by this interface (excluding the control
+ * endpoint). */
+ uint8_t bNumEndpoints;
+
+ /** USB-IF class code for this interface. See \ref libusb_class_code. */
+ uint8_t bInterfaceClass;
+
+ /** USB-IF subclass code for this interface, qualified by the
+ * bInterfaceClass value */
+ uint8_t bInterfaceSubClass;
+
+ /** USB-IF protocol code for this interface, qualified by the
+ * bInterfaceClass and bInterfaceSubClass values */
+ uint8_t bInterfaceProtocol;
+
+ /** Index of string descriptor describing this interface */
+ uint8_t iInterface;
+
+ /** Array of endpoint descriptors. This length of this array is determined
+ * by the bNumEndpoints field. */
+ const struct libusb_endpoint_descriptor *endpoint;
+
+ /** Extra descriptors. If libusb encounters unknown interface descriptors,
+ * it will store them here, should you wish to parse them. */
+ const unsigned char *extra;
+
+ /** Length of the extra descriptors, in bytes. */
+ int extra_length;
+};
+
+/** \ingroup libusb_desc
+ * A collection of alternate settings for a particular USB interface.
+ */
+struct libusb_interface {
+ /** Array of interface descriptors. The length of this array is determined
+ * by the num_altsetting field. */
+ const struct libusb_interface_descriptor *altsetting;
+
+ /** The number of alternate settings that belong to this interface */
+ int num_altsetting;
+};
+
+/** \ingroup libusb_desc
+ * A structure representing the standard USB configuration descriptor. This
+ * descriptor is documented in section 9.6.3 of the USB 3.0 specification.
+ * All multiple-byte fields are represented in host-endian format.
+ */
+struct libusb_config_descriptor {
+ /** Size of this descriptor (in bytes) */
+ uint8_t bLength;
+
+ /** Descriptor type. Will have value
+ * \ref libusb_descriptor_type::LIBUSB_DT_CONFIG LIBUSB_DT_CONFIG
+ * in this context. */
+ uint8_t bDescriptorType;
+
+ /** Total length of data returned for this configuration */
+ uint16_t wTotalLength;
+
+ /** Number of interfaces supported by this configuration */
+ uint8_t bNumInterfaces;
+
+ /** Identifier value for this configuration */
+ uint8_t bConfigurationValue;
+
+ /** Index of string descriptor describing this configuration */
+ uint8_t iConfiguration;
+
+ /** Configuration characteristics */
+ uint8_t bmAttributes;
+
+ /** Maximum power consumption of the USB device from this bus in this
+ * configuration when the device is fully operation. Expressed in units
+ * of 2 mA when the device is operating in high-speed mode and in units
+ * of 8 mA when the device is operating in super-speed mode. */
+ uint8_t MaxPower;
+
+ /** Array of interfaces supported by this configuration. The length of
+ * this array is determined by the bNumInterfaces field. */
+ const struct libusb_interface *interface;
+
+ /** Extra descriptors. If libusb encounters unknown configuration
+ * descriptors, it will store them here, should you wish to parse them. */
+ const unsigned char *extra;
+
+ /** Length of the extra descriptors, in bytes. */
+ int extra_length;
+};
+
+/** \ingroup libusb_desc
+ * A structure representing the superspeed endpoint companion
+ * descriptor. This descriptor is documented in section 9.6.7 of
+ * the USB 3.0 specification. All multiple-byte fields are represented in
+ * host-endian format.
+ */
+struct libusb_ss_endpoint_companion_descriptor {
+
+ /** Size of this descriptor (in bytes) */
+ uint8_t bLength;
+
+ /** Descriptor type. Will have value
+ * \ref libusb_descriptor_type::LIBUSB_DT_SS_ENDPOINT_COMPANION in
+ * this context. */
+ uint8_t bDescriptorType;
+
+
+ /** The maximum number of packets the endpoint can send or
+ * receive as part of a burst. */
+ uint8_t bMaxBurst;
+
+ /** In bulk EP: bits 4:0 represents the maximum number of
+ * streams the EP supports. In isochronous EP: bits 1:0
+ * represents the Mult - a zero based value that determines
+ * the maximum number of packets within a service interval */
+ uint8_t bmAttributes;
+
+ /** The total number of bytes this EP will transfer every
+ * service interval. valid only for periodic EPs. */
+ uint16_t wBytesPerInterval;
+};
+
+/** \ingroup libusb_desc
+ * A generic representation of a BOS Device Capability descriptor. It is
+ * advised to check bDevCapabilityType and call the matching
+ * libusb_get_*_descriptor function to get a structure fully matching the type.
+ */
+struct libusb_bos_dev_capability_descriptor {
+ /** Size of this descriptor (in bytes) */
+ uint8_t bLength;
+ /** Descriptor type. Will have value
+ * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
+ * LIBUSB_DT_DEVICE_CAPABILITY in this context. */
+ uint8_t bDescriptorType;
+ /** Device Capability type */
+ uint8_t bDevCapabilityType;
+ /** Device Capability data (bLength - 3 bytes) */
+ uint8_t dev_capability_data
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+ [] /* valid C99 code */
+#else
+ [0] /* non-standard, but usually working code */
+#endif
+ ;
+};
+
+/** \ingroup libusb_desc
+ * A structure representing the Binary Device Object Store (BOS) descriptor.
+ * This descriptor is documented in section 9.6.2 of the USB 3.0 specification.
+ * All multiple-byte fields are represented in host-endian format.
+ */
+struct libusb_bos_descriptor {
+ /** Size of this descriptor (in bytes) */
+ uint8_t bLength;
+
+ /** Descriptor type. Will have value
+ * \ref libusb_descriptor_type::LIBUSB_DT_BOS LIBUSB_DT_BOS
+ * in this context. */
+ uint8_t bDescriptorType;
+
+ /** Length of this descriptor and all of its sub descriptors */
+ uint16_t wTotalLength;
+
+ /** The number of separate device capability descriptors in
+ * the BOS */
+ uint8_t bNumDeviceCaps;
+
+ /** bNumDeviceCap Device Capability Descriptors */
+ struct libusb_bos_dev_capability_descriptor *dev_capability
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+ [] /* valid C99 code */
+#else
+ [0] /* non-standard, but usually working code */
+#endif
+ ;
+};
+
+/** \ingroup libusb_desc
+ * A structure representing the USB 2.0 Extension descriptor
+ * This descriptor is documented in section 9.6.2.1 of the USB 3.0 specification.
+ * All multiple-byte fields are represented in host-endian format.
+ */
+struct libusb_usb_2_0_extension_descriptor {
+ /** Size of this descriptor (in bytes) */
+ uint8_t bLength;
+
+ /** Descriptor type. Will have value
+ * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
+ * LIBUSB_DT_DEVICE_CAPABILITY in this context. */
+ uint8_t bDescriptorType;
+
+ /** Capability type. Will have value
+ * \ref libusb_capability_type::LIBUSB_BT_USB_2_0_EXTENSION
+ * LIBUSB_BT_USB_2_0_EXTENSION in this context. */
+ uint8_t bDevCapabilityType;
+
+ /** Bitmap encoding of supported device level features.
+ * A value of one in a bit location indicates a feature is
+ * supported; a value of zero indicates it is not supported.
+ * See \ref libusb_usb_2_0_extension_attributes. */
+ uint32_t bmAttributes;
+};
+
+/** \ingroup libusb_desc
+ * A structure representing the SuperSpeed USB Device Capability descriptor
+ * This descriptor is documented in section 9.6.2.2 of the USB 3.0 specification.
+ * All multiple-byte fields are represented in host-endian format.
+ */
+struct libusb_ss_usb_device_capability_descriptor {
+ /** Size of this descriptor (in bytes) */
+ uint8_t bLength;
+
+ /** Descriptor type. Will have value
+ * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
+ * LIBUSB_DT_DEVICE_CAPABILITY in this context. */
+ uint8_t bDescriptorType;
+
+ /** Capability type. Will have value
+ * \ref libusb_capability_type::LIBUSB_BT_SS_USB_DEVICE_CAPABILITY
+ * LIBUSB_BT_SS_USB_DEVICE_CAPABILITY in this context. */
+ uint8_t bDevCapabilityType;
+
+ /** Bitmap encoding of supported device level features.
+ * A value of one in a bit location indicates a feature is
+ * supported; a value of zero indicates it is not supported.
+ * See \ref libusb_ss_usb_device_capability_attributes. */
+ uint8_t bmAttributes;
+
+ /** Bitmap encoding of the speed supported by this device when
+ * operating in SuperSpeed mode. See \ref libusb_supported_speed. */
+ uint16_t wSpeedSupported;
+
+ /** The lowest speed at which all the functionality supported
+ * by the device is available to the user. For example if the
+ * device supports all its functionality when connected at
+ * full speed and above then it sets this value to 1. */
+ uint8_t bFunctionalitySupport;
+
+ /** U1 Device Exit Latency. */
+ uint8_t bU1DevExitLat;
+
+ /** U2 Device Exit Latency. */
+ uint16_t bU2DevExitLat;
+};
+
+/** \ingroup libusb_desc
+ * A structure representing the Container ID descriptor.
+ * This descriptor is documented in section 9.6.2.3 of the USB 3.0 specification.
+ * All multiple-byte fields, except UUIDs, are represented in host-endian format.
+ */
+struct libusb_container_id_descriptor {
+ /** Size of this descriptor (in bytes) */
+ uint8_t bLength;
+
+ /** Descriptor type. Will have value
+ * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
+ * LIBUSB_DT_DEVICE_CAPABILITY in this context. */
+ uint8_t bDescriptorType;
+
+ /** Capability type. Will have value
+ * \ref libusb_capability_type::LIBUSB_BT_CONTAINER_ID
+ * LIBUSB_BT_CONTAINER_ID in this context. */
+ uint8_t bDevCapabilityType;
+
+ /** Reserved field */
+ uint8_t bReserved;
+
+ /** 128 bit UUID */
+ uint8_t ContainerID[16];
+};
+
+/** \ingroup libusb_asyncio
+ * Setup packet for control transfers. */
+struct libusb_control_setup {
+ /** Request type. Bits 0:4 determine recipient, see
+ * \ref libusb_request_recipient. Bits 5:6 determine type, see
+ * \ref libusb_request_type. Bit 7 determines data transfer direction, see
+ * \ref libusb_endpoint_direction.
+ */
+ uint8_t bmRequestType;
+
+ /** Request. If the type bits of bmRequestType are equal to
+ * \ref libusb_request_type::LIBUSB_REQUEST_TYPE_STANDARD
+ * "LIBUSB_REQUEST_TYPE_STANDARD" then this field refers to
+ * \ref libusb_standard_request. For other cases, use of this field is
+ * application-specific. */
+ uint8_t bRequest;
+
+ /** Value. Varies according to request */
+ uint16_t wValue;
+
+ /** Index. Varies according to request, typically used to pass an index
+ * or offset */
+ uint16_t wIndex;
+
+ /** Number of bytes to transfer */
+ uint16_t wLength;
+};
+
+#define LIBUSB_CONTROL_SETUP_SIZE (sizeof(struct libusb_control_setup))
+
+/* libusb */
+
+struct libusb_context;
+struct libusb_device;
+struct libusb_device_handle;
+
+/** \ingroup libusb_lib
+ * Structure providing the version of the libusb runtime
+ */
+struct libusb_version {
+ /** Library major version. */
+ const uint16_t major;
+
+ /** Library minor version. */
+ const uint16_t minor;
+
+ /** Library micro version. */
+ const uint16_t micro;
+
+ /** Library nano version. */
+ const uint16_t nano;
+
+ /** Library release candidate suffix string, e.g. "-rc4". */
+ const char *rc;
+
+ /** For ABI compatibility only. */
+ const char* describe;
+};
+
+/** \ingroup libusb_lib
+ * Structure representing a libusb session. The concept of individual libusb
+ * sessions allows for your program to use two libraries (or dynamically
+ * load two modules) which both independently use libusb. This will prevent
+ * interference between the individual libusb users - for example
+ * libusb_set_debug() will not affect the other user of the library, and
+ * libusb_exit() will not destroy resources that the other user is still
+ * using.
+ *
+ * Sessions are created by libusb_init() and destroyed through libusb_exit().
+ * If your application is guaranteed to only ever include a single libusb
+ * user (i.e. you), you do not have to worry about contexts: pass NULL in
+ * every function call where a context is required. The default context
+ * will be used.
+ *
+ * For more information, see \ref libusb_contexts.
+ */
+typedef struct libusb_context libusb_context;
+
+/** \ingroup libusb_dev
+ * Structure representing a USB device detected on the system. This is an
+ * opaque type for which you are only ever provided with a pointer, usually
+ * originating from libusb_get_device_list().
+ *
+ * Certain operations can be performed on a device, but in order to do any
+ * I/O you will have to first obtain a device handle using libusb_open().
+ *
+ * Devices are reference counted with libusb_ref_device() and
+ * libusb_unref_device(), and are freed when the reference count reaches 0.
+ * New devices presented by libusb_get_device_list() have a reference count of
+ * 1, and libusb_free_device_list() can optionally decrease the reference count
+ * on all devices in the list. libusb_open() adds another reference which is
+ * later destroyed by libusb_close().
+ */
+typedef struct libusb_device libusb_device;
+
+
+/** \ingroup libusb_dev
+ * Structure representing a handle on a USB device. This is an opaque type for
+ * which you are only ever provided with a pointer, usually originating from
+ * libusb_open().
+ *
+ * A device handle is used to perform I/O and other operations. When finished
+ * with a device handle, you should call libusb_close().
+ */
+typedef struct libusb_device_handle libusb_device_handle;
+
+/** \ingroup libusb_dev
+ * Speed codes. Indicates the speed at which the device is operating.
+ */
+enum libusb_speed {
+ /** The OS doesn't report or know the device speed. */
+ LIBUSB_SPEED_UNKNOWN = 0,
+
+ /** The device is operating at low speed (1.5MBit/s). */
+ LIBUSB_SPEED_LOW = 1,
+
+ /** The device is operating at full speed (12MBit/s). */
+ LIBUSB_SPEED_FULL = 2,
+
+ /** The device is operating at high speed (480MBit/s). */
+ LIBUSB_SPEED_HIGH = 3,
+
+ /** The device is operating at super speed (5000MBit/s). */
+ LIBUSB_SPEED_SUPER = 4,
+};
+
+/** \ingroup libusb_dev
+ * Supported speeds (wSpeedSupported) bitfield. Indicates what
+ * speeds the device supports.
+ */
+enum libusb_supported_speed {
+ /** Low speed operation supported (1.5MBit/s). */
+ LIBUSB_LOW_SPEED_OPERATION = 1,
+
+ /** Full speed operation supported (12MBit/s). */
+ LIBUSB_FULL_SPEED_OPERATION = 2,
+
+ /** High speed operation supported (480MBit/s). */
+ LIBUSB_HIGH_SPEED_OPERATION = 4,
+
+ /** Superspeed operation supported (5000MBit/s). */
+ LIBUSB_SUPER_SPEED_OPERATION = 8,
+};
+
+/** \ingroup libusb_dev
+ * Masks for the bits of the
+ * \ref libusb_usb_2_0_extension_descriptor::bmAttributes "bmAttributes" field
+ * of the USB 2.0 Extension descriptor.
+ */
+enum libusb_usb_2_0_extension_attributes {
+ /** Supports Link Power Management (LPM) */
+ LIBUSB_BM_LPM_SUPPORT = 2,
+};
+
+/** \ingroup libusb_dev
+ * Masks for the bits of the
+ * \ref libusb_ss_usb_device_capability_descriptor::bmAttributes "bmAttributes" field
+ * field of the SuperSpeed USB Device Capability descriptor.
+ */
+enum libusb_ss_usb_device_capability_attributes {
+ /** Supports Latency Tolerance Messages (LTM) */
+ LIBUSB_BM_LTM_SUPPORT = 2,
+};
+
+/** \ingroup libusb_dev
+ * USB capability types
+ */
+enum libusb_bos_type {
+ /** Wireless USB device capability */
+ LIBUSB_BT_WIRELESS_USB_DEVICE_CAPABILITY = 1,
+
+ /** USB 2.0 extensions */
+ LIBUSB_BT_USB_2_0_EXTENSION = 2,
+
+ /** SuperSpeed USB device capability */
+ LIBUSB_BT_SS_USB_DEVICE_CAPABILITY = 3,
+
+ /** Container ID type */
+ LIBUSB_BT_CONTAINER_ID = 4,
+};
+
+/** \ingroup libusb_misc
+ * Error codes. Most libusb functions return 0 on success or one of these
+ * codes on failure.
+ * You can call libusb_error_name() to retrieve a string representation of an
+ * error code or libusb_strerror() to get an end-user suitable description of
+ * an error code.
+ */
+enum libusb_error {
+ /** Success (no error) */
+ LIBUSB_SUCCESS = 0,
+
+ /** Input/output error */
+ LIBUSB_ERROR_IO = -1,
+
+ /** Invalid parameter */
+ LIBUSB_ERROR_INVALID_PARAM = -2,
+
+ /** Access denied (insufficient permissions) */
+ LIBUSB_ERROR_ACCESS = -3,
+
+ /** No such device (it may have been disconnected) */
+ LIBUSB_ERROR_NO_DEVICE = -4,
+
+ /** Entity not found */
+ LIBUSB_ERROR_NOT_FOUND = -5,
+
+ /** Resource busy */
+ LIBUSB_ERROR_BUSY = -6,
+
+ /** Operation timed out */
+ LIBUSB_ERROR_TIMEOUT = -7,
+
+ /** Overflow */
+ LIBUSB_ERROR_OVERFLOW = -8,
+
+ /** Pipe error */
+ LIBUSB_ERROR_PIPE = -9,
+
+ /** System call interrupted (perhaps due to signal) */
+ LIBUSB_ERROR_INTERRUPTED = -10,
+
+ /** Insufficient memory */
+ LIBUSB_ERROR_NO_MEM = -11,
+
+ /** Operation not supported or unimplemented on this platform */
+ LIBUSB_ERROR_NOT_SUPPORTED = -12,
+
+ /* NB: Remember to update LIBUSB_ERROR_COUNT below as well as the
+ message strings in strerror.c when adding new error codes here. */
+
+ /** Other error */
+ LIBUSB_ERROR_OTHER = -99,
+};
+
+/* Total number of error codes in enum libusb_error */
+#define LIBUSB_ERROR_COUNT 14
+
+/** \ingroup libusb_asyncio
+ * Transfer status codes */
+enum libusb_transfer_status {
+ /** Transfer completed without error. Note that this does not indicate
+ * that the entire amount of requested data was transferred. */
+ LIBUSB_TRANSFER_COMPLETED,
+
+ /** Transfer failed */
+ LIBUSB_TRANSFER_ERROR,
+
+ /** Transfer timed out */
+ LIBUSB_TRANSFER_TIMED_OUT,
+
+ /** Transfer was cancelled */
+ LIBUSB_TRANSFER_CANCELLED,
+
+ /** For bulk/interrupt endpoints: halt condition detected (endpoint
+ * stalled). For control endpoints: control request not supported. */
+ LIBUSB_TRANSFER_STALL,
+
+ /** Device was disconnected */
+ LIBUSB_TRANSFER_NO_DEVICE,
+
+ /** Device sent more data than requested */
+ LIBUSB_TRANSFER_OVERFLOW,
+
+ /* NB! Remember to update libusb_error_name()
+ when adding new status codes here. */
+};
+
+/** \ingroup libusb_asyncio
+ * libusb_transfer.flags values */
+enum libusb_transfer_flags {
+ /** Report short frames as errors */
+ LIBUSB_TRANSFER_SHORT_NOT_OK = 1<<0,
+
+ /** Automatically free() transfer buffer during libusb_free_transfer().
+ * Note that buffers allocated with libusb_dev_mem_alloc() should not
+ * be attempted freed in this way, since free() is not an appropriate
+ * way to release such memory. */
+ LIBUSB_TRANSFER_FREE_BUFFER = 1<<1,
+
+ /** Automatically call libusb_free_transfer() after callback returns.
+ * If this flag is set, it is illegal to call libusb_free_transfer()
+ * from your transfer callback, as this will result in a double-free
+ * when this flag is acted upon. */
+ LIBUSB_TRANSFER_FREE_TRANSFER = 1<<2,
+
+ /** Terminate transfers that are a multiple of the endpoint's
+ * wMaxPacketSize with an extra zero length packet. This is useful
+ * when a device protocol mandates that each logical request is
+ * terminated by an incomplete packet (i.e. the logical requests are
+ * not separated by other means).
+ *
+ * This flag only affects host-to-device transfers to bulk and interrupt
+ * endpoints. In other situations, it is ignored.
+ *
+ * This flag only affects transfers with a length that is a multiple of
+ * the endpoint's wMaxPacketSize. On transfers of other lengths, this
+ * flag has no effect. Therefore, if you are working with a device that
+ * needs a ZLP whenever the end of the logical request falls on a packet
+ * boundary, then it is sensible to set this flag on every
+ * transfer (you do not have to worry about only setting it on transfers
+ * that end on the boundary).
+ *
+ * This flag is currently only supported on Linux.
+ * On other systems, libusb_submit_transfer() will return
+ * LIBUSB_ERROR_NOT_SUPPORTED for every transfer where this flag is set.
+ *
+ * Available since libusb-1.0.9.
+ */
+ LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1 << 3,
+};
+
+/** \ingroup libusb_asyncio
+ * Isochronous packet descriptor. */
+struct libusb_iso_packet_descriptor {
+ /** Length of data to request in this packet */
+ unsigned int length;
+
+ /** Amount of data that was actually transferred */
+ unsigned int actual_length;
+
+ /** Status code for this packet */
+ enum libusb_transfer_status status;
+};
+
+struct libusb_transfer;
+
+/** \ingroup libusb_asyncio
+ * Asynchronous transfer callback function type. When submitting asynchronous
+ * transfers, you pass a pointer to a callback function of this type via the
+ * \ref libusb_transfer::callback "callback" member of the libusb_transfer
+ * structure. libusb will call this function later, when the transfer has
+ * completed or failed. See \ref libusb_asyncio for more information.
+ * \param transfer The libusb_transfer struct the callback function is being
+ * notified about.
+ */
+typedef void (LIBUSB_CALL *libusb_transfer_cb_fn)(struct libusb_transfer *transfer);
+
+/** \ingroup libusb_asyncio
+ * The generic USB transfer structure. The user populates this structure and
+ * then submits it in order to request a transfer. After the transfer has
+ * completed, the library populates the transfer with the results and passes
+ * it back to the user.
+ */
+struct libusb_transfer {
+ /** Handle of the device that this transfer will be submitted to */
+ libusb_device_handle *dev_handle;
+
+ /** A bitwise OR combination of \ref libusb_transfer_flags. */
+ uint8_t flags;
+
+ /** Address of the endpoint where this transfer will be sent. */
+ unsigned char endpoint;
+
+ /** Type of the endpoint from \ref libusb_transfer_type */
+ unsigned char type;
+
+ /** Timeout for this transfer in millseconds. A value of 0 indicates no
+ * timeout. */
+ unsigned int timeout;
+
+ /** The status of the transfer. Read-only, and only for use within
+ * transfer callback function.
+ *
+ * If this is an isochronous transfer, this field may read COMPLETED even
+ * if there were errors in the frames. Use the
+ * \ref libusb_iso_packet_descriptor::status "status" field in each packet
+ * to determine if errors occurred. */
+ enum libusb_transfer_status status;
+
+ /** Length of the data buffer */
+ int length;
+
+ /** Actual length of data that was transferred. Read-only, and only for
+ * use within transfer callback function. Not valid for isochronous
+ * endpoint transfers. */
+ int actual_length;
+
+ /** Callback function. This will be invoked when the transfer completes,
+ * fails, or is cancelled. */
+ libusb_transfer_cb_fn callback;
+
+ /** User context data to pass to the callback function. */
+ void *user_data;
+
+ /** Data buffer */
+ unsigned char *buffer;
+
+ /** Number of isochronous packets. Only used for I/O with isochronous
+ * endpoints. */
+ int num_iso_packets;
+
+ /** Isochronous packet descriptors, for isochronous transfers only. */
+ struct libusb_iso_packet_descriptor iso_packet_desc
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+ [] /* valid C99 code */
+#else
+ [0] /* non-standard, but usually working code */
+#endif
+ ;
+};
+
+/** \ingroup libusb_misc
+ * Capabilities supported by an instance of libusb on the current running
+ * platform. Test if the loaded library supports a given capability by calling
+ * \ref libusb_has_capability().
+ */
+enum libusb_capability {
+ /** The libusb_has_capability() API is available. */
+ LIBUSB_CAP_HAS_CAPABILITY = 0x0000,
+ /** Hotplug support is available on this platform. */
+ LIBUSB_CAP_HAS_HOTPLUG = 0x0001,
+ /** The library can access HID devices without requiring user intervention.
+ * Note that before being able to actually access an HID device, you may
+ * still have to call additional libusb functions such as
+ * \ref libusb_detach_kernel_driver(). */
+ LIBUSB_CAP_HAS_HID_ACCESS = 0x0100,
+ /** The library supports detaching of the default USB driver, using
+ * \ref libusb_detach_kernel_driver(), if one is set by the OS kernel */
+ LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER = 0x0101
+};
+
+/** \ingroup libusb_lib
+ * Log message levels.
+ * - LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library (default)
+ * - LIBUSB_LOG_LEVEL_ERROR (1) : error messages are printed to stderr
+ * - LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to stderr
+ * - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stdout, warning
+ * and error messages are printed to stderr
+ * - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stdout,
+ * warnings and errors to stderr
+ */
+enum libusb_log_level {
+ LIBUSB_LOG_LEVEL_NONE = 0,
+ LIBUSB_LOG_LEVEL_ERROR,
+ LIBUSB_LOG_LEVEL_WARNING,
+ LIBUSB_LOG_LEVEL_INFO,
+ LIBUSB_LOG_LEVEL_DEBUG,
+};
+
+int LIBUSB_CALL libusb_init(libusb_context **ctx);
+void LIBUSB_CALL libusb_exit(libusb_context *ctx);
+void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level);
+const struct libusb_version * LIBUSB_CALL libusb_get_version(void);
+int LIBUSB_CALL libusb_has_capability(uint32_t capability);
+const char * LIBUSB_CALL libusb_error_name(int errcode);
+int LIBUSB_CALL libusb_setlocale(const char *locale);
+const char * LIBUSB_CALL libusb_strerror(enum libusb_error errcode);
+
+ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context *ctx,
+ libusb_device ***list);
+void LIBUSB_CALL libusb_free_device_list(libusb_device **list,
+ int unref_devices);
+libusb_device * LIBUSB_CALL libusb_ref_device(libusb_device *dev);
+void LIBUSB_CALL libusb_unref_device(libusb_device *dev);
+
+int LIBUSB_CALL libusb_get_configuration(libusb_device_handle *dev,
+ int *config);
+int LIBUSB_CALL libusb_get_device_descriptor(libusb_device *dev,
+ struct libusb_device_descriptor *desc);
+int LIBUSB_CALL libusb_get_active_config_descriptor(libusb_device *dev,
+ struct libusb_config_descriptor **config);
+int LIBUSB_CALL libusb_get_config_descriptor(libusb_device *dev,
+ uint8_t config_index, struct libusb_config_descriptor **config);
+int LIBUSB_CALL libusb_get_config_descriptor_by_value(libusb_device *dev,
+ uint8_t bConfigurationValue, struct libusb_config_descriptor **config);
+void LIBUSB_CALL libusb_free_config_descriptor(
+ struct libusb_config_descriptor *config);
+int LIBUSB_CALL libusb_get_ss_endpoint_companion_descriptor(
+ struct libusb_context *ctx,
+ const struct libusb_endpoint_descriptor *endpoint,
+ struct libusb_ss_endpoint_companion_descriptor **ep_comp);
+void LIBUSB_CALL libusb_free_ss_endpoint_companion_descriptor(
+ struct libusb_ss_endpoint_companion_descriptor *ep_comp);
+int LIBUSB_CALL libusb_get_bos_descriptor(libusb_device_handle *dev_handle,
+ struct libusb_bos_descriptor **bos);
+void LIBUSB_CALL libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos);
+int LIBUSB_CALL libusb_get_usb_2_0_extension_descriptor(
+ struct libusb_context *ctx,
+ struct libusb_bos_dev_capability_descriptor *dev_cap,
+ struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension);
+void LIBUSB_CALL libusb_free_usb_2_0_extension_descriptor(
+ struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension);
+int LIBUSB_CALL libusb_get_ss_usb_device_capability_descriptor(
+ struct libusb_context *ctx,
+ struct libusb_bos_dev_capability_descriptor *dev_cap,
+ struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_cap);
+void LIBUSB_CALL libusb_free_ss_usb_device_capability_descriptor(
+ struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap);
+int LIBUSB_CALL libusb_get_container_id_descriptor(struct libusb_context *ctx,
+ struct libusb_bos_dev_capability_descriptor *dev_cap,
+ struct libusb_container_id_descriptor **container_id);
+void LIBUSB_CALL libusb_free_container_id_descriptor(
+ struct libusb_container_id_descriptor *container_id);
+uint8_t LIBUSB_CALL libusb_get_bus_number(libusb_device *dev);
+uint8_t LIBUSB_CALL libusb_get_port_number(libusb_device *dev);
+int LIBUSB_CALL libusb_get_port_numbers(libusb_device *dev, uint8_t* port_numbers, int port_numbers_len);
+LIBUSB_DEPRECATED_FOR(libusb_get_port_numbers)
+int LIBUSB_CALL libusb_get_port_path(libusb_context *ctx, libusb_device *dev, uint8_t* path, uint8_t path_length);
+libusb_device * LIBUSB_CALL libusb_get_parent(libusb_device *dev);
+uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device *dev);
+int LIBUSB_CALL libusb_get_device_speed(libusb_device *dev);
+int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev,
+ unsigned char endpoint);
+int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev,
+ unsigned char endpoint);
+
+int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **dev_handle);
+void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle);
+libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle);
+
+int LIBUSB_CALL libusb_set_configuration(libusb_device_handle *dev_handle,
+ int configuration);
+int LIBUSB_CALL libusb_claim_interface(libusb_device_handle *dev_handle,
+ int interface_number);
+int LIBUSB_CALL libusb_release_interface(libusb_device_handle *dev_handle,
+ int interface_number);
+
+libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid(
+ libusb_context *ctx, uint16_t vendor_id, uint16_t product_id);
+
+int LIBUSB_CALL libusb_set_interface_alt_setting(libusb_device_handle *dev_handle,
+ int interface_number, int alternate_setting);
+int LIBUSB_CALL libusb_clear_halt(libusb_device_handle *dev_handle,
+ unsigned char endpoint);
+int LIBUSB_CALL libusb_reset_device(libusb_device_handle *dev_handle);
+
+int LIBUSB_CALL libusb_alloc_streams(libusb_device_handle *dev_handle,
+ uint32_t num_streams, unsigned char *endpoints, int num_endpoints);
+int LIBUSB_CALL libusb_free_streams(libusb_device_handle *dev_handle,
+ unsigned char *endpoints, int num_endpoints);
+
+unsigned char * LIBUSB_CALL libusb_dev_mem_alloc(libusb_device_handle *dev_handle,
+ size_t length);
+int LIBUSB_CALL libusb_dev_mem_free(libusb_device_handle *dev_handle,
+ unsigned char *buffer, size_t length);
+
+int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle *dev_handle,
+ int interface_number);
+int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle *dev_handle,
+ int interface_number);
+int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle *dev_handle,
+ int interface_number);
+int LIBUSB_CALL libusb_set_auto_detach_kernel_driver(
+ libusb_device_handle *dev_handle, int enable);
+
+/* async I/O */
+
+/** \ingroup libusb_asyncio
+ * Get the data section of a control transfer. This convenience function is here
+ * to remind you that the data does not start until 8 bytes into the actual
+ * buffer, as the setup packet comes first.
+ *
+ * Calling this function only makes sense from a transfer callback function,
+ * or situations where you have already allocated a suitably sized buffer at
+ * transfer->buffer.
+ *
+ * \param transfer a transfer
+ * \returns pointer to the first byte of the data section
+ */
+static inline unsigned char *libusb_control_transfer_get_data(
+ struct libusb_transfer *transfer)
+{
+ return transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
+}
+
+/** \ingroup libusb_asyncio
+ * Get the control setup packet of a control transfer. This convenience
+ * function is here to remind you that the control setup occupies the first
+ * 8 bytes of the transfer data buffer.
+ *
+ * Calling this function only makes sense from a transfer callback function,
+ * or situations where you have already allocated a suitably sized buffer at
+ * transfer->buffer.
+ *
+ * \param transfer a transfer
+ * \returns a casted pointer to the start of the transfer data buffer
+ */
+static inline struct libusb_control_setup *libusb_control_transfer_get_setup(
+ struct libusb_transfer *transfer)
+{
+ return (struct libusb_control_setup *)(void *) transfer->buffer;
+}
+
+/** \ingroup libusb_asyncio
+ * Helper function to populate the setup packet (first 8 bytes of the data
+ * buffer) for a control transfer. The wIndex, wValue and wLength values should
+ * be given in host-endian byte order.
+ *
+ * \param buffer buffer to output the setup packet into
+ * This pointer must be aligned to at least 2 bytes boundary.
+ * \param bmRequestType see the
+ * \ref libusb_control_setup::bmRequestType "bmRequestType" field of
+ * \ref libusb_control_setup
+ * \param bRequest see the
+ * \ref libusb_control_setup::bRequest "bRequest" field of
+ * \ref libusb_control_setup
+ * \param wValue see the
+ * \ref libusb_control_setup::wValue "wValue" field of
+ * \ref libusb_control_setup
+ * \param wIndex see the
+ * \ref libusb_control_setup::wIndex "wIndex" field of
+ * \ref libusb_control_setup
+ * \param wLength see the
+ * \ref libusb_control_setup::wLength "wLength" field of
+ * \ref libusb_control_setup
+ */
+static inline void libusb_fill_control_setup(unsigned char *buffer,
+ uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
+ uint16_t wLength)
+{
+ struct libusb_control_setup *setup = (struct libusb_control_setup *)(void *) buffer;
+ setup->bmRequestType = bmRequestType;
+ setup->bRequest = bRequest;
+ setup->wValue = libusb_cpu_to_le16(wValue);
+ setup->wIndex = libusb_cpu_to_le16(wIndex);
+ setup->wLength = libusb_cpu_to_le16(wLength);
+}
+
+struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(int iso_packets);
+int LIBUSB_CALL libusb_submit_transfer(struct libusb_transfer *transfer);
+int LIBUSB_CALL libusb_cancel_transfer(struct libusb_transfer *transfer);
+void LIBUSB_CALL libusb_free_transfer(struct libusb_transfer *transfer);
+void LIBUSB_CALL libusb_transfer_set_stream_id(
+ struct libusb_transfer *transfer, uint32_t stream_id);
+uint32_t LIBUSB_CALL libusb_transfer_get_stream_id(
+ struct libusb_transfer *transfer);
+
+/** \ingroup libusb_asyncio
+ * Helper function to populate the required \ref libusb_transfer fields
+ * for a control transfer.
+ *
+ * If you pass a transfer buffer to this function, the first 8 bytes will
+ * be interpreted as a control setup packet, and the wLength field will be
+ * used to automatically populate the \ref libusb_transfer::length "length"
+ * field of the transfer. Therefore the recommended approach is:
+ * -# Allocate a suitably sized data buffer (including space for control setup)
+ * -# Call libusb_fill_control_setup()
+ * -# If this is a host-to-device transfer with a data stage, put the data
+ * in place after the setup packet
+ * -# Call this function
+ * -# Call libusb_submit_transfer()
+ *
+ * It is also legal to pass a NULL buffer to this function, in which case this
+ * function will not attempt to populate the length field. Remember that you
+ * must then populate the buffer and length fields later.
+ *
+ * \param transfer the transfer to populate
+ * \param dev_handle handle of the device that will handle the transfer
+ * \param buffer data buffer. If provided, this function will interpret the
+ * first 8 bytes as a setup packet and infer the transfer length from that.
+ * This pointer must be aligned to at least 2 bytes boundary.
+ * \param callback callback function to be invoked on transfer completion
+ * \param user_data user data to pass to callback function
+ * \param timeout timeout for the transfer in milliseconds
+ */
+static inline void libusb_fill_control_transfer(
+ struct libusb_transfer *transfer, libusb_device_handle *dev_handle,
+ unsigned char *buffer, libusb_transfer_cb_fn callback, void *user_data,
+ unsigned int timeout)
+{
+ struct libusb_control_setup *setup = (struct libusb_control_setup *)(void *) buffer;
+ transfer->dev_handle = dev_handle;
+ transfer->endpoint = 0;
+ transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL;
+ transfer->timeout = timeout;
+ transfer->buffer = buffer;
+ if (setup)
+ transfer->length = (int) (LIBUSB_CONTROL_SETUP_SIZE
+ + libusb_le16_to_cpu(setup->wLength));
+ transfer->user_data = user_data;
+ transfer->callback = callback;
+}
+
+/** \ingroup libusb_asyncio
+ * Helper function to populate the required \ref libusb_transfer fields
+ * for a bulk transfer.
+ *
+ * \param transfer the transfer to populate
+ * \param dev_handle handle of the device that will handle the transfer
+ * \param endpoint address of the endpoint where this transfer will be sent
+ * \param buffer data buffer
+ * \param length length of data buffer
+ * \param callback callback function to be invoked on transfer completion
+ * \param user_data user data to pass to callback function
+ * \param timeout timeout for the transfer in milliseconds
+ */
+static inline void libusb_fill_bulk_transfer(struct libusb_transfer *transfer,
+ libusb_device_handle *dev_handle, unsigned char endpoint,
+ unsigned char *buffer, int length, libusb_transfer_cb_fn callback,
+ void *user_data, unsigned int timeout)
+{
+ transfer->dev_handle = dev_handle;
+ transfer->endpoint = endpoint;
+ transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
+ transfer->timeout = timeout;
+ transfer->buffer = buffer;
+ transfer->length = length;
+ transfer->user_data = user_data;
+ transfer->callback = callback;
+}
+
+/** \ingroup libusb_asyncio
+ * Helper function to populate the required \ref libusb_transfer fields
+ * for a bulk transfer using bulk streams.
+ *
+ * Since version 1.0.19, \ref LIBUSB_API_VERSION >= 0x01000103
+ *
+ * \param transfer the transfer to populate
+ * \param dev_handle handle of the device that will handle the transfer
+ * \param endpoint address of the endpoint where this transfer will be sent
+ * \param stream_id bulk stream id for this transfer
+ * \param buffer data buffer
+ * \param length length of data buffer
+ * \param callback callback function to be invoked on transfer completion
+ * \param user_data user data to pass to callback function
+ * \param timeout timeout for the transfer in milliseconds
+ */
+static inline void libusb_fill_bulk_stream_transfer(
+ struct libusb_transfer *transfer, libusb_device_handle *dev_handle,
+ unsigned char endpoint, uint32_t stream_id,
+ unsigned char *buffer, int length, libusb_transfer_cb_fn callback,
+ void *user_data, unsigned int timeout)
+{
+ libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer,
+ length, callback, user_data, timeout);
+ transfer->type = LIBUSB_TRANSFER_TYPE_BULK_STREAM;
+ libusb_transfer_set_stream_id(transfer, stream_id);
+}
+
+/** \ingroup libusb_asyncio
+ * Helper function to populate the required \ref libusb_transfer fields
+ * for an interrupt transfer.
+ *
+ * \param transfer the transfer to populate
+ * \param dev_handle handle of the device that will handle the transfer
+ * \param endpoint address of the endpoint where this transfer will be sent
+ * \param buffer data buffer
+ * \param length length of data buffer
+ * \param callback callback function to be invoked on transfer completion
+ * \param user_data user data to pass to callback function
+ * \param timeout timeout for the transfer in milliseconds
+ */
+static inline void libusb_fill_interrupt_transfer(
+ struct libusb_transfer *transfer, libusb_device_handle *dev_handle,
+ unsigned char endpoint, unsigned char *buffer, int length,
+ libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout)
+{
+ transfer->dev_handle = dev_handle;
+ transfer->endpoint = endpoint;
+ transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
+ transfer->timeout = timeout;
+ transfer->buffer = buffer;
+ transfer->length = length;
+ transfer->user_data = user_data;
+ transfer->callback = callback;
+}
+
+/** \ingroup libusb_asyncio
+ * Helper function to populate the required \ref libusb_transfer fields
+ * for an isochronous transfer.
+ *
+ * \param transfer the transfer to populate
+ * \param dev_handle handle of the device that will handle the transfer
+ * \param endpoint address of the endpoint where this transfer will be sent
+ * \param buffer data buffer
+ * \param length length of data buffer
+ * \param num_iso_packets the number of isochronous packets
+ * \param callback callback function to be invoked on transfer completion
+ * \param user_data user data to pass to callback function
+ * \param timeout timeout for the transfer in milliseconds
+ */
+static inline void libusb_fill_iso_transfer(struct libusb_transfer *transfer,
+ libusb_device_handle *dev_handle, unsigned char endpoint,
+ unsigned char *buffer, int length, int num_iso_packets,
+ libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout)
+{
+ transfer->dev_handle = dev_handle;
+ transfer->endpoint = endpoint;
+ transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
+ transfer->timeout = timeout;
+ transfer->buffer = buffer;
+ transfer->length = length;
+ transfer->num_iso_packets = num_iso_packets;
+ transfer->user_data = user_data;
+ transfer->callback = callback;
+}
+
+/** \ingroup libusb_asyncio
+ * Convenience function to set the length of all packets in an isochronous
+ * transfer, based on the num_iso_packets field in the transfer structure.
+ *
+ * \param transfer a transfer
+ * \param length the length to set in each isochronous packet descriptor
+ * \see libusb_get_max_packet_size()
+ */
+static inline void libusb_set_iso_packet_lengths(
+ struct libusb_transfer *transfer, unsigned int length)
+{
+ int i;
+ for (i = 0; i < transfer->num_iso_packets; i++)
+ transfer->iso_packet_desc[i].length = length;
+}
+
+/** \ingroup libusb_asyncio
+ * Convenience function to locate the position of an isochronous packet
+ * within the buffer of an isochronous transfer.
+ *
+ * This is a thorough function which loops through all preceding packets,
+ * accumulating their lengths to find the position of the specified packet.
+ * Typically you will assign equal lengths to each packet in the transfer,
+ * and hence the above method is sub-optimal. You may wish to use
+ * libusb_get_iso_packet_buffer_simple() instead.
+ *
+ * \param transfer a transfer
+ * \param packet the packet to return the address of
+ * \returns the base address of the packet buffer inside the transfer buffer,
+ * or NULL if the packet does not exist.
+ * \see libusb_get_iso_packet_buffer_simple()
+ */
+static inline unsigned char *libusb_get_iso_packet_buffer(
+ struct libusb_transfer *transfer, unsigned int packet)
+{
+ int i;
+ size_t offset = 0;
+ int _packet;
+
+ /* oops..slight bug in the API. packet is an unsigned int, but we use
+ * signed integers almost everywhere else. range-check and convert to
+ * signed to avoid compiler warnings. FIXME for libusb-2. */
+ if (packet > INT_MAX)
+ return NULL;
+ _packet = (int) packet;
+
+ if (_packet >= transfer->num_iso_packets)
+ return NULL;
+
+ for (i = 0; i < _packet; i++)
+ offset += transfer->iso_packet_desc[i].length;
+
+ return transfer->buffer + offset;
+}
+
+/** \ingroup libusb_asyncio
+ * Convenience function to locate the position of an isochronous packet
+ * within the buffer of an isochronous transfer, for transfers where each
+ * packet is of identical size.
+ *
+ * This function relies on the assumption that every packet within the transfer
+ * is of identical size to the first packet. Calculating the location of
+ * the packet buffer is then just a simple calculation:
+ * buffer + (packet_size * packet)
+ *
+ * Do not use this function on transfers other than those that have identical
+ * packet lengths for each packet.
+ *
+ * \param transfer a transfer
+ * \param packet the packet to return the address of
+ * \returns the base address of the packet buffer inside the transfer buffer,
+ * or NULL if the packet does not exist.
+ * \see libusb_get_iso_packet_buffer()
+ */
+static inline unsigned char *libusb_get_iso_packet_buffer_simple(
+ struct libusb_transfer *transfer, unsigned int packet)
+{
+ int _packet;
+
+ /* oops..slight bug in the API. packet is an unsigned int, but we use
+ * signed integers almost everywhere else. range-check and convert to
+ * signed to avoid compiler warnings. FIXME for libusb-2. */
+ if (packet > INT_MAX)
+ return NULL;
+ _packet = (int) packet;
+
+ if (_packet >= transfer->num_iso_packets)
+ return NULL;
+
+ return transfer->buffer + ((int) transfer->iso_packet_desc[0].length * _packet);
+}
+
+/* sync I/O */
+
+int LIBUSB_CALL libusb_control_transfer(libusb_device_handle *dev_handle,
+ uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
+ unsigned char *data, uint16_t wLength, unsigned int timeout);
+
+int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle *dev_handle,
+ unsigned char endpoint, unsigned char *data, int length,
+ int *actual_length, unsigned int timeout);
+
+int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle,
+ unsigned char endpoint, unsigned char *data, int length,
+ int *actual_length, unsigned int timeout);
+
+/** \ingroup libusb_desc
+ * Retrieve a descriptor from the default control pipe.
+ * This is a convenience function which formulates the appropriate control
+ * message to retrieve the descriptor.
+ *
+ * \param dev_handle a device handle
+ * \param desc_type the descriptor type, see \ref libusb_descriptor_type
+ * \param desc_index the index of the descriptor to retrieve
+ * \param data output buffer for descriptor
+ * \param length size of data buffer
+ * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure
+ */
+static inline int libusb_get_descriptor(libusb_device_handle *dev_handle,
+ uint8_t desc_type, uint8_t desc_index, unsigned char *data, int length)
+{
+ return libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_IN,
+ LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t) ((desc_type << 8) | desc_index),
+ 0, data, (uint16_t) length, 1000);
+}
+
+/** \ingroup libusb_desc
+ * Retrieve a descriptor from a device.
+ * This is a convenience function which formulates the appropriate control
+ * message to retrieve the descriptor. The string returned is Unicode, as
+ * detailed in the USB specifications.
+ *
+ * \param dev_handle a device handle
+ * \param desc_index the index of the descriptor to retrieve
+ * \param langid the language ID for the string descriptor
+ * \param data output buffer for descriptor
+ * \param length size of data buffer
+ * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure
+ * \see libusb_get_string_descriptor_ascii()
+ */
+static inline int libusb_get_string_descriptor(libusb_device_handle *dev_handle,
+ uint8_t desc_index, uint16_t langid, unsigned char *data, int length)
+{
+ return libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_IN,
+ LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t)((LIBUSB_DT_STRING << 8) | desc_index),
+ langid, data, (uint16_t) length, 1000);
+}
+
+int LIBUSB_CALL libusb_get_string_descriptor_ascii(libusb_device_handle *dev_handle,
+ uint8_t desc_index, unsigned char *data, int length);
+
+/* polling and timeouts */
+
+int LIBUSB_CALL libusb_try_lock_events(libusb_context *ctx);
+void LIBUSB_CALL libusb_lock_events(libusb_context *ctx);
+void LIBUSB_CALL libusb_unlock_events(libusb_context *ctx);
+int LIBUSB_CALL libusb_event_handling_ok(libusb_context *ctx);
+int LIBUSB_CALL libusb_event_handler_active(libusb_context *ctx);
+void LIBUSB_CALL libusb_interrupt_event_handler(libusb_context *ctx);
+void LIBUSB_CALL libusb_lock_event_waiters(libusb_context *ctx);
+void LIBUSB_CALL libusb_unlock_event_waiters(libusb_context *ctx);
+int LIBUSB_CALL libusb_wait_for_event(libusb_context *ctx, struct timeval *tv);
+
+int LIBUSB_CALL libusb_handle_events_timeout(libusb_context *ctx,
+ struct timeval *tv);
+int LIBUSB_CALL libusb_handle_events_timeout_completed(libusb_context *ctx,
+ struct timeval *tv, int *completed);
+int LIBUSB_CALL libusb_handle_events(libusb_context *ctx);
+int LIBUSB_CALL libusb_handle_events_completed(libusb_context *ctx, int *completed);
+int LIBUSB_CALL libusb_handle_events_locked(libusb_context *ctx,
+ struct timeval *tv);
+int LIBUSB_CALL libusb_pollfds_handle_timeouts(libusb_context *ctx);
+int LIBUSB_CALL libusb_get_next_timeout(libusb_context *ctx,
+ struct timeval *tv);
+
+/** \ingroup libusb_poll
+ * File descriptor for polling
+ */
+struct libusb_pollfd {
+ /** Numeric file descriptor */
+ int fd;
+
+ /** Event flags to poll for from . POLLIN indicates that you
+ * should monitor this file descriptor for becoming ready to read from,
+ * and POLLOUT indicates that you should monitor this file descriptor for
+ * nonblocking write readiness. */
+ short events;
+};
+
+/** \ingroup libusb_poll
+ * Callback function, invoked when a new file descriptor should be added
+ * to the set of file descriptors monitored for events.
+ * \param fd the new file descriptor
+ * \param events events to monitor for, see \ref libusb_pollfd for a
+ * description
+ * \param user_data User data pointer specified in
+ * libusb_set_pollfd_notifiers() call
+ * \see libusb_set_pollfd_notifiers()
+ */
+typedef void (LIBUSB_CALL *libusb_pollfd_added_cb)(int fd, short events,
+ void *user_data);
+
+/** \ingroup libusb_poll
+ * Callback function, invoked when a file descriptor should be removed from
+ * the set of file descriptors being monitored for events. After returning
+ * from this callback, do not use that file descriptor again.
+ * \param fd the file descriptor to stop monitoring
+ * \param user_data User data pointer specified in
+ * libusb_set_pollfd_notifiers() call
+ * \see libusb_set_pollfd_notifiers()
+ */
+typedef void (LIBUSB_CALL *libusb_pollfd_removed_cb)(int fd, void *user_data);
+
+const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds(
+ libusb_context *ctx);
+void LIBUSB_CALL libusb_free_pollfds(const struct libusb_pollfd **pollfds);
+void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx,
+ libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
+ void *user_data);
+
+/** \ingroup libusb_hotplug
+ * Callback handle.
+ *
+ * Callbacks handles are generated by libusb_hotplug_register_callback()
+ * and can be used to deregister callbacks. Callback handles are unique
+ * per libusb_context and it is safe to call libusb_hotplug_deregister_callback()
+ * on an already deregisted callback.
+ *
+ * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
+ *
+ * For more information, see \ref libusb_hotplug.
+ */
+typedef int libusb_hotplug_callback_handle;
+
+/** \ingroup libusb_hotplug
+ *
+ * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
+ *
+ * Flags for hotplug events */
+typedef enum {
+ /** Default value when not using any flags. */
+ LIBUSB_HOTPLUG_NO_FLAGS = 0,
+
+ /** Arm the callback and fire it for all matching currently attached devices. */
+ LIBUSB_HOTPLUG_ENUMERATE = 1<<0,
+} libusb_hotplug_flag;
+
+/** \ingroup libusb_hotplug
+ *
+ * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
+ *
+ * Hotplug events */
+typedef enum {
+ /** A device has been plugged in and is ready to use */
+ LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED = 0x01,
+
+ /** A device has left and is no longer available.
+ * It is the user's responsibility to call libusb_close on any handle associated with a disconnected device.
+ * It is safe to call libusb_get_device_descriptor on a device that has left */
+ LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT = 0x02,
+} libusb_hotplug_event;
+
+/** \ingroup libusb_hotplug
+ * Wildcard matching for hotplug events */
+#define LIBUSB_HOTPLUG_MATCH_ANY -1
+
+/** \ingroup libusb_hotplug
+ * Hotplug callback function type. When requesting hotplug event notifications,
+ * you pass a pointer to a callback function of this type.
+ *
+ * This callback may be called by an internal event thread and as such it is
+ * recommended the callback do minimal processing before returning.
+ *
+ * libusb will call this function later, when a matching event had happened on
+ * a matching device. See \ref libusb_hotplug for more information.
+ *
+ * It is safe to call either libusb_hotplug_register_callback() or
+ * libusb_hotplug_deregister_callback() from within a callback function.
+ *
+ * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
+ *
+ * \param ctx context of this notification
+ * \param device libusb_device this event occurred on
+ * \param event event that occurred
+ * \param user_data user data provided when this callback was registered
+ * \returns bool whether this callback is finished processing events.
+ * returning 1 will cause this callback to be deregistered
+ */
+typedef int (LIBUSB_CALL *libusb_hotplug_callback_fn)(libusb_context *ctx,
+ libusb_device *device,
+ libusb_hotplug_event event,
+ void *user_data);
+
+/** \ingroup libusb_hotplug
+ * Register a hotplug callback function
+ *
+ * Register a callback with the libusb_context. The callback will fire
+ * when a matching event occurs on a matching device. The callback is
+ * armed until either it is deregistered with libusb_hotplug_deregister_callback()
+ * or the supplied callback returns 1 to indicate it is finished processing events.
+ *
+ * If the \ref LIBUSB_HOTPLUG_ENUMERATE is passed the callback will be
+ * called with a \ref LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED for all devices
+ * already plugged into the machine. Note that libusb modifies its internal
+ * device list from a separate thread, while calling hotplug callbacks from
+ * libusb_handle_events(), so it is possible for a device to already be present
+ * on, or removed from, its internal device list, while the hotplug callbacks
+ * still need to be dispatched. This means that when using \ref
+ * LIBUSB_HOTPLUG_ENUMERATE, your callback may be called twice for the arrival
+ * of the same device, once from libusb_hotplug_register_callback() and once
+ * from libusb_handle_events(); and/or your callback may be called for the
+ * removal of a device for which an arrived call was never made.
+ *
+ * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
+ *
+ * \param[in] ctx context to register this callback with
+ * \param[in] events bitwise or of events that will trigger this callback. See \ref
+ * libusb_hotplug_event
+ * \param[in] flags hotplug callback flags. See \ref libusb_hotplug_flag
+ * \param[in] vendor_id the vendor id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
+ * \param[in] product_id the product id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
+ * \param[in] dev_class the device class to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
+ * \param[in] cb_fn the function to be invoked on a matching event/device
+ * \param[in] user_data user data to pass to the callback function
+ * \param[out] callback_handle pointer to store the handle of the allocated callback (can be NULL)
+ * \returns LIBUSB_SUCCESS on success LIBUSB_ERROR code on failure
+ */
+int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx,
+ libusb_hotplug_event events,
+ libusb_hotplug_flag flags,
+ int vendor_id, int product_id,
+ int dev_class,
+ libusb_hotplug_callback_fn cb_fn,
+ void *user_data,
+ libusb_hotplug_callback_handle *callback_handle);
+
+/** \ingroup libusb_hotplug
+ * Deregisters a hotplug callback.
+ *
+ * Deregister a callback from a libusb_context. This function is safe to call from within
+ * a hotplug callback.
+ *
+ * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
+ *
+ * \param[in] ctx context this callback is registered with
+ * \param[in] callback_handle the handle of the callback to deregister
+ */
+void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context *ctx,
+ libusb_hotplug_callback_handle callback_handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/hackrf-sweep/lib/libusb-1.0.21/libusb-1.0.def b/src/hackrf-sweep/lib/libusb-1.0.21/libusb-1.0.def
new file mode 100644
index 0000000..a38a6a6
--- /dev/null
+++ b/src/hackrf-sweep/lib/libusb-1.0.21/libusb-1.0.def
@@ -0,0 +1,346 @@
+LIBRARY "libusb-1.0.dll"
+EXPORTS
+ _libusb_alloc_streams
+ _libusb_alloc_streams@16 = _libusb_alloc_streams
+ _libusb_alloc_transfer
+ _libusb_alloc_transfer@4 = _libusb_alloc_transfer
+ _libusb_attach_kernel_driver
+ _libusb_attach_kernel_driver@8 = _libusb_attach_kernel_driver
+ _libusb_bulk_transfer
+ _libusb_bulk_transfer@24 = _libusb_bulk_transfer
+ _libusb_cancel_transfer
+ _libusb_cancel_transfer@4 = _libusb_cancel_transfer
+ _libusb_claim_interface
+ _libusb_claim_interface@8 = _libusb_claim_interface
+ _libusb_clear_halt
+ _libusb_clear_halt@8 = _libusb_clear_halt
+ _libusb_close
+ _libusb_close@4 = _libusb_close
+ _libusb_control_transfer
+ _libusb_control_transfer@32 = _libusb_control_transfer
+ _libusb_detach_kernel_driver
+ _libusb_detach_kernel_driver@8 = _libusb_detach_kernel_driver
+ _libusb_dev_mem_alloc
+ _libusb_dev_mem_alloc@8 = _libusb_dev_mem_alloc
+ _libusb_dev_mem_free
+ _libusb_dev_mem_free@12 = _libusb_dev_mem_free
+ _libusb_error_name
+ _libusb_error_name@4 = _libusb_error_name
+ _libusb_event_handler_active
+ _libusb_event_handler_active@4 = _libusb_event_handler_active
+ _libusb_event_handling_ok
+ _libusb_event_handling_ok@4 = _libusb_event_handling_ok
+ _libusb_exit
+ _libusb_exit@4 = _libusb_exit
+ _libusb_free_bos_descriptor
+ _libusb_free_bos_descriptor@4 = _libusb_free_bos_descriptor
+ _libusb_free_config_descriptor
+ _libusb_free_config_descriptor@4 = _libusb_free_config_descriptor
+ _libusb_free_container_id_descriptor
+ _libusb_free_container_id_descriptor@4 = _libusb_free_container_id_descriptor
+ _libusb_free_device_list
+ _libusb_free_device_list@8 = _libusb_free_device_list
+ _libusb_free_pollfds
+ _libusb_free_pollfds@4 = _libusb_free_pollfds
+ _libusb_free_ss_endpoint_companion_descriptor
+ _libusb_free_ss_endpoint_companion_descriptor@4 = _libusb_free_ss_endpoint_companion_descriptor
+ _libusb_free_ss_usb_device_capability_descriptor
+ _libusb_free_ss_usb_device_capability_descriptor@4 = _libusb_free_ss_usb_device_capability_descriptor
+ _libusb_free_streams
+ _libusb_free_streams@12 = _libusb_free_streams
+ _libusb_free_transfer
+ _libusb_free_transfer@4 = _libusb_free_transfer
+ _libusb_free_usb_2_0_extension_descriptor
+ _libusb_free_usb_2_0_extension_descriptor@4 = _libusb_free_usb_2_0_extension_descriptor
+ _libusb_get_active_config_descriptor
+ _libusb_get_active_config_descriptor@8 = _libusb_get_active_config_descriptor
+ _libusb_get_bos_descriptor
+ _libusb_get_bos_descriptor@8 = _libusb_get_bos_descriptor
+ _libusb_get_bus_number
+ _libusb_get_bus_number@4 = _libusb_get_bus_number
+ _libusb_get_config_descriptor
+ _libusb_get_config_descriptor@12 = _libusb_get_config_descriptor
+ _libusb_get_config_descriptor_by_value
+ _libusb_get_config_descriptor_by_value@12 = _libusb_get_config_descriptor_by_value
+ _libusb_get_configuration
+ _libusb_get_configuration@8 = _libusb_get_configuration
+ _libusb_get_container_id_descriptor
+ _libusb_get_container_id_descriptor@12 = _libusb_get_container_id_descriptor
+ _libusb_get_device
+ _libusb_get_device@4 = _libusb_get_device
+ _libusb_get_device_address
+ _libusb_get_device_address@4 = _libusb_get_device_address
+ _libusb_get_device_descriptor
+ _libusb_get_device_descriptor@8 = _libusb_get_device_descriptor
+ _libusb_get_device_list
+ _libusb_get_device_list@8 = _libusb_get_device_list
+ _libusb_get_device_speed
+ _libusb_get_device_speed@4 = _libusb_get_device_speed
+ _libusb_get_max_iso_packet_size
+ _libusb_get_max_iso_packet_size@8 = _libusb_get_max_iso_packet_size
+ _libusb_get_max_packet_size
+ _libusb_get_max_packet_size@8 = _libusb_get_max_packet_size
+ _libusb_get_next_timeout
+ _libusb_get_next_timeout@8 = _libusb_get_next_timeout
+ _libusb_get_parent
+ _libusb_get_parent@4 = _libusb_get_parent
+ _libusb_get_pollfds
+ _libusb_get_pollfds@4 = _libusb_get_pollfds
+ _libusb_get_port_number
+ _libusb_get_port_number@4 = _libusb_get_port_number
+ _libusb_get_port_numbers
+ _libusb_get_port_numbers@12 = _libusb_get_port_numbers
+ _libusb_get_port_path
+ _libusb_get_port_path@16 = _libusb_get_port_path
+ _libusb_get_ss_endpoint_companion_descriptor
+ _libusb_get_ss_endpoint_companion_descriptor@12 = _libusb_get_ss_endpoint_companion_descriptor
+ _libusb_get_ss_usb_device_capability_descriptor
+ _libusb_get_ss_usb_device_capability_descriptor@12 = _libusb_get_ss_usb_device_capability_descriptor
+ _libusb_get_string_descriptor_ascii
+ _libusb_get_string_descriptor_ascii@16 = _libusb_get_string_descriptor_ascii
+ _libusb_get_usb_2_0_extension_descriptor
+ _libusb_get_usb_2_0_extension_descriptor@12 = _libusb_get_usb_2_0_extension_descriptor
+ _libusb_get_version
+ _libusb_get_version@0 = _libusb_get_version
+ _libusb_handle_events
+ _libusb_handle_events@4 = _libusb_handle_events
+ _libusb_handle_events_completed
+ _libusb_handle_events_completed@8 = _libusb_handle_events_completed
+ _libusb_handle_events_locked
+ _libusb_handle_events_locked@8 = _libusb_handle_events_locked
+ _libusb_handle_events_timeout
+ _libusb_handle_events_timeout@8 = _libusb_handle_events_timeout
+ _libusb_handle_events_timeout_completed
+ _libusb_handle_events_timeout_completed@12 = _libusb_handle_events_timeout_completed
+ _libusb_has_capability
+ _libusb_has_capability@4 = _libusb_has_capability
+ _libusb_hotplug_deregister_callback
+ _libusb_hotplug_deregister_callback@8 = _libusb_hotplug_deregister_callback
+ _libusb_hotplug_register_callback
+ _libusb_hotplug_register_callback@36 = _libusb_hotplug_register_callback
+ _libusb_init
+ _libusb_init@4 = _libusb_init
+ _libusb_interrupt_event_handler
+ _libusb_interrupt_event_handler@4 = _libusb_interrupt_event_handler
+ _libusb_interrupt_transfer
+ _libusb_interrupt_transfer@24 = _libusb_interrupt_transfer
+ _libusb_kernel_driver_active
+ _libusb_kernel_driver_active@8 = _libusb_kernel_driver_active
+ _libusb_lock_event_waiters
+ _libusb_lock_event_waiters@4 = _libusb_lock_event_waiters
+ _libusb_lock_events
+ _libusb_lock_events@4 = _libusb_lock_events
+ _libusb_open
+ _libusb_open@8 = _libusb_open
+ _libusb_open_device_with_vid_pid
+ _libusb_open_device_with_vid_pid@12 = _libusb_open_device_with_vid_pid
+ _libusb_pollfds_handle_timeouts
+ _libusb_pollfds_handle_timeouts@4 = _libusb_pollfds_handle_timeouts
+ _libusb_ref_device
+ _libusb_ref_device@4 = _libusb_ref_device
+ _libusb_release_interface
+ _libusb_release_interface@8 = _libusb_release_interface
+ _libusb_reset_device
+ _libusb_reset_device@4 = _libusb_reset_device
+ _libusb_set_auto_detach_kernel_driver
+ _libusb_set_auto_detach_kernel_driver@8 = _libusb_set_auto_detach_kernel_driver
+ _libusb_set_configuration
+ _libusb_set_configuration@8 = _libusb_set_configuration
+ _libusb_set_debug
+ _libusb_set_debug@8 = _libusb_set_debug
+ _libusb_set_interface_alt_setting
+ _libusb_set_interface_alt_setting@12 = _libusb_set_interface_alt_setting
+ _libusb_set_pollfd_notifiers
+ _libusb_set_pollfd_notifiers@16 = _libusb_set_pollfd_notifiers
+ _libusb_setlocale
+ _libusb_setlocale@4 = _libusb_setlocale
+ _libusb_strerror
+ _libusb_strerror@4 = _libusb_strerror
+ _libusb_submit_transfer
+ _libusb_submit_transfer@4 = _libusb_submit_transfer
+ _libusb_transfer_get_stream_id
+ _libusb_transfer_get_stream_id@4 = _libusb_transfer_get_stream_id
+ _libusb_transfer_set_stream_id
+ _libusb_transfer_set_stream_id@8 = _libusb_transfer_set_stream_id
+ _libusb_try_lock_events
+ _libusb_try_lock_events@4 = _libusb_try_lock_events
+ _libusb_unlock_event_waiters
+ _libusb_unlock_event_waiters@4 = _libusb_unlock_event_waiters
+ _libusb_unlock_events
+ _libusb_unlock_events@4 = _libusb_unlock_events
+ _libusb_unref_device
+ _libusb_unref_device@4 = _libusb_unref_device
+ _libusb_wait_for_event
+ _libusb_wait_for_event@8 = _libusb_wait_for_event
+ libusb_alloc_streams
+ libusb_alloc_streams@16 = libusb_alloc_streams
+ libusb_alloc_transfer
+ libusb_alloc_transfer@4 = libusb_alloc_transfer
+ libusb_attach_kernel_driver
+ libusb_attach_kernel_driver@8 = libusb_attach_kernel_driver
+ libusb_bulk_transfer
+ libusb_bulk_transfer@24 = libusb_bulk_transfer
+ libusb_cancel_transfer
+ libusb_cancel_transfer@4 = libusb_cancel_transfer
+ libusb_claim_interface
+ libusb_claim_interface@8 = libusb_claim_interface
+ libusb_clear_halt
+ libusb_clear_halt@8 = libusb_clear_halt
+ libusb_close
+ libusb_close@4 = libusb_close
+ libusb_control_transfer
+ libusb_control_transfer@32 = libusb_control_transfer
+ libusb_detach_kernel_driver
+ libusb_detach_kernel_driver@8 = libusb_detach_kernel_driver
+ libusb_dev_mem_alloc
+ libusb_dev_mem_alloc@8 = libusb_dev_mem_alloc
+ libusb_dev_mem_free
+ libusb_dev_mem_free@12 = libusb_dev_mem_free
+ libusb_error_name
+ libusb_error_name@4 = libusb_error_name
+ libusb_event_handler_active
+ libusb_event_handler_active@4 = libusb_event_handler_active
+ libusb_event_handling_ok
+ libusb_event_handling_ok@4 = libusb_event_handling_ok
+ libusb_exit
+ libusb_exit@4 = libusb_exit
+ libusb_free_bos_descriptor
+ libusb_free_bos_descriptor@4 = libusb_free_bos_descriptor
+ libusb_free_config_descriptor
+ libusb_free_config_descriptor@4 = libusb_free_config_descriptor
+ libusb_free_container_id_descriptor
+ libusb_free_container_id_descriptor@4 = libusb_free_container_id_descriptor
+ libusb_free_device_list
+ libusb_free_device_list@8 = libusb_free_device_list
+ libusb_free_pollfds
+ libusb_free_pollfds@4 = libusb_free_pollfds
+ libusb_free_ss_endpoint_companion_descriptor
+ libusb_free_ss_endpoint_companion_descriptor@4 = libusb_free_ss_endpoint_companion_descriptor
+ libusb_free_ss_usb_device_capability_descriptor
+ libusb_free_ss_usb_device_capability_descriptor@4 = libusb_free_ss_usb_device_capability_descriptor
+ libusb_free_streams
+ libusb_free_streams@12 = libusb_free_streams
+ libusb_free_transfer
+ libusb_free_transfer@4 = libusb_free_transfer
+ libusb_free_usb_2_0_extension_descriptor
+ libusb_free_usb_2_0_extension_descriptor@4 = libusb_free_usb_2_0_extension_descriptor
+ libusb_get_active_config_descriptor
+ libusb_get_active_config_descriptor@8 = libusb_get_active_config_descriptor
+ libusb_get_bos_descriptor
+ libusb_get_bos_descriptor@8 = libusb_get_bos_descriptor
+ libusb_get_bus_number
+ libusb_get_bus_number@4 = libusb_get_bus_number
+ libusb_get_config_descriptor
+ libusb_get_config_descriptor@12 = libusb_get_config_descriptor
+ libusb_get_config_descriptor_by_value
+ libusb_get_config_descriptor_by_value@12 = libusb_get_config_descriptor_by_value
+ libusb_get_configuration
+ libusb_get_configuration@8 = libusb_get_configuration
+ libusb_get_container_id_descriptor
+ libusb_get_container_id_descriptor@12 = libusb_get_container_id_descriptor
+ libusb_get_device
+ libusb_get_device@4 = libusb_get_device
+ libusb_get_device_address
+ libusb_get_device_address@4 = libusb_get_device_address
+ libusb_get_device_descriptor
+ libusb_get_device_descriptor@8 = libusb_get_device_descriptor
+ libusb_get_device_list
+ libusb_get_device_list@8 = libusb_get_device_list
+ libusb_get_device_speed
+ libusb_get_device_speed@4 = libusb_get_device_speed
+ libusb_get_max_iso_packet_size
+ libusb_get_max_iso_packet_size@8 = libusb_get_max_iso_packet_size
+ libusb_get_max_packet_size
+ libusb_get_max_packet_size@8 = libusb_get_max_packet_size
+ libusb_get_next_timeout
+ libusb_get_next_timeout@8 = libusb_get_next_timeout
+ libusb_get_parent
+ libusb_get_parent@4 = libusb_get_parent
+ libusb_get_pollfds
+ libusb_get_pollfds@4 = libusb_get_pollfds
+ libusb_get_port_number
+ libusb_get_port_number@4 = libusb_get_port_number
+ libusb_get_port_numbers
+ libusb_get_port_numbers@12 = libusb_get_port_numbers
+ libusb_get_port_path
+ libusb_get_port_path@16 = libusb_get_port_path
+ libusb_get_ss_endpoint_companion_descriptor
+ libusb_get_ss_endpoint_companion_descriptor@12 = libusb_get_ss_endpoint_companion_descriptor
+ libusb_get_ss_usb_device_capability_descriptor
+ libusb_get_ss_usb_device_capability_descriptor@12 = libusb_get_ss_usb_device_capability_descriptor
+ libusb_get_string_descriptor_ascii
+ libusb_get_string_descriptor_ascii@16 = libusb_get_string_descriptor_ascii
+ libusb_get_usb_2_0_extension_descriptor
+ libusb_get_usb_2_0_extension_descriptor@12 = libusb_get_usb_2_0_extension_descriptor
+ libusb_get_version
+ libusb_get_version@0 = libusb_get_version
+ libusb_handle_events
+ libusb_handle_events@4 = libusb_handle_events
+ libusb_handle_events_completed
+ libusb_handle_events_completed@8 = libusb_handle_events_completed
+ libusb_handle_events_locked
+ libusb_handle_events_locked@8 = libusb_handle_events_locked
+ libusb_handle_events_timeout
+ libusb_handle_events_timeout@8 = libusb_handle_events_timeout
+ libusb_handle_events_timeout_completed
+ libusb_handle_events_timeout_completed@12 = libusb_handle_events_timeout_completed
+ libusb_has_capability
+ libusb_has_capability@4 = libusb_has_capability
+ libusb_hotplug_deregister_callback
+ libusb_hotplug_deregister_callback@8 = libusb_hotplug_deregister_callback
+ libusb_hotplug_register_callback
+ libusb_hotplug_register_callback@36 = libusb_hotplug_register_callback
+ libusb_init
+ libusb_init@4 = libusb_init
+ libusb_interrupt_event_handler
+ libusb_interrupt_event_handler@4 = libusb_interrupt_event_handler
+ libusb_interrupt_transfer
+ libusb_interrupt_transfer@24 = libusb_interrupt_transfer
+ libusb_kernel_driver_active
+ libusb_kernel_driver_active@8 = libusb_kernel_driver_active
+ libusb_lock_event_waiters
+ libusb_lock_event_waiters@4 = libusb_lock_event_waiters
+ libusb_lock_events
+ libusb_lock_events@4 = libusb_lock_events
+ libusb_open
+ libusb_open@8 = libusb_open
+ libusb_open_device_with_vid_pid
+ libusb_open_device_with_vid_pid@12 = libusb_open_device_with_vid_pid
+ libusb_pollfds_handle_timeouts
+ libusb_pollfds_handle_timeouts@4 = libusb_pollfds_handle_timeouts
+ libusb_ref_device
+ libusb_ref_device@4 = libusb_ref_device
+ libusb_release_interface
+ libusb_release_interface@8 = libusb_release_interface
+ libusb_reset_device
+ libusb_reset_device@4 = libusb_reset_device
+ libusb_set_auto_detach_kernel_driver
+ libusb_set_auto_detach_kernel_driver@8 = libusb_set_auto_detach_kernel_driver
+ libusb_set_configuration
+ libusb_set_configuration@8 = libusb_set_configuration
+ libusb_set_debug
+ libusb_set_debug@8 = libusb_set_debug
+ libusb_set_interface_alt_setting
+ libusb_set_interface_alt_setting@12 = libusb_set_interface_alt_setting
+ libusb_set_pollfd_notifiers
+ libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers
+ libusb_setlocale
+ libusb_setlocale@4 = libusb_setlocale
+ libusb_strerror
+ libusb_strerror@4 = libusb_strerror
+ libusb_submit_transfer
+ libusb_submit_transfer@4 = libusb_submit_transfer
+ libusb_transfer_get_stream_id
+ libusb_transfer_get_stream_id@4 = libusb_transfer_get_stream_id
+ libusb_transfer_set_stream_id
+ libusb_transfer_set_stream_id@8 = libusb_transfer_set_stream_id
+ libusb_try_lock_events
+ libusb_try_lock_events@4 = libusb_try_lock_events
+ libusb_unlock_event_waiters
+ libusb_unlock_event_waiters@4 = libusb_unlock_event_waiters
+ libusb_unlock_events
+ libusb_unlock_events@4 = libusb_unlock_events
+ libusb_unref_device
+ libusb_unref_device@4 = libusb_unref_device
+ libusb_wait_for_event
+ libusb_wait_for_event@8 = libusb_wait_for_event
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/HackRFSweepSpectrumAnalyzer.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/HackRFSweepSpectrumAnalyzer.java
index c288b90..58aee8f 100644
--- a/src/hackrf-sweep/src-java/jspectrumanalyzer/HackRFSweepSpectrumAnalyzer.java
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/HackRFSweepSpectrumAnalyzer.java
@@ -5,12 +5,24 @@
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
+import java.awt.Frame;
import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.RenderingHints;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.File;
import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.concurrent.ArrayBlockingQueue;
@@ -18,6 +30,8 @@
import javax.swing.ImageIcon;
import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
@@ -34,104 +48,823 @@
import org.jfree.chart.event.ChartProgressEvent;
import org.jfree.chart.event.ChartProgressListener;
import org.jfree.chart.event.OverlayChangeListener;
+import org.jfree.chart.event.PlotChangeEvent;
+import org.jfree.chart.event.PlotChangeListener;
import org.jfree.chart.panel.Overlay;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.ValueMarker;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.chart.title.TextTitle;
import org.jfree.data.Range;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
+import org.jfree.ui.Align;
+import org.jfree.ui.HorizontalAlignment;
import org.jfree.ui.RectangleAnchor;
+import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.TextAnchor;
-import jspectrumanalyzer.core.DatasetSpectrum;
+import jspectrumanalyzer.capture.ScreenCapture;
import jspectrumanalyzer.core.DatasetSpectrumPeak;
import jspectrumanalyzer.core.FFTBins;
+import jspectrumanalyzer.core.FrequencyAllocationTable;
+import jspectrumanalyzer.core.FrequencyAllocations;
+import jspectrumanalyzer.core.FrequencyBand;
+import jspectrumanalyzer.core.FrequencyRange;
import jspectrumanalyzer.core.HackRFSettings;
-import jspectrumanalyzer.core.HackRFSweepSettingsUI;
-import jspectrumanalyzer.core.PowerCalibration;
+import jspectrumanalyzer.core.PersistentDisplay;
import jspectrumanalyzer.core.SpurFilter;
-import jspectrumanalyzer.core.WaterfallPlot;
+import jspectrumanalyzer.core.jfc.XYSeriesCollectionImmutable;
import jspectrumanalyzer.nativebridge.HackRFSweepDataCallback;
import jspectrumanalyzer.nativebridge.HackRFSweepNativeBridge;
+import jspectrumanalyzer.ui.HackRFSweepSettingsUI;
+import jspectrumanalyzer.ui.WaterfallPlot;
+import shared.mvc.MVCController;
+import shared.mvc.ModelValue;
+import shared.mvc.ModelValue.ModelValueBoolean;
+import shared.mvc.ModelValue.ModelValueInt;
+
+public class HackRFSweepSpectrumAnalyzer implements HackRFSettings, HackRFSweepDataCallback {
+
+ private static class PerformanceEntry{
+ final String name;
+ long nanosSum;
+ int count;
+ public PerformanceEntry(String name) {
+ this.name = name;
+ }
+ public void addDrawingTime(long nanos) {
+ nanosSum += nanos;
+ count++;
+ }
+ public void reset() {
+ count = 0;
+ nanosSum = 0;
+ }
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+
+ private static class RuntimePerformanceWatch {
+ /**
+ * incoming full spectrum updates from the hardware
+ */
+ int hwFullSpectrumRefreshes = 0;
+ volatile long lastStatisticsRefreshed = System.currentTimeMillis();
+ PerformanceEntry persisentDisplay = new PerformanceEntry("Pers.disp");
+ PerformanceEntry waterfallUpdate = new PerformanceEntry("Wtrfall.upd");
+ PerformanceEntry waterfallDraw = new PerformanceEntry("Wtrfll.drw");
+ PerformanceEntry chartDrawing = new PerformanceEntry("Spectr.chart");
+ PerformanceEntry spurFilter = new PerformanceEntry("Spur.fil");
+
+ private ArrayList entries = new ArrayList<>();
+ public RuntimePerformanceWatch() {
+ entries.add(persisentDisplay);
+ entries.add(waterfallUpdate);
+ entries.add(waterfallDraw);
+ entries.add(chartDrawing);
+ entries.add(spurFilter);
+ }
+
+ public synchronized String generateStatistics() {
+ long timeElapsed = System.currentTimeMillis() - lastStatisticsRefreshed;
+ if (timeElapsed <= 0)
+ timeElapsed = 1;
+ StringBuilder b = new StringBuilder();
+ long sumNanos = 0;
+ for (PerformanceEntry entry : entries) {
+ sumNanos += entry.nanosSum;
+ float callsPerSec = entry.count/(timeElapsed/1000f);
+ b.append(entry.name).append(String.format(" %3dms (%5.1f calls/s) \n", entry.nanosSum/1000000, callsPerSec));
+ }
+ b.append(String.format("Total: %4dms draw time/s: ", sumNanos/1000000));
+ return b.toString();
+// double timeSpentDrawingChartPerSec = chartDrawingSum / (timeElapsed / 1000d) / 1000d;
+// return String.format("Spectrum refreshes: %d / Chart redraws: %d / Drawing time in 1 sec %.2fs",
+// hwFullSpectrumRefreshes, chartRedrawed, timeSpentDrawingChartPerSec);
+
+ }
+
+ public synchronized void reset() {
+ hwFullSpectrumRefreshes = 0;
+ for (PerformanceEntry dataDrawingEntry : entries) {
+ dataDrawingEntry.reset();
+ }
+ lastStatisticsRefreshed = System.currentTimeMillis();
+ }
+ }
+
+ /**
+ * Color palette for UI
+ */
+ protected static class ColorScheme {
+ Color palette0 = Color.white;
+ Color palette1 = new Color(0xe5e5e5);
+ Color palette2 = new Color(0xFCA311);
+ Color palette3 = new Color(0x14213D);
+ Color palette4 = Color.BLACK;
+ }
+
+ public static final int SPECTRUM_PALETTE_SIZE_MIN = 5;
+ private static boolean captureGIF = false;
-public class HackRFSweepSpectrumAnalyzer implements HackRFSettings, HackRFSweepDataCallback
-{
- public static final int SPECTRUM_PALETTE_SIZE_MIN = 5;
+ private static long initTime = System.currentTimeMillis();
+
+ public static void main(String[] args) throws IOException {
+ // System.out.println(new File("").getAbsolutePath());
+ if (args.length > 0) {
+ if (args[0].equals("capturegif")) {
+ captureGIF = true;
+ }
+ }
+ // try { Thread.sleep(20000); System.out.println("Started..."); } catch (InterruptedException e) {}
- public static void main(String[] args) throws IOException
- {
-// System.out.println(new File("").getAbsolutePath());
new HackRFSweepSpectrumAnalyzer();
}
- private XYSeriesCollection dataset = new XYSeriesCollection();
- private JFreeChart chart = ChartFactory.createXYLineChart("Spectrum analyzer", "Frequency [MHz]", "Power [dB]", dataset,
- PlotOrientation.VERTICAL, false, false, false);
-
- private DatasetSpectrumPeak datasetSpectrum;
- private int dropped = 0;
- private JFrame f;
- private boolean filterSpectrum;
- private int lnaGain;
- private ReentrantLock lock = new ReentrantLock();
- private int parameterFFTBinHz = 200000;
- private int parameterGaindB = 40;
- private int parameterMaxFreqMHz = 2500;
- private int parameterMinFreqMHz = 2400;
- private int parameterSamples = 8192;
- private boolean parameterAntPower = false;
- private ArrayBlockingQueue processingQueue = new ArrayBlockingQueue<>(1000);
- private boolean showPeaks = false;
- private float spectrumInitValue = -150;
- private boolean spurRemoval = false;
- private Thread threadHackrfSweep;
- private ArrayBlockingQueue threadLaunchCommands = new ArrayBlockingQueue<>(1);
-
- private Thread threadLauncher;
- private Thread threadProcessing;
- private int vgaGain;
- private ValueMarker waterfallPaletteEndMarker;
- private ValueMarker waterfallPaletteStartMarker;
-
- private WaterfallPlot waterfallPlot;
-
- boolean isChartDrawing = false;
- private ArrayList listeners = new ArrayList<>();
- private boolean isCapturing = true;
-
- public HackRFSweepSpectrumAnalyzer()
- {
- int axisWidthLeft = 70;
- int axisWidthRight = 20;
+ public boolean flagIsHWSendingData = false;
+ private float alphaFreqAllocationTableBandsImage = 0.5f;
+ private float alphaPersistentDisplayImage = 1.0f;
+ private JFreeChart chart;
+
+ private ModelValue chartDataArea = new ModelValue(
+ "Chart data area", new Rectangle2D.Double(0, 0, 1, 1));
+ private XYSeriesCollectionImmutable chartDataset = new XYSeriesCollectionImmutable();
+ private XYLineAndShapeRenderer chartLineRenderer;
+ private ChartPanel chartPanel;
+ private ColorScheme colors = new ColorScheme();
+ private DatasetSpectrumPeak datasetSpectrum;
+ private int dropped = 0;
+ private volatile boolean flagManualGain = false;
+ private volatile boolean forceStopSweep = false;
+ /**
+ * Capture a GIF of the program for the GITHUB page
+ */
+ private ScreenCapture gifCap = null;
+ private ArrayList hRFlisteners = new ArrayList<>();
+ private ArrayBlockingQueue hwProcessingQueue = new ArrayBlockingQueue<>(
+ 1000);
+ private BufferedImage imageFrequencyAllocationTableBands = null;
+ private boolean isChartDrawing = false;
+ private ReentrantLock lock = new ReentrantLock();
+
+ private ModelValueBoolean parameterAntPower = new ModelValueBoolean(
+ "Ant power", false);
+ private ModelValueInt parameterFFTBinHz = new ModelValueInt(
+ "FFT Bin [Hz]", 100000);
+ private ModelValueBoolean parameterFilterSpectrum = new ModelValueBoolean(
+ "Filter", false);
+ private ModelValue parameterFrequency = new ModelValue<>(
+ "Frequency range", new FrequencyRange(2400, 2500));
+
+ private ModelValue parameterFrequencyAllocationTable = new ModelValue(
+ "Frequency allocation table", null);
+
+ private ModelValueInt parameterGainLNA = new ModelValueInt("LNA Gain",
+ 0, 8, 0, 40);
+ private ModelValueInt parameterGainTotal = new ModelValueInt("Gain [dB]",
+ 40);
+ private ModelValueInt parameterGainVGA = new ModelValueInt("VGA Gain",
+ 0, 2, 0, 60);
+ private ModelValueBoolean parameterIsCapturingPaused = new ModelValueBoolean(
+ "Capturing paused", false);
+
+ private ModelValueInt parameterPersistentDisplayPersTime = new ModelValueInt("Persistence time", 30, 1, 1, 60);
+ private ModelValueInt parameterPeakFallRateSecs = new ModelValueInt(
+ "Peak fall rate", 30);
+ private ModelValueBoolean parameterPersistentDisplay = new ModelValueBoolean(
+ "Persistent display", false);
+
+ private ModelValueInt parameterSamples = new ModelValueInt("Samples",
+ 8192);
+
+ private ModelValueBoolean parameterShowPeaks = new ModelValueBoolean(
+ "Show peaks", false);
+
+ private ModelValueBoolean parameterDebugDisplay = new ModelValueBoolean("Debug", false);
+
+ private ModelValue parameterSpectrumLineThickness = new ModelValue<>(
+ "Spectrum line thickness", new BigDecimal("1"));
+ private ModelValueInt parameterSpectrumPaletteSize = new ModelValueInt(
+ "Spectrum palette size", 0);
+ private ModelValueInt parameterSpectrumPaletteStart = new ModelValueInt(
+ "Spectrum palette start", 0);
+
+ private ModelValueBoolean parameterSpurRemoval = new ModelValueBoolean(
+ "Spur removal", false);
+ private ModelValueBoolean parameterWaterfallVisible = new ModelValueBoolean(
+ "Waterfall visible", true);
+ private PersistentDisplay persistentDisplay = new PersistentDisplay();
+ private float spectrumInitValue = -150;
+ private SpurFilter spurFilter;
+ private Thread threadHackrfSweep;
+ private ArrayBlockingQueue threadLaunchCommands = new ArrayBlockingQueue<>(1);
+ private Thread threadLauncher;
+ private Thread threadProcessing;
+ private TextTitle titleFreqBand = new TextTitle("",
+ new Font("Dialog", Font.PLAIN, 11));
+ private RuntimePerformanceWatch perfWatch = new RuntimePerformanceWatch();
+ private JFrame uiFrame;
+ private ValueMarker waterfallPaletteEndMarker;
+ private ValueMarker waterfallPaletteStartMarker;
+ private WaterfallPlot waterfallPlot;
+ private JLabel labelMessages;
+
+ public HackRFSweepSpectrumAnalyzer() {
+ printInit(0);
+
+ if (captureGIF) {
+// parameterFrequency.setValue(new FrequencyRange(700, 2700));
+ parameterFrequency.setValue(new FrequencyRange(2400, 2700));
+ parameterGainTotal.setValue(60);
+ parameterSpurRemoval.setValue(true);
+ parameterPersistentDisplay.setValue(true);
+ parameterFFTBinHz.setValue(500000);
+ parameterFrequencyAllocationTable.setValue(new FrequencyAllocations().getTable().values().stream().findFirst().get());
+ }
- recalculateGains(parameterGaindB);
+ recalculateGains(parameterGainTotal.getValue());
- try
- {
+ try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception e1) {
+ e1.printStackTrace();
}
- catch (Exception e1)
+ // UIManager.getLookAndFeelDefaults().put("TabbedPane.borderHightlightColor", Color.black);
+ // UIManager.getLookAndFeelDefaults().put("TabbedPane.background", Color.black);
+ // UIManager.getLookAndFeelDefaults().put("TabbedPane.contentAreaColor", Color.black);
+ // UIManager.getLookAndFeelDefaults().put("TabbedPane.darkShadow", Color.black);
+ // UIManager.getLookAndFeelDefaults().put("TabbedPane.focus", Color.black);
+ // UIManager.getLookAndFeelDefaults().put("TabbedPane.highlight", Color.black);
+ // UIManager.getLookAndFeelDefaults().put("TabbedPane.light", Color.black);
+ // UIManager.getLookAndFeelDefaults().put("TabbedPane.selected", Color.black);
+ // UIManager.getLookAndFeelDefaults().put("TabbedPane.selectedForeground", Color.black);
+ // UIManager.getLookAndFeelDefaults().put("TabbedPane.selectHighlight", Color.black);
+ // UIManager.getLookAndFeelDefaults().put("TabbedPane.shadow", Color.black);
+ // UIManager.getLookAndFeelDefaults().put("TabbedPane.tabAreaBackground", Color.black);
+
+ Insets insets = new Insets(1, 1, 1, 1);
+ UIManager.getLookAndFeelDefaults().put("TabbedPane.contentBorderInsets", insets);
+ UIManager.getLookAndFeelDefaults().put("TabbedPane.selectedTabPadInsets", insets);
+ UIManager.getLookAndFeelDefaults().put("TabbedPane.tabAreaInsets", insets);
+ // UIManager.getLookAndFeelDefaults().put("", insets);
+ // UIManager.getLookAndFeelDefaults().put("", insets);
+
+ // UIManager.getLookAndFeelDefaults().values().forEach((p) -> {
+ // System.out.println(p.toString());
+ // });
+
+ setupChart();
+
+ setupChartMouseMarkers();
+
+ waterfallPlot = new WaterfallPlot(chartPanel, 300);
+ waterfallPaletteStartMarker = new ValueMarker(waterfallPlot.getSpectrumPaletteStart(), colors.palette2,
+ new BasicStroke(1f));
+ waterfallPaletteEndMarker = new ValueMarker(
+ waterfallPlot.getSpectrumPaletteStart() + waterfallPlot.getSpectrumPaletteSize(), colors.palette2,
+ new BasicStroke(1f));
+ // chart.getXYPlot().addRangeMarker(waterfallPaletteStartMarker);
+ // chart.getXYPlot().addRangeMarker(waterfallPaletteEndMarker);
+
+ printInit(2);
+
+ HackRFSweepSettingsUI settingsPanel = new HackRFSweepSettingsUI(this);
+
+ printInit(3);
+
+
+ JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, chartPanel, waterfallPlot);
+ splitPane.setResizeWeight(0.8);
+ splitPane.setBorder(null);
+
+ labelMessages = new JLabel("dsadasd");
+ labelMessages.setForeground(Color.white);
+ labelMessages.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
+ parameterDebugDisplay.addListener((debug) -> {
+ labelMessages.setVisible(debug);
+ });
+ parameterDebugDisplay.callObservers();
+
+ JPanel splitPanePanel = new JPanel(new BorderLayout());
+ splitPanePanel.setBackground(Color.black);
+ splitPanePanel.add(splitPane, BorderLayout.CENTER);
+ splitPanePanel.add(labelMessages, BorderLayout.SOUTH);
+
+ uiFrame = new JFrame();
+ uiFrame.setUndecorated(captureGIF);
+ uiFrame.setExtendedState(uiFrame.getExtendedState() | Frame.MAXIMIZED_BOTH);
+ uiFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ uiFrame.setLayout(new BorderLayout());
+ uiFrame.setTitle("Spectrum Analyzer - hackrf_sweep");
+ uiFrame.add(splitPanePanel, BorderLayout.CENTER);
+ uiFrame.setMinimumSize(new Dimension(600, 600));
+ uiFrame.add(settingsPanel, BorderLayout.EAST);
+ try {
+ uiFrame.setIconImage(new ImageIcon("program.png").getImage());
+ } catch (Exception e) {
+ // e.printStackTrace();
+ }
+
+ printInit(4);
+ setupFrequencyAllocationTable();
+ printInit(5);
+
+ uiFrame.pack();
+ uiFrame.setVisible(true);
+
+ printInit(6);
+
+ startLauncherThread();
+ restartHackrfSweep();
+
+ /**
+ * register parameter observers
+ */
+ setupParameterObservers();
+
+ //shutdown on exit
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> stopHackrfSweep()));
+
+ if (captureGIF) {
+ try {
+ gifCap = new ScreenCapture(uiFrame, 35 * 1, 10, 5, 760, 660, new File("screenshot.gif"));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public ModelValueBoolean getAntennaPowerEnable() {
+ return parameterAntPower;
+ }
+
+ @Override
+ public ModelValueInt getFFTBinHz() {
+ return parameterFFTBinHz;
+ }
+
+ @Override
+ public ModelValue getFrequency() {
+ return parameterFrequency;
+ }
+
+ @Override
+ public ModelValue getFrequencyAllocationTable() {
+ return parameterFrequencyAllocationTable;
+ }
+
+ @Override
+ public ModelValueInt getGain() {
+ return parameterGainTotal;
+ }
+
+ @Override
+ public ModelValueInt getGainLNA() {
+ return parameterGainLNA;
+ }
+
+ @Override
+ public ModelValueInt getGainVGA() {
+ return parameterGainVGA;
+ }
+
+ @Override
+ public ModelValueInt getPeakFallRate() {
+ return parameterPeakFallRateSecs;
+ }
+
+ @Override
+ public ModelValueInt getSamples() {
+ return parameterSamples;
+ }
+
+ @Override
+ public ModelValue getSpectrumLineThickness() {
+ return parameterSpectrumLineThickness;
+ }
+
+ @Override
+ public ModelValueInt getPersistentDisplayDecayRate() {
+ return parameterPersistentDisplayPersTime;
+ }
+
+ @Override
+ public ModelValueInt getSpectrumPaletteSize() {
+ return parameterSpectrumPaletteSize;
+ }
+
+ @Override
+ public ModelValueInt getSpectrumPaletteStart() {
+ return parameterSpectrumPaletteStart;
+ }
+
+ @Override
+ public ModelValueBoolean isCapturingPaused() {
+ return parameterIsCapturingPaused;
+ }
+
+ @Override
+ public ModelValueBoolean isChartsPeaksVisible() {
+ return parameterShowPeaks;
+ }
+
+ @Override
+ public ModelValueBoolean isDebugDisplay() {
+ return parameterDebugDisplay;
+ }
+
+ @Override
+ public ModelValueBoolean isFilterSpectrum() {
+ return parameterFilterSpectrum;
+ }
+
+ @Override
+ public ModelValueBoolean isPersistentDisplayVisible() {
+ return parameterPersistentDisplay;
+ }
+
+ @Override
+ public ModelValueBoolean isSpurRemoval() {
+ return this.parameterSpurRemoval;
+ }
+
+ @Override
+ public ModelValueBoolean isWaterfallVisible() {
+ return parameterWaterfallVisible;
+ }
+
+ @Override
+ public void newSpectrumData(boolean fullSweepDone, double[] frequencyStart, float fftBinWidthHz,
+ float[] signalPowerdBm) {
+ // System.out.println(frequencyStart+" "+fftBinWidthHz+" "+signalPowerdBm);
+ fireHardwareStateChanged(true);
+ if (!hwProcessingQueue.offer(new FFTBins(fullSweepDone, frequencyStart, fftBinWidthHz, signalPowerdBm))) {
+ System.out.println("queue full");
+ dropped++;
+ }
+ }
+
+ @Override
+ public void registerListener(HackRFEventListener listener) {
+ hRFlisteners.add(listener);
+ }
+
+ @Override
+ public void removeListener(HackRFEventListener listener) {
+ hRFlisteners.remove(listener);
+ }
+
+ private void fireCapturingStateChanged() {
+ SwingUtilities.invokeLater(() -> {
+ synchronized (hRFlisteners) {
+ for (HackRFEventListener hackRFEventListener : hRFlisteners) {
+ try {
+ hackRFEventListener.captureStateChanged(!parameterIsCapturingPaused.getValue());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ });
+ }
+
+ private void fireHardwareStateChanged(boolean sendingData) {
+ if (this.flagIsHWSendingData != sendingData) {
+ this.flagIsHWSendingData = sendingData;
+ SwingUtilities.invokeLater(() -> {
+ synchronized (hRFlisteners) {
+ for (HackRFEventListener hackRFEventListener : hRFlisteners) {
+ try {
+ hackRFEventListener.hardwareStatusChanged(sendingData);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ });
+ }
+ }
+
+ private FrequencyRange getFreq() {
+ return parameterFrequency.getValue();
+ }
+
+ private void printInit(int initNumber) {
+ // System.out.println("Startup "+(initNumber++)+" in " + (System.currentTimeMillis() - initTime) + "ms");
+ }
+
+ private void processingThread() {
+ long counter = 0;
+ long frameCounterChart = 0;
+
+ //mainWhile:
+ //while(true)
{
- e1.printStackTrace();
+ FFTBins bin1 = null;
+ try {
+ bin1 = hwProcessingQueue.take();
+ } catch (InterruptedException e1) {
+ return;
+ }
+ float binHz = bin1.fftBinWidthHz;
+
+ /**
+ * prevents from spectrum chart from using too much CPU
+ */
+ int limitChartRefreshFPS = 30;
+ int limitPersistentRefreshEveryChartFrame = 2;
+
+ // PowerCalibration calibration = new PowerCalibration(-45, -12.5, 40);
+
+ datasetSpectrum = new DatasetSpectrumPeak(binHz, getFreq().getStartMHz(), getFreq().getEndMHz(),
+ spectrumInitValue, 15, parameterPeakFallRateSecs.getValue() * 1000);
+ chart.getXYPlot().getDomainAxis().setRange(getFreq().getStartMHz(), getFreq().getEndMHz());
+
+ XYSeries spectrumPeaksEmpty = new XYSeries("peaks");
+
+ float maxPeakJitterdB = 6;
+ float peakThresholdAboveNoise = 4;
+ int maxPeakBins = 4;
+ int validIterations = 25;
+ spurFilter = new SpurFilter(maxPeakJitterdB, peakThresholdAboveNoise, maxPeakBins, validIterations,
+ datasetSpectrum);
+
+ long lastChartUpdated = System.currentTimeMillis();
+ long lastScanStartTime = System.currentTimeMillis();
+ double lastFreq = 0;
+
+ while (true) {
+ try {
+ counter++;
+ FFTBins bins = hwProcessingQueue.take();
+ if (parameterIsCapturingPaused.getValue())
+ continue;
+ boolean triggerChartRefresh = bins.fullSweepDone;
+ //continue;
+
+ if (bins.freqStart != null && bins.sigPowdBm != null) {
+ // PowerCalibration.correctPower(calibration, parameterGaindB, bins);
+ datasetSpectrum.addNewData(bins);
+ }
+
+ if ((triggerChartRefresh/* || timeDiff > 1000 */)) {
+ // System.out.println("ctr "+counter+" dropped "+dropped);
+ /**
+ * filter first
+ */
+ if (parameterSpurRemoval.getValue()) {
+ long start = System.nanoTime();
+ spurFilter.filterDataset();
+ synchronized (perfWatch) {
+ perfWatch.spurFilter.addDrawingTime(System.nanoTime()-start);
+ }
+ }
+ /**
+ * after filtering, calculate peak spectrum
+ */
+ if (parameterShowPeaks.getValue()) {
+ datasetSpectrum.refreshPeakSpectrum();
+ waterfallPlot.setStatusMessage(String.format("Total Spectrum Peak Power %.1fdBm",
+ datasetSpectrum.calculateSpectrumPeakPower()), 0);
+ }
+
+ /**
+ * Update performance counters
+ */
+ if (System.currentTimeMillis() - perfWatch.lastStatisticsRefreshed > 1000) {
+ synchronized (perfWatch) {
+// waterfallPlot.setStatusMessage(perfWatch.generateStatistics(), 1);
+ perfWatch.waterfallDraw.nanosSum = waterfallPlot.getDrawTimeSumAndReset();
+ perfWatch.waterfallDraw.count = waterfallPlot.getDrawingCounterAndReset();
+ String stats = perfWatch.generateStatistics();
+ SwingUtilities.invokeLater(() -> {
+ labelMessages.setText(stats);
+ });
+ perfWatch.reset();
+ }
+ }
+
+ boolean flagChartRedraw = false;
+ /**
+ * Update chart in the swing thread
+ */
+ if (System.currentTimeMillis() - lastChartUpdated > 1000/limitChartRefreshFPS) {
+ flagChartRedraw = true;
+ frameCounterChart++;
+ lastChartUpdated = System.currentTimeMillis();
+ }
+
+
+ XYSeries spectrumSeries;
+ XYSeries spectrumPeaks;
+
+ if (true) {
+ spectrumSeries = datasetSpectrum.createSpectrumDataset("spectrum");
+
+ if (parameterShowPeaks.getValue()) {
+ spectrumPeaks = datasetSpectrum.createPeaksDataset("peaks");
+ } else {
+ spectrumPeaks = spectrumPeaksEmpty;
+ }
+ } else {
+ spectrumSeries = new XYSeries("spectrum", false, true);
+ spectrumSeries.setNotify(false);
+ datasetSpectrum.fillToXYSeries(spectrumSeries);
+ spectrumSeries.setNotify(true);
+
+ spectrumPeaks =
+ // new XYSeries("peaks");
+ new XYSeries("peaks", false, true);
+ if (parameterShowPeaks.getValue()) {
+ spectrumPeaks.setNotify(false);
+ datasetSpectrum.fillPeaksToXYSeries(spectrumPeaks);
+ spectrumPeaks.setNotify(false);
+ }
+ }
+
+ if (parameterPersistentDisplay.getValue()) {
+ long start = System.nanoTime();
+ boolean redraw = false;
+ if (flagChartRedraw && frameCounterChart % limitPersistentRefreshEveryChartFrame == 0)
+ redraw = true;
+
+ //persistentDisplay.drawSpectrumFloat
+ persistentDisplay.drawSpectrum2
+ (datasetSpectrum,
+ (float) chart.getXYPlot().getRangeAxis().getRange().getLowerBound(),
+ (float) chart.getXYPlot().getRangeAxis().getRange().getUpperBound(), redraw);
+ synchronized (perfWatch) {
+ perfWatch.persisentDisplay.addDrawingTime(System.nanoTime()-start);
+ }
+ }
+
+ /**
+ * do not render it in swing thread because it might
+ * miss data
+ */
+ if (parameterWaterfallVisible.getValue()) {
+ long start = System.nanoTime();
+ waterfallPlot.addNewData(datasetSpectrum);
+ synchronized (perfWatch) {
+ perfWatch.waterfallUpdate.addDrawingTime(System.nanoTime()-start);
+ }
+ }
+
+ if (flagChartRedraw) {
+ if (parameterWaterfallVisible.getValue()) {
+ waterfallPlot.repaint();
+ }
+ SwingUtilities.invokeLater(() -> {
+
+ chart.setNotify(false);
+
+ chartDataset.removeAllSeries();
+ chartDataset.addSeries(spectrumPeaks);
+ chartDataset.addSeries(spectrumSeries);
+ chart.setNotify(true);
+
+ if (gifCap != null) {
+ gifCap.captureFrame();
+ }
+ });
+ }
+
+ synchronized (perfWatch) {
+ perfWatch.hwFullSpectrumRefreshes++;
+ }
+
+ counter = 0;
+ }
+
+ } catch (InterruptedException e) {
+ return;
+ }
+ }
+
}
+ }
+
+ private void recalculateGains(int totalGain) {
/**
- * Color palette for UI
+ * use only lna gain when <=40 when >40, add only vga gain
*/
- Color palette0 = Color.white;
- Color palette1 = new Color(0xe5e5e5);
- Color palette2 = new Color(0xFCA311);
- Color palette3 = new Color(0x14213D);
- Color palette4 = Color.BLACK;
+ int lnaGain = totalGain / 8 * 8; //lna gain has step 8, range <0, 40>
+ if (lnaGain > 40)
+ lnaGain = 40;
+ int vgaGain = lnaGain != 40 ? 0 : ((totalGain - lnaGain) & ~1); //vga gain has step 2, range <0,60>
+ this.parameterGainLNA.setValue(lnaGain);
+ this.parameterGainVGA.setValue(vgaGain);
+ this.parameterGainTotal.setValue(lnaGain + vgaGain);
+ }
+
+ /**
+ * uses fifo queue to process launch commands, only the last launch command
+ * is important, delete others
+ */
+ private synchronized void restartHackrfSweep() {
+ if (threadLaunchCommands.offer(0) == false) {
+ threadLaunchCommands.clear();
+ threadLaunchCommands.offer(0);
+ }
+ }
+
+ /**
+ * no need to synchronize, executes only in the launcher thread
+ */
+ private void restartHackrfSweepExecute() {
+ stopHackrfSweep();
+ threadHackrfSweep = new Thread(() -> {
+ Thread.currentThread().setName("hackrf_sweep");
+ try {
+ forceStopSweep = false;
+ sweep();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+ threadHackrfSweep.start();
+ }
+
+ private void setupChart() {
+ int axisWidthLeft = 70;
+ int axisWidthRight = 20;
+
+ chart = ChartFactory.createXYLineChart("Spectrum analyzer", "Frequency [MHz]", "Power [dB]", chartDataset,
+ PlotOrientation.VERTICAL, false, false, false);
+ chart.getRenderingHints().put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
XYPlot plot = chart.getXYPlot();
NumberAxis domainAxis = ((NumberAxis) plot.getDomainAxis());
NumberAxis rangeAxis = ((NumberAxis) plot.getRangeAxis());
- XYLineAndShapeRenderer rend = new XYLineAndShapeRenderer();
- rend.setBaseShapesVisible(false);
+ chartLineRenderer = new XYLineAndShapeRenderer();
+ chartLineRenderer.setBaseShapesVisible(false);
+ chartLineRenderer.setBaseStroke(new BasicStroke(parameterSpectrumLineThickness.getValue().floatValue()));
+
+ rangeAxis.setAutoRange(false);
+ rangeAxis.setRange(-110, 20);
+ rangeAxis.setTickUnit(new NumberTickUnit(10, new DecimalFormat("###")));
+
+ domainAxis.setNumberFormatOverride(new DecimalFormat(" #.### "));
+
+ chartLineRenderer.setAutoPopulateSeriesStroke(false);
+ chartLineRenderer.setAutoPopulateSeriesPaint(false);
+ chartLineRenderer.setSeriesPaint(0, colors.palette2);
+
+ if (false)
+ chart.addProgressListener(new ChartProgressListener() {
+ StandardTickUnitSource tus = new StandardTickUnitSource();
+
+ @Override
+ public void chartProgress(ChartProgressEvent event) {
+ if (event.getType() == ChartProgressEvent.DRAWING_STARTED) {
+ Range r = domainAxis.getRange();
+ domainAxis.setTickUnit((NumberTickUnit) tus.getCeilingTickUnit(r.getLength() / 20));
+ domainAxis.setMinorTickCount(2);
+ domainAxis.setMinorTickMarksVisible(true);
+
+ }
+ }
+ });
+
+ plot.setDomainGridlinesVisible(false);
+ plot.setRenderer(chartLineRenderer);
+
+ /**
+ * sets empty space around the plot
+ */
+ AxisSpace axisSpace = new AxisSpace();
+ axisSpace.setLeft(axisWidthLeft);
+ axisSpace.setRight(axisWidthRight);
+ axisSpace.setTop(0);
+ axisSpace.setBottom(50);
+ plot.setFixedDomainAxisSpace(axisSpace);//sets width of the domain axis left/right
+ plot.setFixedRangeAxisSpace(axisSpace);//sets heigth of range axis top/bottom
+
+ rangeAxis.setAxisLineVisible(false);
+ rangeAxis.setTickMarksVisible(false);
+
+ plot.setAxisOffset(RectangleInsets.ZERO_INSETS); //no space between range axis and plot
+
+ Font labelFont = new Font(Font.MONOSPACED, Font.BOLD, 16);
+ rangeAxis.setLabelFont(labelFont);
+ rangeAxis.setTickLabelFont(labelFont);
+ rangeAxis.setLabelPaint(colors.palette1);
+ rangeAxis.setTickLabelPaint(colors.palette1);
+ domainAxis.setLabelFont(labelFont);
+ domainAxis.setTickLabelFont(labelFont);
+ domainAxis.setLabelPaint(colors.palette1);
+ domainAxis.setTickLabelPaint(colors.palette1);
+ chartLineRenderer.setBasePaint(Color.white);
+ plot.setBackgroundPaint(colors.palette4);
+ chart.setBackgroundPaint(colors.palette4);
+ chartLineRenderer.setSeriesPaint(1, colors.palette1);
chartPanel = new ChartPanel(chart);
chartPanel.setMaximumDrawWidth(4096);
@@ -142,26 +875,29 @@ public HackRFSweepSpectrumAnalyzer()
chartPanel.setPopupMenu(null);
chartPanel.setMinimumSize(new Dimension(200, 200));
+ printInit(1);
+
/**
- * Draws overlay of waterfall's color scale next to main spectrum chart to show
+ * Draws overlay of waterfall's color scale next to main spectrum chart
+ * to show
*/
- chartPanel.addOverlay(new Overlay()
- {
- @Override public void addChangeListener(OverlayChangeListener listener)
- {
+ chartPanel.addOverlay(new Overlay() {
+ @Override
+ public void addChangeListener(OverlayChangeListener listener) {
}
- @Override public void paintOverlay(Graphics2D g, ChartPanel chartPanel)
- {
-
+ @Override
+ public void paintOverlay(Graphics2D g, ChartPanel chartPanel) {
Rectangle2D area = chartPanel.getChartRenderingInfo().getPlotInfo().getDataArea();
int plotStartX = (int) area.getX();
int plotWidth = (int) area.getWidth();
Rectangle2D subplotArea = chartPanel.getChartRenderingInfo().getPlotInfo().getDataArea();
- int y1 = (int) plot.getRangeAxis().valueToJava2D(waterfallPlot.getSpectrumPaletteStart(), subplotArea, plot.getRangeAxisEdge());
- int y2 = (int) plot.getRangeAxis().valueToJava2D(waterfallPlot.getSpectrumPaletteStart() + waterfallPlot.getSpectrumPaletteSize(), subplotArea,
+ int y1 = (int) plot.getRangeAxis().valueToJava2D(waterfallPlot.getSpectrumPaletteStart(), subplotArea,
+ plot.getRangeAxisEdge());
+ int y2 = (int) plot.getRangeAxis().valueToJava2D(
+ waterfallPlot.getSpectrumPaletteStart() + waterfallPlot.getSpectrumPaletteSize(), subplotArea,
plot.getRangeAxisEdge());
int x = plotStartX + plotWidth;
@@ -170,597 +906,286 @@ public HackRFSweepSpectrumAnalyzer()
waterfallPlot.drawScale(g, x, y2, w, h);
}
- @Override public void removeChangeListener(OverlayChangeListener listener)
- {
+ @Override
+ public void removeChangeListener(OverlayChangeListener listener) {
}
});
- //Align the waterfall plot and the spectrum chart
- chart.addChangeListener(new ChartChangeListener()
- {
- @Override public void chartChanged(ChartChangeEvent event)
- {
- Rectangle2D area = chartPanel.getChartRenderingInfo().getPlotInfo().getDataArea();
- int plotStartX = (int) area.getX();
- int plotWidth = (int) area.getWidth();
- waterfallPlot.setDrawingOffsets(plotStartX, plotWidth);
- // System.out.println("l off "+offLeft+" width "+chartWidth );
+ /**
+ * Draw frequency bands as an overlay
+ */
+ if (true)
+ chartPanel.addOverlay(new Overlay() {
+ @Override
+ public void addChangeListener(OverlayChangeListener listener) {
}
- });
-
- addChartMouseMarkers();
-
- waterfallPlot = new WaterfallPlot(chartPanel, 300);
- waterfallPaletteStartMarker = new ValueMarker(waterfallPlot.getSpectrumPaletteStart(), palette2, new BasicStroke(1f));
- waterfallPaletteEndMarker = new ValueMarker(waterfallPlot.getSpectrumPaletteStart() + waterfallPlot.getSpectrumPaletteSize(), palette2,
- new BasicStroke(1f));
- // chart.getXYPlot().addRangeMarker(waterfallPaletteStartMarker);
- // chart.getXYPlot().addRangeMarker(waterfallPaletteEndMarker);
-
- HackRFSweepSettingsUI settingsPanel = new HackRFSweepSettingsUI(this);
-
- f = new JFrame();
- f.setExtendedState(f.getExtendedState() | JFrame.MAXIMIZED_BOTH);
- f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- f.setLayout(new BorderLayout());
- f.setTitle("Spectrum Analyzer - hackrf_sweep");
- JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, chartPanel, waterfallPlot);
- splitPane.setResizeWeight(0.8);
- splitPane.setBorder(null);
- f.add(splitPane, BorderLayout.CENTER);
- f.setMinimumSize(new Dimension(600, 600));
- f.add(settingsPanel, BorderLayout.EAST);
- try
- {
- f.setIconImage(new ImageIcon("program.png").getImage());
- }
- catch (Exception e)
- {
-// e.printStackTrace();
- }
- f.pack();
- f.setVisible(true);
-
- rangeAxis.setAutoRange(false);
- rangeAxis.setRange(-110, 0);
- rangeAxis.setTickUnit(new NumberTickUnit(10, new DecimalFormat("###")));
-
- domainAxis.setNumberFormatOverride(new DecimalFormat(" #.### "));
-
- rend.setAutoPopulateSeriesStroke(false);
- rend.setAutoPopulateSeriesPaint(false);
- rend.setSeriesPaint(0, palette2);
-
- if (false)
- chart.addProgressListener(new ChartProgressListener()
- {
- StandardTickUnitSource tus = new StandardTickUnitSource();
-
- @Override public void chartProgress(ChartProgressEvent event)
- {
- if (event.getType() == ChartProgressEvent.DRAWING_STARTED)
- {
- Range r = domainAxis.getRange();
- domainAxis.setTickUnit((NumberTickUnit) tus.getCeilingTickUnit(r.getLength() / 20));
- domainAxis.setMinorTickCount(2);
- domainAxis.setMinorTickMarksVisible(true);
-
- }
+ @Override
+ public void paintOverlay(Graphics2D g2, ChartPanel chartPanel) {
+ BufferedImage img = imageFrequencyAllocationTableBands;
+ if (img != null) {
+ Rectangle2D area = chartPanel.getChartRenderingInfo().getPlotInfo().getDataArea();
+ g2.drawImage(img, (int) area.getX(), (int) area.getY(), null);
}
- });
+ }
- plot.setDomainGridlinesVisible(false);
- plot.setRenderer(rend);
+ @Override
+ public void removeChangeListener(OverlayChangeListener listener) {
+ }
+ });
/**
- * sets empty space around the plot
+ * monitors chart data area for change due to no other way to extract
+ * that info from jfreechart when it changes
*/
- AxisSpace axisSpace = new AxisSpace();
- axisSpace.setLeft(axisWidthLeft);
- axisSpace.setRight(axisWidthRight);
- axisSpace.setTop(20);
- axisSpace.setBottom(50);
- plot.setFixedDomainAxisSpace(axisSpace);//sets width of the domain axis left/right
- plot.setFixedRangeAxisSpace(axisSpace);//sets heigth of range axis top/bottom
-
- rangeAxis.setAxisLineVisible(false);
- rangeAxis.setTickMarksVisible(false);
-
- plot.setAxisOffset(RectangleInsets.ZERO_INSETS); //no space between range axis and plot
+ chart.addChangeListener(event -> {
+ Rectangle2D aN = chartPanel.getChartRenderingInfo().getPlotInfo().getDataArea();
+ Rectangle2D aO = chartDataArea.getValue();
+ if (aO.getX() != aN.getX() || aO.getY() != aN.getY() || aO.getWidth() != aN.getWidth()
+ || aO.getHeight() != aN.getHeight()) {
+ chartDataArea.setValue(new Rectangle2D.Double(aN.getX(), aN.getY(), aN.getWidth(), aN.getHeight()));
+ }
+ });
- Font labelFont = new Font(Font.MONOSPACED, Font.BOLD, 16);
- rangeAxis.setLabelFont(labelFont);
- rangeAxis.setTickLabelFont(labelFont);
- rangeAxis.setLabelPaint(palette1);
- rangeAxis.setTickLabelPaint(palette1);
- domainAxis.setLabelFont(labelFont);
- domainAxis.setTickLabelFont(labelFont);
- domainAxis.setLabelPaint(palette1);
- domainAxis.setTickLabelPaint(palette1);
- rend.setBasePaint(Color.white);
- plot.setBackgroundPaint(palette4);
- chart.setBackgroundPaint(palette4);
- rend.setSeriesPaint(1, palette1);
+ chart.addProgressListener(new ChartProgressListener() {
+ private long chartRedrawStarted;
- startLauncherThread();
- restartHackrfSweep();
-
- //shutdown on exit
- Runtime.getRuntime().addShutdownHook(new Thread(new Runnable()
- {
- @Override public void run()
- {
- stopHackrfSweep();
+ @Override
+ public void chartProgress(ChartProgressEvent arg0) {
+ if (arg0.getType() == ChartProgressEvent.DRAWING_STARTED) {
+ chartRedrawStarted = System.nanoTime();
+ } else if (arg0.getType() == ChartProgressEvent.DRAWING_FINISHED) {
+ synchronized (perfWatch) {
+ perfWatch.chartDrawing.addDrawingTime(System.nanoTime() - chartRedrawStarted);
+ }
+ }
}
- }));
+ });
+
+
}
- private void addChartMouseMarkers() {
- ValueMarker freqMarker = new ValueMarker(0, Color.WHITE, new BasicStroke(1f));
+ /**
+ * Displays a cross marker with current frequency and signal strength when
+ * mouse hovers over the frequency chart
+ */
+ private void setupChartMouseMarkers() {
+ ValueMarker freqMarker = new ValueMarker(0, Color.WHITE, new BasicStroke(1f));
freqMarker.setLabelPaint(Color.white);
freqMarker.setLabelAnchor(RectangleAnchor.TOP_RIGHT);
freqMarker.setLabelTextAnchor(TextAnchor.TOP_LEFT);
freqMarker.setLabelFont(new Font(Font.MONOSPACED, Font.BOLD, 16));
- ValueMarker signalMarker = new ValueMarker(0, Color.WHITE, new BasicStroke(1f));
+ ValueMarker signalMarker = new ValueMarker(0, Color.WHITE, new BasicStroke(1f));
signalMarker.setLabelPaint(Color.white);
signalMarker.setLabelAnchor(RectangleAnchor.TOP_RIGHT);
signalMarker.setLabelTextAnchor(TextAnchor.BOTTOM_RIGHT);
signalMarker.setLabelFont(new Font(Font.MONOSPACED, Font.BOLD, 16));
chartPanel.addMouseMotionListener(new MouseMotionAdapter() {
+ DecimalFormat format = new DecimalFormat("0.#");
+
@Override
public void mouseMoved(MouseEvent e) {
- int x = e.getX();
- int y = e.getY();
+ int x = e.getX();
+ int y = e.getY();
- XYPlot plot = chart.getXYPlot();
+ XYPlot plot = chart.getXYPlot();
Rectangle2D subplotArea = chartPanel.getChartRenderingInfo().getPlotInfo().getDataArea();
- double crosshairRange = plot.getRangeAxis().java2DToValue(y, subplotArea, plot.getRangeAxisEdge());
+ double crosshairRange = plot.getRangeAxis().java2DToValue(y, subplotArea, plot.getRangeAxisEdge());
signalMarker.setValue(crosshairRange);
signalMarker.setLabel(String.format("%.1fdB", crosshairRange));
- double crosshairDomain = plot.getDomainAxis().java2DToValue(x, subplotArea, plot.getDomainAxisEdge());
+ double crosshairDomain = plot.getDomainAxis().java2DToValue(x, subplotArea, plot.getDomainAxisEdge());
freqMarker.setValue(crosshairDomain);
freqMarker.setLabel(String.format("%.1fMHz", crosshairDomain));
+
+ FrequencyAllocationTable activeTable = parameterFrequencyAllocationTable.getValue();
+ if (activeTable != null) {
+ FrequencyBand band = activeTable.lookupBand((long) (crosshairDomain * 1000000l));
+ if (band == null)
+ titleFreqBand.setText(" ");
+ else {
+ titleFreqBand.setText(String.format("%s - %s MHz %s", format.format(band.getMHzStartIncl()),
+ format.format(band.getMHzEndExcl()), band.getApplications().replaceAll("/", " / ")));
+ }
+ }
}
});
chartPanel.addMouseListener(new MouseAdapter() {
@Override
- public void mouseExited(MouseEvent e) {
+ public void mouseEntered(MouseEvent e) {
chart.getXYPlot().clearDomainMarkers();
chart.getXYPlot().clearRangeMarkers();
+ chart.getXYPlot().addRangeMarker(signalMarker);
+ chart.getXYPlot().addDomainMarker(freqMarker);
}
+
@Override
- public void mouseEntered(MouseEvent e) {
+ public void mouseExited(MouseEvent e) {
chart.getXYPlot().clearDomainMarkers();
chart.getXYPlot().clearRangeMarkers();
- chart.getXYPlot().addRangeMarker(signalMarker);
- chart.getXYPlot().addDomainMarker(freqMarker);
+ titleFreqBand.setText(" ");
}
});
- }
- public boolean isHWSendingData = false;
- private void fireHardwareStateChanged(boolean sendingData)
- {
- if (this.isHWSendingData != sendingData){
- this.isHWSendingData = sendingData;
- SwingUtilities.invokeLater(new Runnable()
- {
- @Override public void run()
- {
- synchronized (listeners)
- {
- for (HackRFEventListener hackRFEventListener : listeners)
- {
- try
- {
- hackRFEventListener.hardwareStatusChanged(sendingData);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- }
- }
- }
- });
- }
+ titleFreqBand.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 14));
+ titleFreqBand.setPosition(RectangleEdge.BOTTOM);
+ titleFreqBand.setHorizontalAlignment(HorizontalAlignment.LEFT);
+ titleFreqBand.setMargin(0.0, 2.0, 0.0, 2.0);
+ titleFreqBand.setPaint(Color.white);
+ chart.addSubtitle(titleFreqBand);
}
- private void fireCapturingStateChanged(boolean isCapturing)
- {
- if (!this.isCapturing != isCapturing){
- this.isCapturing = isCapturing;
- SwingUtilities.invokeLater(new Runnable()
- {
- @Override public void run()
- {
- synchronized (listeners)
- {
- for (HackRFEventListener hackRFEventListener : listeners)
- {
- try
- {
- hackRFEventListener.captureStateChanged(isCapturing);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- }
- }
+ private void setupFrequencyAllocationTable() {
+ SwingUtilities.invokeLater(() -> {
+ chartPanel.addComponentListener(new ComponentAdapter() {
+ public void componentResized(ComponentEvent e) {
+ redrawFrequencySpectrumTable();
}
});
- }
- }
-
- @Override
- public boolean getAntennaPowerEnable() {
- return parameterAntPower;
- }
-
- @Override
- public void setAntennaPowerEnable(boolean enable) {
- this.parameterAntPower = enable;
- restartHackrfSweep();
- }
-
- @Override public int getFFTBinHz()
- {
- return parameterFFTBinHz;
- }
-
- @Override public int getFrequencyEnd()
- {
- return parameterMaxFreqMHz;
- }
-
- @Override public int getFrequencyStart()
- {
- return parameterMinFreqMHz;
- }
-
- @Override public int getGain()
- {
- return parameterGaindB;
- }
-
- @Override public int getLNAGain()
- {
- return lnaGain;
- }
-
- @Override public int getSamples()
- {
- return parameterSamples;
- }
-
- @Override public int getSpectrumPaletteSize()
- {
- return (int) waterfallPlot.getSpectrumPaletteSize();
- }
-
- @Override public int getSpectrumPaletteStart()
- {
- return (int) waterfallPlot.getSpectrumPaletteStart();
- }
-
- @Override public int getVGAGain()
- {
- return vgaGain;
- }
-
- @Override public boolean isChartsPeaksVisible()
- {
- return showPeaks;
- }
-
- @Override public boolean isFilterSpectrum()
- {
- return filterSpectrum;
- }
-
- @Override public void newSpectrumData(boolean fullSweepDone, double[] frequencyStart, float fftBinWidthHz, float[] signalPowerdBm)
- {
- // System.out.println(frequencyStart+" "+fftBinWidthHz+" "+signalPowerdBm);
- fireHardwareStateChanged(true);
- if (!processingQueue.offer(new FFTBins(fullSweepDone, frequencyStart, fftBinWidthHz, signalPowerdBm)))
- {
- System.out.println("queue full");
- dropped++;
- }
- }
-
- @Override public void setChartPeaksVisibility(boolean visible)
- {
- this.showPeaks = visible;
- DatasetSpectrumPeak p = datasetSpectrum;
- if (p != null)
- {
- p.resetPeaks();
- }
- }
-
- @Override public void setFFTBin(int fftBinHz)
- {
- this.parameterFFTBinHz = fftBinHz;
- restartHackrfSweep();
- }
-
- @Override public void setFilterSpectrum(boolean filter)
- {
- filterSpectrum = filter;
- }
-
- @Override public void setFrequency(int freqStartMHz, int freqEndMHz)
- {
- parameterMinFreqMHz = freqStartMHz;
- parameterMaxFreqMHz = freqEndMHz;
- restartHackrfSweep();
- }
+ chart.getXYPlot().getDomainAxis().addChangeListener((e) -> {
+ redrawFrequencySpectrumTable();
+ });
+ chart.getXYPlot().getRangeAxis().addChangeListener(event -> {
+ redrawFrequencySpectrumTable();
+ System.out.println(event);
+ });
- @Override public void setGain(int gaindB)
- {
- if (gaindB == this.parameterGaindB)
- return;
- recalculateGains(gaindB);
- restartHackrfSweep();
+ });
+ parameterFrequencyAllocationTable.addListener(this::redrawFrequencySpectrumTable);
}
- @Override public void setSamples(int samples)
- {
- this.parameterSamples = samples;
- restartHackrfSweep();
- }
+ private void setupParameterObservers() {
+ Runnable restartHackrf = this::restartHackrfSweep;
+ parameterFrequency.addListener(restartHackrf);
+ parameterAntPower.addListener(restartHackrf);
+ parameterFFTBinHz.addListener(restartHackrf);
+ parameterSamples.addListener(restartHackrf);
+ parameterIsCapturingPaused.addListener(this::fireCapturingStateChanged);
- @Override public void setSpectrumPaletteSize(int dB)
- {
- if (dB < SPECTRUM_PALETTE_SIZE_MIN)
- return;
- waterfallPlot.setSpectrumPaletteSize(dB);
- SwingUtilities.invokeLater(new Runnable()
- {
- @Override public void run()
- {
- waterfallPaletteStartMarker.setValue(waterfallPlot.getSpectrumPaletteStart());
- waterfallPaletteEndMarker.setValue(waterfallPlot.getSpectrumPaletteStart() + waterfallPlot.getSpectrumPaletteSize());
- }
+ parameterGainTotal.addListener((gainTotal) -> {
+ if (flagManualGain) //flag is being adjusted manually by LNA or VGA, do not recalculate the gains
+ return;
+ recalculateGains(gainTotal);
+ restartHackrfSweep();
});
- }
-
- @Override public void setSpectrumPaletteStart(int dB)
- {
- waterfallPlot.setSpectrumPaletteStart(dB);
- SwingUtilities.invokeLater(new Runnable()
- {
- @Override public void run()
- {
- waterfallPaletteStartMarker.setValue(waterfallPlot.getSpectrumPaletteStart());
- waterfallPaletteEndMarker.setValue(waterfallPlot.getSpectrumPaletteStart() + waterfallPlot.getSpectrumPaletteSize());
+ Runnable gainRecalc = () -> {
+ int totalGain = parameterGainLNA.getValue() + parameterGainVGA.getValue();
+ flagManualGain = true;
+ try {
+ parameterGainTotal.setValue(totalGain);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ flagManualGain = false;
+ }
+ restartHackrfSweep();
+ };
+ parameterGainLNA.addListener(gainRecalc);
+ parameterGainVGA.addListener(gainRecalc);
+
+ parameterSpurRemoval.addListener(() -> {
+ SpurFilter filter = spurFilter;
+ if (filter != null) {
+ filter.recalibrate();
}
});
- }
-
- @Override public void setSpurRemoval(boolean enable)
- {
- this.spurRemoval = enable;
- SpurFilter filter = spurFilter;
- if (filter != null){
- filter.recalibrate();
- }
- }
-
- @Override public boolean isSpurRemoval()
- {
- return this.spurRemoval;
- }
-
- @Override public void registerListener(HackRFEventListener listener)
- {
- listeners.add(listener);
- }
-
- @Override public void removeListener(HackRFEventListener listener)
- {
- listeners.remove(listener);
- }
-
- @Override public void setCapturing(boolean capturing)
- {
- isCapturing = capturing;
- fireCapturingStateChanged(isCapturing);
- }
-
- @Override public boolean isCapturing()
- {
- return isCapturing;
- }
-
- private void processingThread()
- {
- int counter = 0;
-
- //mainWhile:
- //while(true)
- {
- FFTBins bin1 = null;
- try
- {
- bin1 = processingQueue.take();
+ parameterShowPeaks.addListener(() -> {
+ DatasetSpectrumPeak p = datasetSpectrum;
+ if (p != null) {
+ p.resetPeaks();
}
- catch (InterruptedException e1)
- {
+ });
+ parameterSpectrumPaletteStart.setValue((int) waterfallPlot.getSpectrumPaletteStart());
+ parameterSpectrumPaletteSize.setValue((int) waterfallPlot.getSpectrumPaletteSize());
+ parameterSpectrumPaletteStart.addListener((dB) -> {
+ waterfallPlot.setSpectrumPaletteStart(dB);
+ SwingUtilities.invokeLater(() -> {
+ waterfallPaletteStartMarker.setValue(waterfallPlot.getSpectrumPaletteStart());
+ waterfallPaletteEndMarker
+ .setValue(waterfallPlot.getSpectrumPaletteStart() + waterfallPlot.getSpectrumPaletteSize());
+ });
+ });
+ parameterSpectrumPaletteSize.addListener((dB) -> {
+ if (dB < SPECTRUM_PALETTE_SIZE_MIN)
return;
- }
- float binHz = bin1.fftBinWidthHz;
-
-// PowerCalibration calibration = new PowerCalibration(-45, -12.5, 40);
-
- datasetSpectrum = new DatasetSpectrumPeak(binHz, parameterMinFreqMHz, parameterMaxFreqMHz, spectrumInitValue, 15, 30000);
- chart.getXYPlot().getDomainAxis().setRange(parameterMinFreqMHz, parameterMaxFreqMHz);
-
- float maxPeakJitterdB = 6;
- float peakThresholdAboveNoise = 4;
- int maxPeakBins = 4;
- int validIterations = 25;
- spurFilter = new SpurFilter(maxPeakJitterdB, peakThresholdAboveNoise, maxPeakBins, validIterations, datasetSpectrum);
-
-
- long lastChartUpdated = System.currentTimeMillis();
- long lastScanStartTime = System.currentTimeMillis();
- double lastFreq = 0;
-
- while (true)
- {
- try
- {
- counter++;
- FFTBins bins = processingQueue.take();
- if (!isCapturing)
- continue;
- boolean triggerChartRefresh = bins.fullSweepDone;
- //continue;
-
- if (bins.freqStart != null && bins.sigPowdBm != null)
- {
-// PowerCalibration.correctPower(calibration, parameterGaindB, bins);
- datasetSpectrum.addNewData(bins);
- }
+ waterfallPlot.setSpectrumPaletteSize(dB);
+ SwingUtilities.invokeLater(() -> {
+ waterfallPaletteStartMarker.setValue(waterfallPlot.getSpectrumPaletteStart());
+ waterfallPaletteEndMarker
+ .setValue(waterfallPlot.getSpectrumPaletteStart() + waterfallPlot.getSpectrumPaletteSize());
+ });
- if ((triggerChartRefresh/* || timeDiff > 1000*/))
- {
- // System.out.println("ctr "+counter+" dropped "+dropped);
-
- /**
- * filter first
- */
- if (spurRemoval){
- spurFilter.filterDataset();
- }
- /**
- * after filtering, calculate peak spectrum
- */
- if (showPeaks){
- datasetSpectrum.refreshPeakSpectrum();
- waterfallPlot.setStatusMessage(String.format("Total Spectrum Peak Power %.1fdBm", datasetSpectrum.calculateSpectrumPeakPower()));
- }
-
- XYSeries spectrumSeries = new XYSeries("spectrum");
- spectrumSeries.setNotify(false);
- datasetSpectrum.fillToXYSeries(spectrumSeries);
- spectrumSeries.setNotify(true);
+ });
+ parameterPeakFallRateSecs.addListener((fallRate) -> {
+ datasetSpectrum.setPeakFalloutMillis(fallRate * 1000l);
+ });
- XYSeries spectrumPeaks;
- if (showPeaks)
- {
- spectrumPeaks = new XYSeries("peaks");
- spectrumPeaks.setNotify(false);
- datasetSpectrum.fillPeaksToXYSeries(spectrumPeaks);
- spectrumPeaks.setNotify(false);
- }
- else
- spectrumPeaks = new XYSeries("peaks");
+ parameterSpectrumLineThickness.addListener((thickness) -> {
+ SwingUtilities.invokeLater(() -> chartLineRenderer.setBaseStroke(new BasicStroke(thickness.floatValue())));
+ });
+
+ parameterPersistentDisplayPersTime.addListener((time) -> {
+ persistentDisplay.setPersistenceTime(time);
+ });
- SwingUtilities.invokeLater(new Runnable()
- {
- @Override public void run()
- {
- chart.setNotify(false);
- dataset.removeAllSeries();
- dataset.addSeries(spectrumPeaks);
- dataset.addSeries(spectrumSeries);
- chart.setNotify(true);
- }
- });
- waterfallPlot.addNewData(datasetSpectrum);
+ int persistentDisplayDownscaleFactor = 4;
+
+ Runnable resetPersistentImage = () -> {
+ boolean display = parameterPersistentDisplay.getValue();
+ persistentDisplay.reset();
+ chart.getXYPlot().setBackgroundImage(display ? persistentDisplay.getDisplayImage().getValue() : null);
+ chart.getXYPlot().setBackgroundImageAlpha(alphaPersistentDisplayImage);
+ };
+ persistentDisplay.getDisplayImage().addListener((image) -> {
+ if (parameterPersistentDisplay.getValue())
+ chart.getXYPlot().setBackgroundImage(image);
+ });
- counter = 0;
- lastChartUpdated = System.currentTimeMillis();
+ registerListener(new HackRFEventAdapter() {
+ @Override
+ public void hardwareStatusChanged(boolean hardwareSendingData) {
+ SwingUtilities.invokeLater(() -> {
+ if (hardwareSendingData && parameterPersistentDisplay.getValue()) {
+ resetPersistentImage.run();
}
-
- }
- catch (InterruptedException e)
- {
- return;
- }
+ });
}
+ });
- }
-
- }
-
- private void recalculateGains(int totalGain)
- {
- /**
- * use only lna gain when <=40
- * when >40, add only vga gain
- */
- lnaGain = totalGain / 8 * 8; //lna gain step 8, max 40
- if (lnaGain > 40)
- lnaGain = 40;
- vgaGain = lnaGain != 40 ? 0 : ((totalGain - lnaGain) & ~1); //vga gain step 2, max 60
- this.parameterGaindB = lnaGain + vgaGain;
- }
+ parameterPersistentDisplay.addListener((display) -> {
+ SwingUtilities.invokeLater(resetPersistentImage::run);
+ });
- /**
- * uses fifo queue to process launch commands, only the last launch command is important, delete others
- */
- private synchronized void restartHackrfSweep()
- {
- if (threadLaunchCommands.offer(0) == false)
- {
- threadLaunchCommands.clear();
- threadLaunchCommands.offer(0);
- }
- }
-
- private volatile boolean forceStopSweep = false;
- private SpurFilter spurFilter;
- private ChartPanel chartPanel;
- /**
- * no need to synchronize, executes only in launcher thread
- */
- private void restartHackrfSweepExecute()
- {
- stopHackrfSweep();
- threadHackrfSweep = new Thread(new Runnable()
- {
- @Override public void run()
- {
- Thread.currentThread().setName("hackrf_sweep");
- try
- {
- forceStopSweep = false;
- sweep();
+ chartDataArea.addListener((area) -> {
+ SwingUtilities.invokeLater(() -> {
+ /*
+ * Align the waterfall plot and the spectrum chart
+ */
+ if (waterfallPlot != null)
+ waterfallPlot.setDrawingOffsets((int) area.getX(), (int) area.getWidth());
+
+ /**
+ * persistent display config
+ */
+ persistentDisplay.setImageSize((int) area.getWidth() / persistentDisplayDownscaleFactor,
+ (int) area.getWidth() / persistentDisplayDownscaleFactor);
+ if (parameterPersistentDisplay.getValue()) {
+ chart.getXYPlot().setBackgroundImage(persistentDisplay.getDisplayImage().getValue());
+ chart.getXYPlot().setBackgroundImageAlpha(alphaPersistentDisplayImage);
}
- catch (IOException e)
- {
- e.printStackTrace();
- }
- }
+ });
});
- threadHackrfSweep.start();
}
- private void startLauncherThread()
- {
- threadLauncher = new Thread(new Runnable()
- {
- @Override public void run()
- {
- Thread.currentThread().setName("Launcher-thread");
- while (true)
- {
- try
- {
- threadLaunchCommands.take();
- restartHackrfSweepExecute();
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
+ private void startLauncherThread() {
+ threadLauncher = new Thread(() -> {
+ Thread.currentThread().setName("Launcher-thread");
+ while (true) {
+ try {
+ threadLaunchCommands.take();
+ restartHackrfSweepExecute();
+ } catch (Exception e) {
+ e.printStackTrace();
}
}
});
@@ -770,44 +1195,31 @@ private void startLauncherThread()
/**
* no need to synchronize, executes only in launcher thread
*/
- private void stopHackrfSweep()
- {
- forceStopSweep = true;
- if (threadHackrfSweep != null)
- {
- while (threadHackrfSweep.isAlive())
- {
- forceStopSweep = true;
-// System.out.println("Calling HackRFSweepNativeBridge.stop()");
+ private void stopHackrfSweep() {
+ forceStopSweep = true;
+ if (threadHackrfSweep != null) {
+ while (threadHackrfSweep.isAlive()) {
+ forceStopSweep = true;
+ // System.out.println("Calling HackRFSweepNativeBridge.stop()");
HackRFSweepNativeBridge.stop();
- try
- {
+ try {
Thread.sleep(20);
- }
- catch (InterruptedException e)
- {
+ } catch (InterruptedException e) {
}
}
- try
- {
+ try {
threadHackrfSweep.join();
- }
- catch (InterruptedException e)
- {
+ } catch (InterruptedException e) {
e.printStackTrace();
}
threadHackrfSweep = null;
}
System.out.println("HackRFSweep thread stopped.");
- if (threadProcessing != null)
- {
+ if (threadProcessing != null) {
threadProcessing.interrupt();
- try
- {
+ try {
threadProcessing.join();
- }
- catch (InterruptedException e)
- {
+ } catch (InterruptedException e) {
e.printStackTrace();
}
threadProcessing = null;
@@ -815,44 +1227,54 @@ private void stopHackrfSweep()
}
}
- private void sweep() throws IOException
- {
+ private void sweep() throws IOException {
lock.lock();
- try
- {
- threadProcessing = new Thread(new Runnable()
- {
- @Override public void run()
- {
- Thread.currentThread().setName("hackrf_sweep data processing thread");
- processingThread();
- }
+ try {
+ threadProcessing = new Thread(() -> {
+ Thread.currentThread().setName("hackrf_sweep data processing thread");
+ processingThread();
});
threadProcessing.start();
/**
* Ensures auto-restart if HW disconnects
*/
- while(forceStopSweep == false){
- System.out.println("Starting hackrf_sweep... " + parameterMinFreqMHz + "-" + parameterMaxFreqMHz + "MHz ");
- System.out.println("hackrf_sweep params: freq " + parameterMinFreqMHz + "-" + parameterMaxFreqMHz + "MHz samples " + parameterSamples + " lna: "
- + lnaGain + " vga: " + vgaGain);
+ while (forceStopSweep == false) {
+ System.out.println(
+ "Starting hackrf_sweep... " + getFreq().getStartMHz() + "-" + getFreq().getEndMHz() + "MHz ");
+ System.out.println("hackrf_sweep params: freq " + getFreq().getStartMHz() + "-" + getFreq().getEndMHz()
+ + "MHz FFTBin " + parameterFFTBinHz.getValue() + "Hz samples " + parameterSamples.getValue()
+ + " lna: " + parameterGainLNA.getValue() + " vga: " + parameterGainVGA.getValue());
fireHardwareStateChanged(false);
- HackRFSweepNativeBridge.start(this, parameterMinFreqMHz, parameterMaxFreqMHz, parameterFFTBinHz, parameterSamples, lnaGain, vgaGain, parameterAntPower);
+ HackRFSweepNativeBridge.start(this, getFreq().getStartMHz(), getFreq().getEndMHz(),
+ parameterFFTBinHz.getValue(), parameterSamples.getValue(), parameterGainLNA.getValue(),
+ parameterGainVGA.getValue(), parameterAntPower.getValue());
fireHardwareStateChanged(false);
- if (forceStopSweep==false){
+ if (forceStopSweep == false) {
Thread.sleep(1000);
}
}
- }
- catch (InterruptedException e)
- {
+ } catch (InterruptedException e) {
e.printStackTrace();
- }
- finally
- {
+ } finally {
lock.unlock();
fireHardwareStateChanged(false);
}
}
+
+ protected void redrawFrequencySpectrumTable() {
+ Rectangle2D area = chartPanel.getChartRenderingInfo().getPlotInfo().getDataArea();
+ FrequencyAllocationTable activeTable = parameterFrequencyAllocationTable.getValue();
+ if (activeTable == null) {
+ imageFrequencyAllocationTableBands = null;
+ } else if (area.getWidth() > 0 && area.getHeight() > 0) {
+ imageFrequencyAllocationTableBands = activeTable.drawAllocationTable((int) area.getWidth(),
+ (int) area.getHeight(), alphaFreqAllocationTableBandsImage, getFreq().getStartMHz() * 1000000l,
+ getFreq().getEndMHz() * 1000000l,
+ //colors.palette4,
+ Color.white,
+ //colors.palette1
+ Color.DARK_GRAY);
+ }
+ }
}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/Version.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/Version.java
index 261da9c..2f21515 100644
--- a/src/hackrf-sweep/src-java/jspectrumanalyzer/Version.java
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/Version.java
@@ -2,6 +2,6 @@
public class Version
{
- public static final String version = "1.3";
+ public static final String version = "1.4";
public static final String url = "https://github.com/pavsa/hackrf-spectrum-analyzer";
}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/capture/GifSequenceWriter.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/capture/GifSequenceWriter.java
new file mode 100644
index 0000000..e03e3fd
--- /dev/null
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/capture/GifSequenceWriter.java
@@ -0,0 +1,169 @@
+package jspectrumanalyzer.capture;
+
+//
+
+//GifSequenceWriter.java
+//
+//Created by Elliot Kroo on 2009-04-25.
+//
+//This work is licensed under the Creative Commons Attribution 3.0 Unported
+//License. To view a copy of this license, visit
+//http://creativecommons.org/licenses/by/3.0/ or send a letter to Creative
+//Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
+
+import javax.imageio.*;
+import javax.imageio.metadata.*;
+import javax.imageio.stream.*;
+import java.awt.image.*;
+import java.io.*;
+import java.util.Iterator;
+
+public class GifSequenceWriter {
+ protected ImageWriter gifWriter;
+ protected ImageWriteParam imageWriteParam;
+ protected IIOMetadata imageMetaData;
+
+ /**
+ * Creates a new GifSequenceWriter
+ *
+ * @param outputStream
+ * the ImageOutputStream to be written to
+ * @param imageType
+ * one of the imageTypes specified in BufferedImage
+ * @param timeBetweenFramesMS
+ * the time between frames in miliseconds
+ * @param loopContinuously
+ * wether the gif should loop repeatedly
+ * @throws IIOException
+ * if no gif ImageWriters are found
+ *
+ * @author Elliot Kroo (elliot[at]kroo[dot]net)
+ */
+ public GifSequenceWriter(ImageOutputStream outputStream, int imageType, int timeBetweenFramesMS,
+ boolean loopContinuously) throws IIOException, IOException {
+ // my method to create a writer
+ gifWriter = getWriter();
+ imageWriteParam = gifWriter.getDefaultWriteParam();
+ ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(imageType);
+
+ imageMetaData = gifWriter.getDefaultImageMetadata(imageTypeSpecifier, imageWriteParam);
+
+ String metaFormatName = imageMetaData.getNativeMetadataFormatName();
+
+ IIOMetadataNode root = (IIOMetadataNode) imageMetaData.getAsTree(metaFormatName);
+
+ IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension");
+
+ graphicsControlExtensionNode.setAttribute("disposalMethod", "none");
+ graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");
+ graphicsControlExtensionNode.setAttribute("transparentColorFlag", "FALSE");
+ graphicsControlExtensionNode.setAttribute("delayTime", Integer.toString(timeBetweenFramesMS / 10));
+ graphicsControlExtensionNode.setAttribute("transparentColorIndex", "0");
+
+ IIOMetadataNode commentsNode = getNode(root, "CommentExtensions");
+ commentsNode.setAttribute("CommentExtension", "Created by MAH");
+
+ IIOMetadataNode appEntensionsNode = getNode(root, "ApplicationExtensions");
+
+ IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension");
+
+ child.setAttribute("applicationID", "NETSCAPE");
+ child.setAttribute("authenticationCode", "2.0");
+
+ int loop = loopContinuously ? 0 : 1;
+
+ child.setUserObject(new byte[] { 0x1, (byte) (loop & 0xFF), (byte) ((loop >> 8) & 0xFF) });
+ appEntensionsNode.appendChild(child);
+
+ imageMetaData.setFromTree(metaFormatName, root);
+
+ gifWriter.setOutput(outputStream);
+
+ gifWriter.prepareWriteSequence(null);
+ }
+
+ public void writeToSequence(RenderedImage img) throws IOException {
+ gifWriter.writeToSequence(new IIOImage(img, null, imageMetaData), imageWriteParam);
+ }
+
+ /**
+ * Close this GifSequenceWriter object. This does not close the underlying
+ * stream, just finishes off the GIF.
+ */
+ public void close() throws IOException {
+ gifWriter.endWriteSequence();
+ }
+
+ /**
+ * Returns the first available GIF ImageWriter using
+ * ImageIO.getImageWritersBySuffix("gif").
+ *
+ * @return a GIF ImageWriter object
+ * @throws IIOException
+ * if no GIF image writers are returned
+ */
+ private static ImageWriter getWriter() throws IIOException {
+ Iterator iter = ImageIO.getImageWritersBySuffix("gif");
+ if (!iter.hasNext()) {
+ throw new IIOException("No GIF Image Writers Exist");
+ } else {
+ return iter.next();
+ }
+ }
+
+ /**
+ * Returns an existing child node, or creates and returns a new child node
+ * (if the requested node does not exist).
+ *
+ * @param rootNode
+ * the IIOMetadataNode to search for the child node.
+ * @param nodeName
+ * the name of the child node.
+ *
+ * @return the child node, if found or a new node created with the given
+ * name.
+ */
+ private static IIOMetadataNode getNode(IIOMetadataNode rootNode, String nodeName) {
+ int nNodes = rootNode.getLength();
+ for (int i = 0; i < nNodes; i++) {
+ if (rootNode.item(i).getNodeName().compareToIgnoreCase(nodeName) == 0) {
+ return ((IIOMetadataNode) rootNode.item(i));
+ }
+ }
+ IIOMetadataNode node = new IIOMetadataNode(nodeName);
+ rootNode.appendChild(node);
+ return (node);
+ }
+
+ /**
+ * public GifSequenceWriter( BufferedOutputStream outputStream, int
+ * imageType, int timeBetweenFramesMS, boolean loopContinuously) {
+ *
+ */
+
+ public static void main(String[] args) throws Exception {
+ if (args.length > 1) {
+ // grab the output image type from the first image in the sequence
+ BufferedImage firstImage = ImageIO.read(new File(args[0]));
+
+ // create a new BufferedOutputStream with the last argument
+ ImageOutputStream output = new FileImageOutputStream(new File(args[args.length - 1]));
+
+ // create a gif sequence with the type of the first image, 1 second
+ // between frames, which loops continuously
+ GifSequenceWriter writer = new GifSequenceWriter(output, firstImage.getType(), 1, false);
+
+ // write out the first image to our sequence...
+ writer.writeToSequence(firstImage);
+ for (int i = 1; i < args.length - 1; i++) {
+ BufferedImage nextImage = ImageIO.read(new File(args[i]));
+ writer.writeToSequence(nextImage);
+ }
+
+ writer.close();
+ output.close();
+ } else {
+ System.out.println("Usage: java GifSequenceWriter [list of gif files] [output file]");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/capture/ScreenCapture.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/capture/ScreenCapture.java
new file mode 100644
index 0000000..3aa55b4
--- /dev/null
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/capture/ScreenCapture.java
@@ -0,0 +1,113 @@
+package jspectrumanalyzer.capture;
+
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import javax.imageio.stream.FileImageOutputStream;
+import javax.imageio.stream.ImageOutputStream;
+import javax.swing.JFrame;
+import javax.swing.SwingUtilities;
+
+/**
+ * Class to capture a video of the whole JFrame into the animated GIF, while capturing only when the view updates with the new data
+ */
+public class ScreenCapture {
+ private final JFrame frame;
+ private final int width, height;
+ private final ImageOutputStream output;
+ private final GifSequenceWriter gif;
+ private final long captureMillis;
+ private final File outputFile;
+ private long startCaptureTS = 0;
+ private long startedCapture = 0;
+ private long lastFrameTS = 0;
+ private int framesCaptured = 0;
+ private ExecutorService saveThread = Executors.newSingleThreadExecutor();
+ private long frameIIntervalMS;
+
+ public ScreenCapture(JFrame frame, int initSecs, int captureSecs, int fps, int width, int height, File outputFile) throws FileNotFoundException, IOException {
+ this.captureMillis = captureSecs*1000L;
+ this.frame = frame;
+ this.width = width;
+ this.height = height;
+ this.outputFile = outputFile;
+
+ this.startCaptureTS = System.currentTimeMillis()+initSecs*1000L;
+ frameIIntervalMS = 1000/fps;
+ frame.setSize(width, height);
+
+ outputFile.delete();
+
+ output = new FileImageOutputStream(outputFile);
+ gif = new GifSequenceWriter(output, BufferedImage.TYPE_3BYTE_BGR, (int)frameIIntervalMS, true);
+ }
+
+ public void captureFrame() {
+ if (!SwingUtilities.isEventDispatchThread()) {
+ throw new IllegalStateException("Capture is NOT inside event dispatch thread!");
+ }
+
+ long start = System.currentTimeMillis();
+
+ if (start-lastFrameTS < frameIIntervalMS || start < startCaptureTS) {
+ return;
+ }
+ lastFrameTS = start;
+
+ if (framesCaptured == -1)
+ return;
+ if (framesCaptured == 0) {
+ startedCapture = System.currentTimeMillis();
+ System.out.println("Capture started...");
+ }
+
+ if (System.currentTimeMillis() - startedCapture >= captureMillis) {
+ System.out.println("Capture finished... frames captured: "+framesCaptured);
+ framesCaptured = -1;
+// task.cancel();
+ try {
+ gif.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ try {
+ output.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ System.exit(0);
+ return;
+ }
+
+ framesCaptured++;
+ BufferedImage capImage = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
+ Graphics2D g = (Graphics2D) capImage.getGraphics();
+ g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+ g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ frame.paint(g);
+ g.dispose();
+
+ /**
+ * convert to gif in a separate thread to not slow down swing's event thread
+ */
+ saveThread.submit(() -> {
+ try {
+ gif.writeToSequence(capImage);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+
+ System.out.println("time to save gif "+(System.currentTimeMillis()-start));
+ }
+
+
+
+}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/DatasetSpectrum.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/DatasetSpectrum.java
index 8f9a15d..eacfee3 100644
--- a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/DatasetSpectrum.java
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/DatasetSpectrum.java
@@ -6,19 +6,25 @@
import org.jfree.data.xy.XYDataItem;
import org.jfree.data.xy.XYSeries;
+import jspectrumanalyzer.core.jfc.XYSeriesImmutable;
+
public class DatasetSpectrum implements Cloneable
{
+ /**
+ * caching decreases GC usage
+ */
+ private final boolean useCached = false;
+ protected ArrayList> cachedDataItems = new ArrayList<>();
+ protected int cachedDataItemsIndex = 0;
protected final float fftBinSizeHz;
+
protected final long freqStartHz;
protected final int freqStartMHz;
+
protected final int freqStopMHz;
-
protected float[] spectrum;
protected float spectrumInitPower;
- protected ArrayList> cachedDataItems = new ArrayList<>();
- protected int cachedDataItemsIndex = 0;
-
/**
* Inits
* @param fftBinSizeHz
@@ -40,21 +46,39 @@ public DatasetSpectrum(float fftBinSizeHz, int freqStartMHz, int freqStopMHz, fl
spectrum = new float[datapoints];
Arrays.fill(spectrum, spectrumInitPower);
- for (int j = 0; j < 5; j++) {
- ArrayList list = new ArrayList<>();
- for (int i = 0; i < datapoints; i++) {
- double freq = (freqStartHz + fftBinSizeHz * i) / 1000000;
- list.add(new XYDataItem(freq, 0));
+ if (useCached) {
+ for (int j = 0; j < 5; j++) {
+ ArrayList list = new ArrayList<>();
+ for (int i = 0; i < datapoints; i++) {
+ double freq = (freqStartHz + fftBinSizeHz * i) / 1000000;
+ list.add(new XYDataItem(freq, 0));
+ }
+ cachedDataItems.add(list);
}
- cachedDataItems.add(list);
}
}
- @Override protected Object clone() throws CloneNotSupportedException
+ /**
+ * Adds new data to spectrum's dataset
+ * @param fftBins
+ * @return true if the whole spectrum was refreshed once
+ */
+ public boolean addNewData(FFTBins fftBins)
{
- DatasetSpectrum copy = (DatasetSpectrum) super.clone();
- copy.spectrum = spectrum.clone();
- return copy;
+ boolean triggerRefresh = false;
+ triggerRefresh = fftBins.fullSweepDone;
+
+ for (int binsIndex = 0; binsIndex < fftBins.freqStart.length; binsIndex++)
+ {
+ double freqStart = fftBins.freqStart[binsIndex];
+ int spectrIndex = (int) ((freqStart - freqStartHz) / fftBinSizeHz);
+ if (spectrIndex < 0 || spectrIndex >= spectrum.length)
+ continue;
+ spectrum[spectrIndex] = fftBins.sigPowdBm[binsIndex];
+ }
+
+
+ return triggerRefresh;
}
public DatasetSpectrum cloneMe()
@@ -73,28 +97,31 @@ public DatasetSpectrum cloneMe()
}
/**
- * Adds new data to spectrum's dataset
- * @param fftBins
- * @return true if the whole spectrum was refreshed once
+ * Copies spectrum to destination dataset
+ * @param filtered
*/
- public boolean addNewData(FFTBins fftBins)
+ public void copyTo(DatasetSpectrum filtered)
{
- boolean triggerRefresh = false;
- triggerRefresh = fftBins.fullSweepDone;
+ System.arraycopy(spectrum, 0, filtered.spectrum, 0, spectrum.length);
+ }
- for (int binsIndex = 0; binsIndex < fftBins.freqStart.length; binsIndex++)
+ /**
+ * Creates {@link XYSeriesImmutable} from spectrum data
+ * @param name
+ * @return
+ */
+ public XYSeriesImmutable createSpectrumDataset(String name) {
+ float[] xValues = new float[spectrum.length];
+ float[] yValues = spectrum;
+ for (int i = 0; i < spectrum.length; i++)
{
- double freqStart = fftBins.freqStart[binsIndex];
- int spectrIndex = (int) ((freqStart - freqStartHz) / fftBinSizeHz);
- if (spectrIndex < 0 || spectrIndex >= spectrum.length)
- continue;
- spectrum[spectrIndex] = fftBins.sigPowdBm[binsIndex];
+ float freq = (freqStartHz + fftBinSizeHz * i) / 1000000f;
+ xValues[i] = freq;
}
-
-
- return triggerRefresh;
+ XYSeriesImmutable xySeriesF = new XYSeriesImmutable(name, xValues, yValues);
+ return xySeriesF;
}
-
+
/**
* Fills data to {@link XYSeries}, uses x units in MHz
* @param series
@@ -104,36 +131,12 @@ public void fillToXYSeries(XYSeries series)
fillToXYSeriesPriv(series, spectrum);
}
- protected void fillToXYSeriesPriv(XYSeries series, float[] spectrum){
- series.clear();
- /**
- * caching decreases GC usage
- */
- boolean useCached = false;
- if (!useCached){
- for (int i = 0; i < spectrum.length; i++)
- {
- double freq = (freqStartHz + fftBinSizeHz * i) / 1000000;
- series.add(freq, spectrum[i]);
- }
- }
- else{
- ArrayList items = cachedDataItems.get(cachedDataItemsIndex);
- for (int i = 0; i < spectrum.length; i++)
- {
- XYDataItem item = items.get(i);
- item.setY(spectrum[i]);
- series.add(item);
- }
- cachedDataItemsIndex = (cachedDataItemsIndex+1)%cachedDataItems.size();
- }
- }
-
+
public float getFFTBinSizeHz()
{
return fftBinSizeHz;
}
-
+
public int getFreqStartMHz()
{
return freqStartMHz;
@@ -160,13 +163,18 @@ public float getPower(int index)
return spectrum[index];
}
+ public float[] getSpectrumArray()
+ {
+ return spectrum;
+ }
+
public void resetSpectrum()
{
Arrays.fill(spectrum, spectrumInitPower);
}
- public float[] getSpectrumArray()
+ public void setSpectrumInitPower(float spectrumInitPower)
{
- return spectrum;
+ this.spectrumInitPower = spectrumInitPower;
}
public int spectrumLength()
@@ -174,17 +182,31 @@ public int spectrumLength()
return spectrum.length;
}
- public void setSpectrumInitPower(float spectrumInitPower)
+ @Override protected Object clone() throws CloneNotSupportedException
{
- this.spectrumInitPower = spectrumInitPower;
+ DatasetSpectrum copy = (DatasetSpectrum) super.clone();
+ copy.spectrum = spectrum.clone();
+ return copy;
}
- /**
- * Copies spectrum to destination dataset
- * @param filtered
- */
- public void copyTo(DatasetSpectrum filtered)
- {
- System.arraycopy(spectrum, 0, filtered.spectrum, 0, spectrum.length);
+ protected void fillToXYSeriesPriv(XYSeries series, float[] spectrum){
+ series.clear();
+ if (!useCached){
+ for (int i = 0; i < spectrum.length; i++)
+ {
+ double freq = (freqStartHz + fftBinSizeHz * i) / 1000000;
+ series.add(freq, spectrum[i]);
+ }
+ }
+ else{
+ ArrayList items = cachedDataItems.get(cachedDataItemsIndex);
+ for (int i = 0; i < spectrum.length; i++)
+ {
+ XYDataItem item = items.get(i);
+ item.setY(spectrum[i]);
+ series.add(item);
+ }
+ cachedDataItemsIndex = (cachedDataItemsIndex+1)%cachedDataItems.size();
+ }
}
}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/DatasetSpectrumPeak.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/DatasetSpectrumPeak.java
index 0768df2..786440c 100644
--- a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/DatasetSpectrumPeak.java
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/DatasetSpectrumPeak.java
@@ -1,11 +1,11 @@
package jspectrumanalyzer.core;
-import java.util.ArrayList;
import java.util.Arrays;
-import org.jfree.data.xy.XYDataItem;
import org.jfree.data.xy.XYSeries;
+import jspectrumanalyzer.core.jfc.XYSeriesImmutable;
+
public class DatasetSpectrumPeak extends DatasetSpectrum
{
protected long lastAdded = System.currentTimeMillis();
@@ -39,6 +39,10 @@ public DatasetSpectrumPeak(float fftBinSizeHz, int freqStartMHz, int freqStopMHz
}
+ public void setPeakFalloutMillis(long peakFalloutMillis) {
+ this.peakFalloutMillis = peakFalloutMillis;
+ }
+
public void copyTo(DatasetSpectrumPeak filtered)
{
super.copyTo(filtered);
@@ -53,6 +57,20 @@ public void copyTo(DatasetSpectrumPeak filtered)
public void fillPeaksToXYSeries(XYSeries series)
{
fillToXYSeriesPriv(series, spectrumPeakHold);
+// fillToXYSeriesPriv(series, spectrumPeak);
+ }
+
+
+ public XYSeriesImmutable createPeaksDataset(String name) {
+ float[] xValues = new float[spectrum.length];
+ float[] yValues = spectrumPeakHold;
+ for (int i = 0; i < spectrum.length; i++)
+ {
+ float freq = (freqStartHz + fftBinSizeHz * i) / 1000000f;
+ xValues[i] = freq;
+ }
+ XYSeriesImmutable xySeriesF = new XYSeriesImmutable(name, xValues, yValues);
+ return xySeriesF;
}
public double calculateSpectrumPeakPower(){
@@ -64,12 +82,24 @@ public double calculateSpectrumPeakPower(){
return powerSum;
}
+ private long debugLastPeakRerfreshTime = 0;
public void refreshPeakSpectrum()
{
+ if (false) {
+ long debugMinPeakRefreshTime = 100;
+ if (System.currentTimeMillis()-debugLastPeakRerfreshTime < debugMinPeakRefreshTime)
+ return;
+ debugLastPeakRerfreshTime = System.currentTimeMillis();
+ }
+
long timeDiffFromPrevValueMillis = System.currentTimeMillis() - lastAdded;
+ if (timeDiffFromPrevValueMillis < 1)
+ timeDiffFromPrevValueMillis = 1;
+
lastAdded = System.currentTimeMillis();
-
- peakFallThreshold = 10;
+
+// peakFallThreshold = 10;
+// peakFalloutMillis = 30000;
for (int spectrIndex = 0; spectrIndex < spectrum.length; spectrIndex++)
{
float spectrumVal = spectrum[spectrIndex];
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencyAllocationTable.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencyAllocationTable.java
new file mode 100644
index 0000000..59233b4
--- /dev/null
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencyAllocationTable.java
@@ -0,0 +1,194 @@
+package jspectrumanalyzer.core;
+
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.Rectangle2D.Float;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import jspectrumanalyzer.ui.GraphicsToolkit;
+
+public class FrequencyAllocationTable {
+ /**
+ * bands will be sorted in the set by frequency
+ */
+ private final TreeSet frequencyBands = new TreeSet<>();
+ private final String area;
+
+ public FrequencyAllocationTable(String area, ArrayList bands) {
+ this.area = area;
+ this.frequencyBands.addAll(bands);
+ }
+
+ public FrequencyBand lookupBand(long hz) {
+ FrequencyBand band = frequencyBands.floor(new FrequencyBand(hz, hz, "", ""));
+ return band;
+ }
+
+ @Override
+ public String toString() {
+ return area;
+ }
+
+ public ArrayList getFrequencyBands(long startHz, long endHz){
+ FrequencyBand startBand = lookupBand(startHz);
+ ArrayList bands = new ArrayList<>();
+ SortedSet entries = frequencyBands.tailSet(startBand);
+ for (FrequencyBand frequencyBand : entries) {
+ if (frequencyBand.getHzStartIncl() > endHz) {
+ break;
+ }
+ bands.add(frequencyBand);
+ }
+ return bands;
+ }
+ private static float map(float x, float in_min, float in_max, float out_min, float out_max)
+ {
+ return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+ }
+
+ public BufferedImage drawAllocationTable(int width, int height, float alpha, long freqStartHz, long freqEndHz, Color textColor, Color bgColor) {
+ /*
+ * draw the image scaled up and then resize it after rendering producing high quality image
+ */
+ int scale = 1;
+ int drawWidth = width*scale;
+ int drawHeight = height*scale;
+ BufferedImage i = GraphicsToolkit.createAcceleratedImageTransparent(drawWidth, drawHeight);
+ Graphics2D g = i.createGraphics();
+
+ AlphaComposite alcom = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
+ g.setComposite(alcom);
+
+ g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ g.setStroke(new BasicStroke(1f));
+ //g.rotate(Math.toRadians(90));
+
+ AffineTransform affineTransform = new AffineTransform();
+ affineTransform.rotate(Math.toRadians(0), 0, 0);
+ Font font = new Font(Font.DIALOG, Font.PLAIN, 10*scale);
+ Font rotatedFont = font.deriveFont(affineTransform);
+ Rectangle2D fontBounds = g.getFontMetrics(rotatedFont).getStringBounds("80M", g);
+ g.setFont(rotatedFont);
+ int fontHeight = (int) fontBounds.getHeight();
+
+ ArrayList bands = getFrequencyBands(freqStartHz, freqEndHz);
+
+ float freqRange = freqEndHz-freqStartHz;
+ Float rect = new Rectangle2D.Float();
+ final float textOffset = fontHeight;
+ final float textX = fontHeight/2;
+
+ class BandRectangle{
+ ArrayList lines; /*null for no text*/;
+ float x,y,w;
+ FrequencyBand band;
+ String longestString;
+ boolean textVisible = true;
+ public BandRectangle(FrequencyBand band, ArrayList lines, float x, float y, float w, String longestString) {
+ this.band = band;
+ this.lines = lines;
+ this.x = x;
+ this.y = y;
+ this.w = w;
+ this.longestString = longestString;
+ }
+
+ }
+
+ ArrayList shapes = new ArrayList<>(bands.size());
+ for (int j = 0; j < bands.size(); j++) {
+ FrequencyBand band = bands.get(j);
+ float xStart = (band.getHzStartIncl()-freqStartHz)*drawWidth/(freqRange);
+ float xEnd = (band.getHzEndExcl()-freqStartHz)*drawWidth/(freqRange);
+ if (xStart < 0)
+ xStart = 0;//if the band starts offscreen to the left, start it on 0
+ float x = xStart;
+ float y = 0;
+ float w = xEnd-xStart;
+
+ String[] lines = band.getName().split("/");
+ ArrayList listLines = new ArrayList<>(lines.length+1);
+ listLines.add(String.format("%d - %dM", band.getHzStartIncl()/1000000, band.getHzEndExcl()/1000000));
+ for (int line = 0; line < lines.length; line++) {
+ String linestr = lines[line];
+ listLines.add(linestr);
+ }
+ /*
+ * find the longest string
+ */
+ Arrays.sort(lines, (o1, o2) -> Integer.compare(o2.length(), o1.length()));
+
+ shapes.add(new BandRectangle(band, listLines, x, y, w, lines[0]));
+ }
+
+ float maxVisibleLines = 1;
+ for (int j = 0; j < shapes.size(); j++) {
+ BandRectangle shape = shapes.get(j);
+ /*
+ * determine if the first line will fit inside the rectangle
+ */
+ Rectangle2D bounds = g.getFontMetrics(rotatedFont).getStringBounds(shape.lines.get(0), g);
+ if (shape.w > bounds.getWidth()) {
+ if (shape.lines.size() > maxVisibleLines)
+ maxVisibleLines = shape.lines.size();
+ }
+ else {
+ shape.textVisible = false;
+ }
+ }
+
+ float rectHeight = (maxVisibleLines) * fontHeight + fontHeight/2;
+ rect.height = rectHeight;
+ for (int j = 0; j < shapes.size(); j++) {
+ BandRectangle shape = shapes.get(j);
+ rect.x = shape.x;
+ rect.y = shape.y;
+ rect.width = shape.w;
+ g.setColor(bgColor);
+ g.fill(rect);
+ g.setColor(Color.black);
+ g.draw(rect);
+ if (shape.textVisible) {
+ g.setColor(textColor);
+// g.setColor(Color.white);
+ Graphics2D gg = (Graphics2D) g.create((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
+ for (int line = 0; line < shape.lines.size(); line++) {
+ String linestr = shape.lines.get(line);
+ gg.drawString(linestr, textX, textOffset + (line)*fontHeight);
+ }
+ gg.dispose();
+ }
+ }
+
+ g.dispose();
+ if (scale > 1) {
+ BufferedImage iOut = GraphicsToolkit.createAcceleratedImageTransparent(width, height);
+ g = iOut.createGraphics();
+ g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ g.drawImage(i, 0, 0, width, height, null);
+ g.dispose();
+ return iOut;
+ }
+ return i;
+ }
+
+}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencyAllocations.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencyAllocations.java
new file mode 100644
index 0000000..7ea3cbd
--- /dev/null
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencyAllocations.java
@@ -0,0 +1,71 @@
+package jspectrumanalyzer.core;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class FrequencyAllocations {
+ private HashMap table = new HashMap<>();
+
+ public FrequencyAllocations() {
+ loadEurope();
+ }
+
+ private Pattern patternEU = Pattern.compile("\"[^\"]+\";\"([0-9.]+)\\s+-\\s+([0-9.]+)\\s+([kM])Hz\";\"([^\"]+)\";\"([^\"]+)\"");
+
+ public HashMap getTable() {
+ return new HashMap<>(table);
+ }
+
+ private void loadEurope() {
+ BufferedReader reader = null;
+
+ ArrayList bands = new ArrayList<>();
+
+ try {
+ /**
+ * Source:
+ * https://www.efis.dk/views2/search-general.jsp
+ */
+ reader = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/resources/freq-europe.csv")));
+ String line = null;
+ int lineNo = 0;
+ while((line = reader.readLine()) != null) {
+ lineNo++;
+ if (lineNo == 1)
+ continue;
+
+ //"- Europe (ECA) -";"526.500 - 1606.500 kHz";"Broadcasting";"Inductive applications/Broadcasting"
+ //"- Europe (ECA) -";"5925.000 - 6700.000 MHz";"Fixed/Fixed-Satellite (Earth-to-space)/Earth Exploration-Satellite (passive)";"Passive sensors (satellite)/Fixed/FSS Earth stations/Radiodetermination applications/UWB applications/-/ESV/Radio astronomy"
+ Matcher m = patternEU.matcher(line);
+ if (m.find()) {
+ double multiplier = m.group(3).equals("k") ? 1000 : 1000000;
+ long startFreq = Math.round(Double.parseDouble(m.group(1)) * multiplier);
+ long stopFreq = Math.round(Double.parseDouble(m.group(2)) * multiplier);
+ String name = m.group(4);
+ String applications = m.group(5);
+ FrequencyBand band = new FrequencyBand(startFreq, stopFreq, name, applications);
+ bands.add(band);
+ }
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException e) {
+
+ }
+ }
+ }
+ FrequencyAllocationTable allocationTable = new FrequencyAllocationTable("Europe", bands);
+ table.put("Europe", allocationTable);
+ }
+}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencyBand.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencyBand.java
new file mode 100644
index 0000000..501f42b
--- /dev/null
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencyBand.java
@@ -0,0 +1,49 @@
+package jspectrumanalyzer.core;
+
+/**
+ * Describes one frequency allocation band by start frequency and end frequency
+ */
+public class FrequencyBand implements Comparable{
+ private final long hzStartIncl;
+ private final long hzEndExcl;
+ private final String name;
+ private final String applications;
+
+ public FrequencyBand(long hzStartIncl, long hzEndExcl, String name, String applications) {
+ this.hzStartIncl = hzStartIncl;
+ this.hzEndExcl = hzEndExcl;
+ this.name = name;
+ this.applications = applications;
+ }
+ public long getHzStartIncl() {
+ return hzStartIncl;
+ }
+
+ public double getMHzStartIncl() {
+ return hzStartIncl/1000000d;
+ }
+
+ public long getHzEndExcl() {
+ return hzEndExcl;
+ }
+ public double getMHzEndExcl() {
+ return hzEndExcl/1000000d;
+ }
+ public String getName() {
+ return name;
+ }
+ public String getApplications() {
+ return applications;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ @Override
+ public int compareTo(FrequencyBand o) {
+ return Long.compare(hzStartIncl, o.hzStartIncl);
+ }
+
+}
\ No newline at end of file
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencyRange.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencyRange.java
new file mode 100644
index 0000000..509f7ca
--- /dev/null
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencyRange.java
@@ -0,0 +1,25 @@
+package jspectrumanalyzer.core;
+
+public class FrequencyRange{
+ private final int startMHz, endMHz;
+
+ public FrequencyRange(int startMHz, int endMHz) {
+ this.startMHz = startMHz;
+ this.endMHz = endMHz;
+ }
+ public int getEndMHz() {
+ return endMHz;
+ }
+ public int getStartMHz() {
+ return startMHz;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof FrequencyRange) {
+ FrequencyRange fr = (FrequencyRange)obj;
+ if (fr.endMHz == endMHz && fr.startMHz == startMHz)
+ return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencyRangeSelector.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencyRangeSelector.java
deleted file mode 100644
index 8c410a3..0000000
--- a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencyRangeSelector.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package jspectrumanalyzer.core;
-
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.beans.PropertyVetoException;
-import java.beans.VetoableChangeListener;
-
-/**
- * Limits frequency selection of two selectors (start/end)
- */
-public class FrequencyRangeSelector
-{
- public FrequencyRangeSelector(FrequencySelectorPanel selFreqStart, FrequencySelectorPanel selFreqEnd, PropertyChangeListener propertyChangeListener)
- {
- VetoableChangeListener freqStartVetoable = new VetoableChangeListener()
- {
- @Override public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException
- {
- Integer newVal = (Integer) evt.getNewValue();
- if (newVal >= (Integer) selFreqEnd.getValue())
- {
- //try to increase freq end by the same value
- if (!selFreqEnd.setValue(selFreqEnd.getValue() + (newVal - (Integer) evt.getOldValue())))
- throw new PropertyVetoException(">", evt);
- }
- }
- };
- VetoableChangeListener freqEndVetoable = new VetoableChangeListener()
- {
- @Override public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException
- {
- Integer newVal = (Integer) evt.getNewValue();
- if (newVal <= (Integer) selFreqStart.getValue())
- {
- if (!selFreqStart.setValue(selFreqStart.getValue() - ((Integer) evt.getOldValue() - newVal)))
- throw new PropertyVetoException(">", evt);
- }
- }
- };
-
- selFreqStart.addPropertyChangeListener("value", propertyChangeListener);
- selFreqEnd.addPropertyChangeListener("value", propertyChangeListener);
-
- selFreqEnd.addVetoableChangeListener(freqEndVetoable);
- selFreqStart.addVetoableChangeListener(freqStartVetoable);
- }
-}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/HackRFSettings.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/HackRFSettings.java
index 4e8c81a..488a19b 100644
--- a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/HackRFSettings.java
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/HackRFSettings.java
@@ -1,78 +1,70 @@
package jspectrumanalyzer.core;
-public interface HackRFSettings
-{
+import java.math.BigDecimal;
+
+import shared.mvc.ModelValue;
+import shared.mvc.ModelValue.ModelValueBoolean;
+import shared.mvc.ModelValue.ModelValueInt;
+
+public interface HackRFSettings {
public static abstract class HackRFEventAdapter implements HackRFEventListener {
- @Override public void captureStateChanged(boolean isCapturing)
- {
-
+ @Override
+ public void captureStateChanged(boolean isCapturing) {
+
}
- @Override public void hardwareStatusChanged(boolean hardwareSendingData)
- {
-
+
+ @Override
+ public void hardwareStatusChanged(boolean hardwareSendingData) {
+
}
}
- public static interface HackRFEventListener{
+ public static interface HackRFEventListener {
public void captureStateChanged(boolean isCapturing);
+
public void hardwareStatusChanged(boolean hardwareSendingData);
}
- public int getFFTBinHz();
+ public ModelValueBoolean getAntennaPowerEnable();
- /**
- * Get sweep frequency end MHz
- * @return
- */
- public int getFrequencyEnd();
+ public ModelValueInt getFFTBinHz();
- /**
- * Get sweep frequency start MHz
- * @return
- */
- public int getFrequencyStart();
+ public ModelValue getFrequency();
- public int getGain();
+ public ModelValueInt getGain();
- public int getLNAGain();
+ public ModelValueInt getGainLNA();
+
+ public ModelValueInt getPersistentDisplayDecayRate();
+
+ public ModelValueBoolean isDebugDisplay();
- public int getSamples();
+ public ModelValueInt getSamples();
+
+ public ModelValueInt getSpectrumPaletteSize();
+
+ public ModelValueBoolean isPersistentDisplayVisible();
+ public ModelValueBoolean isWaterfallVisible();
- public int getSpectrumPaletteSize();
+ public ModelValueInt getSpectrumPaletteStart();
+
+ public ModelValueInt getPeakFallRate();
+
+ public ModelValue getFrequencyAllocationTable();
- public int getSpectrumPaletteStart();
+ public ModelValue getSpectrumLineThickness();
- public boolean isSpurRemoval();
+ public ModelValueInt getGainVGA();
- public int getVGAGain();
+ public ModelValueBoolean isCapturingPaused();
- public boolean isCapturing();
+ public ModelValueBoolean isChartsPeaksVisible();
- public boolean isChartsPeaksVisible();
+ public ModelValueBoolean isFilterSpectrum();
- public boolean isFilterSpectrum();
+ public ModelValueBoolean isSpurRemoval();
public void registerListener(HackRFEventListener listener);
public void removeListener(HackRFEventListener listener);
-
- public void setCapturing(boolean pause);
-
- public void setChartPeaksVisibility(boolean visible);
-
- public void setFFTBin(int fftBinHz);
-
- public void setFilterSpectrum(boolean filter);
-
- public void setFrequency(int freqStartMHz, int freqEndMHz);
- public void setGain(int gaindB);
-
- public void setSamples(int samples);
- public void setSpectrumPaletteSize(int dB);
-
- public void setSpectrumPaletteStart(int dB);
- public void setSpurRemoval(boolean enable);
-
- public void setAntennaPowerEnable(boolean enable);
- public boolean getAntennaPowerEnable();
}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/HackRFSweepSettingsUI.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/HackRFSweepSettingsUI.java
deleted file mode 100644
index 537c2fc..0000000
--- a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/HackRFSweepSettingsUI.java
+++ /dev/null
@@ -1,286 +0,0 @@
-package jspectrumanalyzer.core;
-
-import java.awt.Color;
-import java.awt.Desktop;
-import java.awt.Font;
-import java.awt.Label;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.net.URI;
-
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JSlider;
-import javax.swing.JSpinner;
-import javax.swing.JSpinner.ListEditor;
-import javax.swing.JTextField;
-import javax.swing.SpinnerListModel;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
-import jspectrumanalyzer.HackRFSweepSpectrumAnalyzer;
-import jspectrumanalyzer.Version;
-import net.miginfocom.swing.MigLayout;
-
-public class HackRFSweepSettingsUI extends JPanel
-{
- /**
- *
- */
- private static final long serialVersionUID = 7721079457485020637L;
- private JTextField txtHackrfConnected;
-
- /**
- * Create the panel.
- */
- public HackRFSweepSettingsUI(HackRFSettings hackRFSettings)
- {
- setForeground(Color.WHITE);
- setBackground(Color.BLACK);
- int minFreq = 1;
- int maxFreq = 7250;
- int freqStep = 1;
-
- setLayout(new MigLayout("", "[123.00px,grow,leading]", "[][20px][][][20px][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]"));
-
- JLabel lblNewLabel = new JLabel("Frequency start [MHz]");
- lblNewLabel.setForeground(Color.WHITE);
- add(lblNewLabel, "cell 0 0,growx,aligny center");
-
- FrequencySelectorPanel frequencySelectorStart = new FrequencySelectorPanel(minFreq, maxFreq, freqStep, minFreq);
- add(frequencySelectorStart, "cell 0 1,grow");
-
- frequencySelectorStart.setValue(hackRFSettings.getFrequencyStart());
-
- JLabel lblFrequencyEndmhz = new JLabel("Frequency end [MHz]");
- lblFrequencyEndmhz.setForeground(Color.WHITE);
- add(lblFrequencyEndmhz, "cell 0 3,alignx left,aligny center");
-
- FrequencySelectorPanel frequencySelectorEnd = new FrequencySelectorPanel(minFreq, maxFreq, freqStep, maxFreq);
- add(frequencySelectorEnd, "cell 0 4,grow");
- frequencySelectorEnd.setValue(hackRFSettings.getFrequencyEnd());
-
- JLabel lblFftBinhz = new JLabel("FFT Bin [Hz]");
- lblFftBinhz.setForeground(Color.WHITE);
- add(lblFftBinhz, "cell 0 6");
-
- JSpinner spinnerFFTBinHz = new JSpinner();
- spinnerFFTBinHz.setFont(new Font("Monospaced", Font.BOLD, 16));
- spinnerFFTBinHz.setModel(new SpinnerListModel(
- new String[] { "1000", "2000", "5000", "10 000", "20 000", "50 000", "100 000", "200 000", "500 000", "1 000 000", "2 000 000", "5 000 000" }));
- add(spinnerFFTBinHz, "cell 0 7,growx");
- ((ListEditor) spinnerFFTBinHz.getEditor()).getTextField().setHorizontalAlignment(JTextField.RIGHT);
- spinnerFFTBinHz.addChangeListener(new ChangeListener()
- {
- @Override public void stateChanged(ChangeEvent e)
- {
- hackRFSettings.setFFTBin(Integer.parseInt(spinnerFFTBinHz.getValue().toString().replaceAll("\\s", "")));
- }
- });
- spinnerFFTBinHz.setValue("100 000");
-
- JLabel lblGain = new JLabel("Gain [dB]");
- lblGain.setForeground(Color.WHITE);
- add(lblGain, "cell 0 9");
-
- JSlider sliderGain = new JSlider(JSlider.HORIZONTAL, 0, 100, 2);
- sliderGain.setFont(new Font("Monospaced", Font.BOLD, 16));
- sliderGain.setBackground(Color.BLACK);
- sliderGain.setForeground(Color.WHITE);
- add(sliderGain, "flowy,cell 0 10,growx");
-
- JLabel lbl_gainValue = new JLabel(hackRFSettings.getGain() + "dB");
- lbl_gainValue.setForeground(Color.WHITE);
- add(lbl_gainValue, "cell 0 10,alignx right");
-
- sliderGain.addChangeListener(new ChangeListener()
- {
- @Override public void stateChanged(ChangeEvent e)
- {
- int val = sliderGain.getValue();
- hackRFSettings.setGain(val);
- lbl_gainValue.setText(
- String.format(" %ddB [LNA: %ddB VGA: %ddB]", hackRFSettings.getGain(), hackRFSettings.getLNAGain(), hackRFSettings.getVGAGain()));
- }
- });
- sliderGain.setValue(hackRFSettings.getGain());
-
- JLabel lblNumberOfSamples = new JLabel("Number of samples");
- lblNumberOfSamples.setForeground(Color.WHITE);
- add(lblNumberOfSamples, "cell 0 12");
-
- JSpinner spinner_numberOfSamples = new JSpinner();
- spinner_numberOfSamples.setModel(new SpinnerListModel(new String[] { "8192", "16384", "32768", "65536", "131072", "262144" }));
- spinner_numberOfSamples.setFont(new Font("Monospaced", Font.BOLD, 16));
- ((ListEditor) spinner_numberOfSamples.getEditor()).getTextField().setHorizontalAlignment(JTextField.RIGHT);
- ((ListEditor) spinner_numberOfSamples.getEditor()).getTextField().setEditable(false);
- ;
- add(spinner_numberOfSamples, "cell 0 13,growx");
-
- JCheckBox chckbxAntennaPower = new JCheckBox("Antenna power");
- chckbxAntennaPower.setBackground(Color.BLACK);
- chckbxAntennaPower.setForeground(Color.WHITE);
- add(chckbxAntennaPower, "cell 0 15");
- chckbxAntennaPower.setSelected(hackRFSettings.getAntennaPowerEnable());
- chckbxAntennaPower.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- hackRFSettings.setAntennaPowerEnable(chckbxAntennaPower.isSelected());
- }
- });
-
-
- JLabel lblWaterfallPaletteStart = new JLabel("Waterfall palette start [dB]");
- lblWaterfallPaletteStart.setForeground(Color.WHITE);
- add(lblWaterfallPaletteStart, "cell 0 18");
-
- JSlider slider_waterfallPaletteStart = new JSlider();
- slider_waterfallPaletteStart.setForeground(Color.WHITE);
- slider_waterfallPaletteStart.setBackground(Color.BLACK);
- slider_waterfallPaletteStart.setMinimum(-100);
- slider_waterfallPaletteStart.setMaximum(0);
- slider_waterfallPaletteStart.setValue(-30);
- add(slider_waterfallPaletteStart, "cell 0 19,growx");
- slider_waterfallPaletteStart.setValue(hackRFSettings.getSpectrumPaletteStart());
- slider_waterfallPaletteStart.addChangeListener(new ChangeListener()
- {
- @Override public void stateChanged(ChangeEvent e)
- {
- hackRFSettings.setSpectrumPaletteStart(slider_waterfallPaletteStart.getValue());
- }
- });
-
- spinner_numberOfSamples.setValue(hackRFSettings.getSamples() + "");
- spinner_numberOfSamples.addChangeListener(new ChangeListener()
- {
- @Override public void stateChanged(ChangeEvent e)
- {
- hackRFSettings.setSamples(Integer.parseInt(spinner_numberOfSamples.getValue().toString()));
- }
- });
-
- JLabel lblWaterfallPaletteLength = new JLabel("Waterfall palette length [dB]");
- lblWaterfallPaletteLength.setForeground(Color.WHITE);
- add(lblWaterfallPaletteLength, "cell 0 21");
-
- JSlider slider_waterfallPaletteSize = new JSlider(HackRFSweepSpectrumAnalyzer.SPECTRUM_PALETTE_SIZE_MIN, 100);
- slider_waterfallPaletteSize.setBackground(Color.BLACK);
- slider_waterfallPaletteSize.setForeground(Color.WHITE);
- add(slider_waterfallPaletteSize, "cell 0 22,growx");
-
- slider_waterfallPaletteSize.setValue(hackRFSettings.getSpectrumPaletteSize());
-
- slider_waterfallPaletteSize.addChangeListener(new ChangeListener()
- {
- @Override public void stateChanged(ChangeEvent e)
- {
- hackRFSettings.setSpectrumPaletteSize(slider_waterfallPaletteSize.getValue());
- }
- });
-
- FrequencyRangeSelector frequencyRangeSelector = new FrequencyRangeSelector(frequencySelectorStart, frequencySelectorEnd, new PropertyChangeListener()
- {
- @Override public void propertyChange(PropertyChangeEvent evt)
- {
- hackRFSettings.setFrequency(frequencySelectorStart.getValue(), frequencySelectorEnd.getValue());
- }
- });
-
- JCheckBox chckbxShowPeaks = new JCheckBox("Show peaks");
- chckbxShowPeaks.setForeground(Color.WHITE);
- chckbxShowPeaks.setBackground(Color.BLACK);
- add(chckbxShowPeaks, "cell 0 24,growx");
-
- JCheckBox chckbxRemoveSpurs = new JCheckBox("Spur filter (may distort real signals)");
- chckbxRemoveSpurs.setForeground(Color.WHITE);
- chckbxRemoveSpurs.setBackground(Color.BLACK);
- add(chckbxRemoveSpurs, "cell 0 26");
-
- txtHackrfConnected = new JTextField();
- txtHackrfConnected.setText("HackRF connected");
- txtHackrfConnected.setForeground(Color.WHITE);
- txtHackrfConnected.setBackground(Color.BLACK);
- add(txtHackrfConnected, "cell 0 29,growx");
- txtHackrfConnected.setColumns(10);
- txtHackrfConnected.setBorder(null);
-
- JButton btnPause = new JButton("Pause");
- add(btnPause, "cell 0 31,growx");
- btnPause.setBackground(Color.black);
-
- JButton btnAbout = new JButton("Visit homepage");
- btnAbout.addActionListener(new ActionListener()
- {
- @Override public void actionPerformed(ActionEvent e)
- {
- if (Desktop.isDesktopSupported()) {
- Desktop desktop = Desktop.getDesktop();
- try {
- URI uri = new URI(Version.url);
- desktop.browse(uri);
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- }
- });
-
- Label labelVersion = new Label("Version: v"+Version.version);
- add(labelVersion, "flowx,cell 0 42");
- btnAbout.setBackground(Color.BLACK);
- add(btnAbout, "cell 0 42,alignx right");
- btnPause.addActionListener(new ActionListener()
- {
- @Override public void actionPerformed(ActionEvent e)
- {
- hackRFSettings.setCapturing(!hackRFSettings.isCapturing());
- }
- });
- hackRFSettings.registerListener(new HackRFSettings.HackRFEventAdapter()
- {
- @Override public void captureStateChanged(boolean isCapturing)
- {
- btnPause.setText(isCapturing ? "Pause" : "Resume");
- }
- @Override public void hardwareStatusChanged(boolean hardwareSendingData)
- {
- txtHackrfConnected.setText("HackRF "+(hardwareSendingData ? "connected":"disconnected"));
- }
- });;
-
- JCheckBox chckbxFilterSpectrum = new JCheckBox("Filter spectrum");
- chckbxFilterSpectrum.setBackground(Color.BLACK);
- chckbxFilterSpectrum.setForeground(Color.WHITE);
- // add(chckbxFilterSpectrum, "cell 0 23");
-
- chckbxShowPeaks.addActionListener(new ActionListener()
- {
- @Override public void actionPerformed(ActionEvent e)
- {
- hackRFSettings.setChartPeaksVisibility(chckbxShowPeaks.isSelected());
- }
- });
-
- chckbxFilterSpectrum.addActionListener(new ActionListener()
- {
- @Override public void actionPerformed(ActionEvent e)
- {
- hackRFSettings.setFilterSpectrum(chckbxFilterSpectrum.isSelected());
- }
- });
-
- chckbxRemoveSpurs.setSelected(hackRFSettings.isSpurRemoval());
- chckbxRemoveSpurs.addActionListener(new ActionListener()
- {
- @Override public void actionPerformed(ActionEvent e)
- {
- hackRFSettings.setSpurRemoval(chckbxRemoveSpurs.isSelected());
- }
- });
- }
-
-}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/PersistentDisplay.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/PersistentDisplay.java
new file mode 100644
index 0000000..6fc6ebe
--- /dev/null
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/PersistentDisplay.java
@@ -0,0 +1,248 @@
+package jspectrumanalyzer.core;
+
+import java.awt.Color;
+import java.awt.image.BufferedImage;
+
+import jspectrumanalyzer.ui.GraphicsToolkit;
+import jspectrumanalyzer.ui.HotIronBluePalette;
+import shared.mvc.ModelValue;
+
+public class PersistentDisplay {
+ /**
+ * Image represented by single float array
+ */
+ private static class FloatImage {
+ private final float[] data;
+ private final int width, height;
+
+ public FloatImage(int width, int height) {
+ data = new float[width * height];
+ this.width = width;
+ this.height = height;
+ }
+
+ public float add(int x, int y, float power) {
+ return data[y * width + x] += power;
+ }
+
+ public float get(int x, int y) {
+ return data[y * width + x];
+ }
+
+ public int getIndex(int x, int y) {
+ return y * width + x;
+ }
+
+ public void multiplyAllValues(float value) {
+ for (int i = 0; i < data.length; i++) {
+ data[i] *= value;
+ }
+ }
+
+ public void set(int x, int y, float value) {
+ data[y * width + x] = value;
+ }
+
+ public void subtractAllValues(float value) {
+ for (int i = 0; i < data.length; i++) {
+ data[i] -= value;
+ }
+ }
+ }
+
+ public static float map(float in, float in_min, float in_max, float out_min, float out_max) {
+ return (in - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+ }
+
+ public static int map(int x, int in_min, int in_max, int out_min, int out_max) {
+ return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+ }
+
+ private boolean calibrated = false;
+ private boolean calibrating = false;
+ private long calibrationStarted = 0;
+ private final long calibrationTime = 1000;
+ private ModelValue displayImage = new ModelValue("", null);
+ private FloatImage imagePowerAccumulated;
+ private int incomingDataCounter = 0;
+ private HotIronBluePalette palette = new HotIronBluePalette();
+ private int persistenceTimeSecs = 5;
+ private float updatesPerSecond = 1;
+
+ public PersistentDisplay() {
+ setImageSize(320, 240);
+ }
+
+ public void drawSpectrum2(DatasetSpectrum datasetSpectrum, float yMin, float yMax, boolean renderImage) {
+ drawSpectrumFloat(datasetSpectrum, yMin, yMax, renderImage);
+ }
+
+ public void drawSpectrumFloat(DatasetSpectrum datasetSpectrum, float yMin, float yMax, boolean renderImage) {
+ if (!calibrated) {
+ if (!calibrating) {
+ calibrating = true;
+ calibrationStarted = System.currentTimeMillis();
+ incomingDataCounter = 0;
+ } else {
+ incomingDataCounter++;
+ long t = System.currentTimeMillis() - calibrationStarted;
+ if (t >= calibrationTime) {
+ updatesPerSecond = (float) incomingDataCounter / (t / 1000f);
+ int bins = (int) ((datasetSpectrum.getFreqStopMHz() - datasetSpectrum.getFreqStartMHz()) * 1000000l
+ / datasetSpectrum.getFFTBinSizeHz());
+ BufferedImage image = displayImage.getValue();
+ if (bins < image.getWidth()) {
+ setImageSize(bins, image.getHeight());
+ }
+ calibrated = true;
+ calibrating = false;
+
+ if (updatesPerSecond < 1)
+ updatesPerSecond = 1;
+ }
+ }
+ return;
+ }
+
+ BufferedImage image = this.displayImage.getValue();
+ FloatImage imagePowerAccumulated = this.imagePowerAccumulated;
+
+ if (image == null)
+ return;
+
+ float rawImagePowerArr[] = imagePowerAccumulated.data;
+
+ /**
+ * EMA
+ */
+ float order = persistenceTimeSecs * updatesPerSecond;
+ float k = 2f / (order + 1f);
+ // double result = currentValue * k + previousEMA * (1 - k);
+ float kM1 = 1 - k; /* apply decay only */
+ imagePowerAccumulated.multiplyAllValues(kM1);
+
+ float[] spectrum = datasetSpectrum.getSpectrumArray();
+ int width = image.getWidth();
+ int height = image.getHeight();
+ float hDivYRange = (-height) / (yMax - yMin);
+
+ /**
+ * pipeline: float image accumulates power for each pixel, then the
+ * power value gets converted to color based on the hot iron palette
+ */
+ float maxAccumulatedValue = updatesPerSecond * persistenceTimeSecs;
+ for (int i = 0; i < spectrum.length; i++) {
+ float power = spectrum[i];
+ float powerLin = 1; /*
+ * each occurence of power value at given
+ * frequency is simply +1
+ */
+
+ int x = i * width / spectrum.length;
+ int y = //(power - yMin) * (0 - height) / (yMax - yMin) + height;
+ (int) ((power - yMin) * hDivYRange
+ + height); /* optimized map() */
+
+ if (x >= 0 && y >= 0 && x < width && y < height) {
+ int index = imagePowerAccumulated.getIndex(x, y);
+ if (imagePowerAccumulated.data[index] < maxAccumulatedValue)
+ imagePowerAccumulated.data[index] += powerLin;
+ }
+ }
+
+ /**
+ * render image only when requested
+ */
+ if (renderImage) {
+ /**
+ * Find the max value to properly scale
+ */
+ float maxValue = Float.MIN_NORMAL;
+ for (int i = 0; i < rawImagePowerArr.length; i++) {
+ float value = rawImagePowerArr[i];
+ if (value > maxValue)
+ maxValue = value;
+ }
+
+ /**
+ * Fill the image with black color
+ */
+ // Graphics2D g = image.createGraphics();
+ // g.setColor(Color.red);
+ // g.fillRect(0, 0, width, height);
+ // g.dispose();
+ // renderImage = false;
+ //
+
+ float setToZeroThreshold = 0.01f;
+ float minOutToLog = 1.0f;
+ float maxOutToLog = 100;
+ float logMin = (float) Math.log10(minOutToLog);
+ float logMax = (float) Math.log10(maxOutToLog);
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ float val = imagePowerAccumulated.get(x, y);
+ if (val < setToZeroThreshold) {
+ imagePowerAccumulated.set(x, y, 0);
+ val = 0;
+ }
+
+ if (val == 0) {
+ image.setRGB(x, y, Color.black.getRGB());
+ } else {
+ float outPower = val;
+
+ /**
+ * Log compressed values
+ */
+ outPower = (float) Math.log10(map(outPower, 0, maxValue, minOutToLog, maxOutToLog));
+ float normalized = map(outPower, logMin, logMax, 0.15f, 0.95f); //(imagePowerAccumulated.get(x, y)) / (maxValue);
+
+ /**
+ * linear values
+ */
+ // float normalized = map(outPower, 0, maxValue, 0.4f, 0.9f); //(imagePowerAccumulated.get(x, y)) / (maxValue);
+
+ Color color = palette.getColorNormalized(normalized);
+
+ image.setRGB(x, y, color.getRGB());
+ // g.setColor(color);
+ // g.drawLine(x, y, x, y);
+ }
+ }
+ }
+
+ }
+ }
+
+ public ModelValue getDisplayImage() {
+ return displayImage;
+ }
+
+ public int getPersistenceTime() {
+ return persistenceTimeSecs;
+ }
+
+ public void reset() {
+ BufferedImage image = displayImage.getValue();
+ if (image != null) {
+ setImageSize(image.getWidth(), image.getHeight());
+ }
+ }
+
+ public void setImageSize(int width, int height) {
+ if (width < 1 || height < 1)
+ return;
+
+ calibrated = false;
+ calibrating = false;
+
+ System.out.println("Persistent image set to " + width + "x" + height);
+ displayImage.setValue(GraphicsToolkit.createAcceleratedImageOpaque(width, height));
+ imagePowerAccumulated = new FloatImage(width, height);
+ }
+
+ public void setPersistenceTime(int persistenceTimeSecs) {
+ this.persistenceTimeSecs = persistenceTimeSecs;
+ }
+}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/WaterfallPlot.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/WaterfallPlot.java
deleted file mode 100644
index c630e5a..0000000
--- a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/WaterfallPlot.java
+++ /dev/null
@@ -1,312 +0,0 @@
-package jspectrumanalyzer.core;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.RenderingHints;
-import java.awt.Toolkit;
-import java.awt.event.ComponentAdapter;
-import java.awt.event.ComponentEvent;
-import java.awt.event.FocusAdapter;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseMotionAdapter;
-import java.awt.event.MouseMotionListener;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.util.Arrays;
-
-import javax.swing.JPanel;
-
-import org.jfree.chart.ChartPanel;
-
-public class WaterfallPlot extends JPanel
-{
- /**
- *
- */
- private static final long serialVersionUID = 3249110968962287324L;
- private BufferedImage bufferedImages[] = new BufferedImage[2];
- private int chartXOffset = 0, chartWidth = 100;
- private boolean displayMarker = false;
- private double displayMarkerFrequency = 0;
- private int displayMarkerX = 0;
- private int drawIndex = 0;
- /**
- * stores max value in pixel
- */
- private float drawMaxBuffer[];
- private EMA fps = new EMA(3);
-
- private int fpsRenderedFrames = 0;
-
- private long lastFPSRecalculated = 0;
-
- private DatasetSpectrum lastSpectrum = null;
- private ColorPalette palette = new HotIronBluePalette();
-
- private Rectangle2D.Float rect = new Rectangle2D.Float(0f, 0f, 1f, 1f);
-
- private String renderingInfo = "";
- private int screenWidth;
- private double spectrumPaletteSize = 65;
- private double spectrumPaletteStart = -90;
- private String statusMessage = "";
-
- public WaterfallPlot(ChartPanel chartPanel, int maxHeight)
- {
- setPreferredSize(new Dimension(100, 200));
- setMinimumSize(new Dimension(100, 200));
-
- addComponentListener(new ComponentAdapter()
- {
- @Override public void componentResized(ComponentEvent e)
- {
- setHistorySize(getHeight());
- }
- });
-
- screenWidth = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
- drawMaxBuffer = new float[screenWidth];
- bufferedImages[0] = new BufferedImage(screenWidth, maxHeight, BufferedImage.TYPE_3BYTE_BGR);
- bufferedImages[1] = new BufferedImage(screenWidth, maxHeight, BufferedImage.TYPE_3BYTE_BGR);
-
- /**
- * setup frequency marker
- */
- addMouseMotionListener(new MouseMotionAdapter() {
- @Override
- public void mouseMoved(MouseEvent e) {
- displayMarker = false;
- int x = e.getX();
- if (x < chartXOffset || x > chartXOffset+chartWidth){
- return;
- }
- double freq = translateChartXToFrequency(x-chartXOffset);
- if (freq != -1){
- displayMarker = true;
- displayMarkerFrequency = freq;
- displayMarkerX = x;
- }
- WaterfallPlot.this.repaint();
- }
- });
- addMouseListener(new MouseAdapter() {
- @Override
- public void mouseExited(MouseEvent e) {
- displayMarker = false;
- }
- });
- }
- /**
- * Adds new data to the waterfall plot and renders it
- * @param spectrum
- */
- public synchronized void addNewData(DatasetSpectrum spectrum)
- {
- int size = spectrum.spectrumLength();
- double startFreq = spectrum.getFreqStartMHz() * 1000000d;
- double freqRange = (spectrum.getFreqStopMHz() - spectrum.getFreqStartMHz()) * 1000000d;
- double width = bufferedImages[0].getWidth();
- double spectrumPalleteMax = spectrumPaletteStart + spectrumPaletteSize;
-
- this.lastSpectrum = spectrum;
-
- /**
- * shift image by one pixel down
- */
- BufferedImage previousImage = bufferedImages[drawIndex];
- drawIndex = (drawIndex + 1) % 2;
- Graphics2D g = bufferedImages[drawIndex].createGraphics();
- g.drawImage(previousImage, 0, 1, null);
- g.setColor(Color.black);
- g.fillRect(0, 0, (int) width, 1);
-
- float binWidth = (float) (spectrum.getFFTBinSizeHz() / freqRange * width);
- rect.x = 0;
- rect.y = 0;
- rect.height = 0;
- rect.width = binWidth;
-
- float minimumValueDrawBuffer = -150;
- Arrays.fill(drawMaxBuffer, minimumValueDrawBuffer);
-
- /**
- * draw in two passes - first determines maximum power for the pixel, second draws it
- */
- for (int i = 0; i < size; i++)
- {
- double freq = spectrum.getFrequency(i);
- double power = spectrum.getPower(i);
- double percentageFreq = (freq - startFreq) / freqRange;
- double percentagePower = power < spectrumPaletteStart ? 0 : power > spectrumPalleteMax ? 1 : (power - spectrumPaletteStart) / spectrumPaletteSize;
- int pixelX = (int) Math.round(width * percentageFreq);
- pixelX = pixelX >= drawMaxBuffer.length ? drawMaxBuffer.length-1 : pixelX < 0 ? 0 : pixelX;
- if (percentagePower > drawMaxBuffer[pixelX])
- drawMaxBuffer[pixelX] = (float) percentagePower;
- }
-
- /**
- * fill in pixels that do not have power with last bin's color
- */
- Color lastValidColor = palette.getColor(0);
- for (int x = 0; x < drawMaxBuffer.length; x++)
- {
- Color color;
- if (drawMaxBuffer[x] == minimumValueDrawBuffer)
- color = lastValidColor;
- else
- {
- color = palette.getColorNormalized(drawMaxBuffer[x]);
- lastValidColor = color;
- }
- rect.x = x;
- g.setColor(color);
- g.draw(rect);
- }
-
- renderingInfo = String.format("RBW %.1fkHz / FFT bins: %d%s / %.1ffps", lastSpectrum == null ? 0 : lastSpectrum.getFFTBinSizeHz()/1000d, size >= 10000 ? size / 1000 : size, size >= 10000 ? "k" : "", fps.getEma());
- fpsRenderedFrames++;
- if (System.currentTimeMillis() - lastFPSRecalculated > 1000)
- {
- double rawfps = fpsRenderedFrames / ((System.currentTimeMillis() - (double) lastFPSRecalculated) / 1000d);
- fps.addNewValue(rawfps);
- lastFPSRecalculated = System.currentTimeMillis();
- fpsRenderedFrames = 0;
- }
- g.dispose();
- repaint();
- }
-
- private void copyImage(BufferedImage src, BufferedImage dst)
- {
- Graphics2D g = dst.createGraphics();
- g.drawImage(src, 0, 0, null);
- g.dispose();
- }
-
- /**
- * Draws color palette into given area from bottom (0%) to top (100%)
- * @param g
- * @param x
- * @param y
- * @param w
- * @param h
- */
- public void drawScale(Graphics2D g, int x, int y, int w, int h)
- {
- g = (Graphics2D) g.create(x, y, w, h);
- int step = 3;
- for (int i = 0; i < h; i += step)
- {
- Color c = palette.getColorNormalized(1 - (double) i / h);
- g.setColor(c);
- g.fillRect(0, i, w, step);
- }
-
- /**
- * draw border around the scale
- */
- int thickness = 2;
- g.setColor(Color.darkGray);
- g.fillRect(0, 0, w, thickness);
- g.fillRect(w-thickness, 0, thickness, h);
- g.fillRect(0, h-thickness, w, thickness);
- g.dispose();
- }
-
- public int getHistorySize()
- {
- return bufferedImages[0].getHeight();
- }
-
- public double getSpectrumPaletteSize()
- {
- return spectrumPaletteSize;
- }
-
- public double getSpectrumPaletteStart()
- {
- return spectrumPaletteStart;
- }
-
- @Override protected void paintComponent(Graphics arg0)
- {
- Graphics2D g = (Graphics2D) arg0;
- g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
- int w = chartWidth;
- int h = getHeight();
- g.setColor(Color.black);
- g.fillRect(0, 0, getWidth(), getHeight());
-
- g.drawImage(bufferedImages[drawIndex], chartXOffset, 0, w, h, null);
-
- if (displayMarker){
- g.setColor(Color.gray);
- g.drawLine(displayMarkerX, 0, displayMarkerX, h);
- g.drawString(String.format("%.1fMHz", displayMarkerFrequency/1000000.0), displayMarkerX+5, h/2);
- }//finish marker
-
- g.setColor(Color.white);
- int x = chartXOffset + w - 250;
- int y = h - 20;
- g.drawString(renderingInfo, x, y-20);
- g.drawString(statusMessage, x, y);
- }
-
- public void setStatusMessage(String message)
- {
- this.statusMessage = message;
- }
-
- public void setDrawingOffsets(int xOffsetLeft, int width)
- {
- this.chartXOffset = xOffsetLeft;
- this.chartWidth = width;
- }
-
- public synchronized void setHistorySize(int historyInPixels)
- {
- BufferedImage bufferedImages[] = new BufferedImage[2];
- bufferedImages[0] = new BufferedImage(screenWidth, historyInPixels, BufferedImage.TYPE_3BYTE_BGR);
- bufferedImages[1] = new BufferedImage(screenWidth, historyInPixels, BufferedImage.TYPE_3BYTE_BGR);
- copyImage(this.bufferedImages[0], bufferedImages[0]);
- copyImage(this.bufferedImages[1], bufferedImages[1]);
- this.bufferedImages = bufferedImages;
- }
-
- public void setSpectrumPaletteSize(int dB)
- {
- this.spectrumPaletteSize = dB;
- }
-
- /**
- * Sets start and end of the color scale
- * @param minFreqency
- * @param maxFrequency
- */
- public void setSpectrumPaletteStart(int dB)
- {
- this.spectrumPaletteStart = dB;
- }
-
- private double translateChartXToFrequency(int x){
- if (lastSpectrum != null){
- double startFreq = lastSpectrum.getFreqStartMHz() * 1000000d;
- double stopFreq = lastSpectrum.getFreqStopMHz() * 1000000d;
- double freqRange = (stopFreq - startFreq);
- double width = bufferedImages[0].getWidth();
- double percentageFreq = x/(double)chartWidth;
- double freq = percentageFreq*freqRange + startFreq;
- if (freq > stopFreq)
- freq = stopFreq;
- if (freq < startFreq)
- freq = startFreq;
- return freq;
- }
- return -1;
- }
-}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/jfc/XYSeriesCollectionImmutable.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/jfc/XYSeriesCollectionImmutable.java
new file mode 100644
index 0000000..b351f23
--- /dev/null
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/jfc/XYSeriesCollectionImmutable.java
@@ -0,0 +1,20 @@
+package jspectrumanalyzer.core.jfc;
+
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+
+/**
+ * {@link XYSeriesCollection} for use with {@link XYSeriesImmutable}
+ */
+public class XYSeriesCollectionImmutable extends XYSeriesCollection {
+
+ @Override
+ public double getXValue(int series, int item) {
+ return ((XYSeriesImmutable)getSeries(series)).getXX(item);
+ }
+
+ @Override
+ public double getYValue(int series, int item) {
+ return ((XYSeriesImmutable)getSeries(series)).getYY(item);
+ }
+}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/jfc/XYSeriesImmutable.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/jfc/XYSeriesImmutable.java
new file mode 100644
index 0000000..43f75d4
--- /dev/null
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/core/jfc/XYSeriesImmutable.java
@@ -0,0 +1,41 @@
+package jspectrumanalyzer.core.jfc;
+
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.data.xy.XYDataItem;
+import org.jfree.data.xy.XYSeries;
+
+/**
+ * Optimized immutable {@link XYSeries} for use with {@link XYLineAndShapeRenderer}.
+ * No allocation of {@link XYDataItem} or any other objects.
+ */
+public class XYSeriesImmutable extends XYSeries {
+ private float[] xValues;
+ private float[] yValues;
+
+ public XYSeriesImmutable(Comparable key, float[] xValues, float[] yValues) {
+ super(key, false, false);
+ if (xValues.length != yValues.length)
+ throw new IllegalArgumentException("x/y values are not of the same size");
+ this.xValues = xValues.clone();
+ this.yValues = yValues.clone();
+ }
+
+ public double getXX(int item) {
+ return xValues[item];
+ }
+
+ public double getYY(int item) {
+ return yValues[item];
+ }
+
+ @Override
+ public int getItemCount() {
+ return xValues.length;
+ }
+
+ @Override
+ public XYDataItem getDataItem(int index) {
+ return null;
+ }
+
+}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/ColorPalette.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/ColorPalette.java
similarity index 86%
rename from src/hackrf-sweep/src-java/jspectrumanalyzer/core/ColorPalette.java
rename to src/hackrf-sweep/src-java/jspectrumanalyzer/ui/ColorPalette.java
index 2dd3c24..aa54344 100644
--- a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/ColorPalette.java
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/ColorPalette.java
@@ -1,4 +1,4 @@
-package jspectrumanalyzer.core;
+package jspectrumanalyzer.ui;
import java.awt.Color;
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencySelectorPanel.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/FrequencySelectorPanel.java
similarity index 88%
rename from src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencySelectorPanel.java
rename to src/hackrf-sweep/src-java/jspectrumanalyzer/ui/FrequencySelectorPanel.java
index f58e1be..25b2183 100644
--- a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/FrequencySelectorPanel.java
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/FrequencySelectorPanel.java
@@ -1,10 +1,9 @@
-package jspectrumanalyzer.core;
+package jspectrumanalyzer.ui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
-import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyVetoException;
import java.lang.reflect.InvocationTargetException;
@@ -152,18 +151,14 @@ public boolean setValue(int newValue)
{
try
{
- SwingUtilities.invokeAndWait(new Runnable()
- {
- @Override public void run()
+ SwingUtilities.invokeAndWait(() -> {
+ try
{
- try
- {
- fireValueChange(oldValue, newValue);
- }
- catch (PropertyVetoException e)
- {
- throw new RuntimeException(e);
- }
+ fireValueChange(oldValue, newValue);
+ }
+ catch (PropertyVetoException e)
+ {
+ throw new RuntimeException(e);
}
});
}
@@ -203,15 +198,11 @@ private void add(int digit)
private ActionListener addListener(boolean add, int digit)
{
- ActionListener listener = new ActionListener()
- {
- @Override public void actionPerformed(ActionEvent e)
- {
- if (add)
- add(digit);
- else
- subtract(digit);
- }
+ ActionListener listener = e -> {
+ if (add)
+ add(digit);
+ else
+ subtract(digit);
};
return listener;
}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/FrequencySelectorRangeBinder.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/FrequencySelectorRangeBinder.java
new file mode 100644
index 0000000..adfaae5
--- /dev/null
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/FrequencySelectorRangeBinder.java
@@ -0,0 +1,50 @@
+package jspectrumanalyzer.ui;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyVetoException;
+import java.beans.VetoableChangeListener;
+
+import jspectrumanalyzer.core.FrequencyRange;
+import jspectrumanalyzer.core.HackRFSettings;
+
+/**
+ * Limits frequency selection of two selectors (start/end)
+ */
+public class FrequencySelectorRangeBinder
+{
+ public FrequencySelectorPanel selFreqStart, selFreqEnd;
+ public FrequencySelectorRangeBinder(FrequencySelectorPanel selFreqStart, FrequencySelectorPanel selFreqEnd)
+ {
+ this.selFreqEnd = selFreqEnd;
+ this.selFreqStart = selFreqStart;
+ VetoableChangeListener freqStartVetoable = evt -> {
+ Integer newVal = (Integer) evt.getNewValue();
+ if (newVal >= selFreqEnd.getValue())
+ {
+ //try to increase freq end by the same value
+ if (!selFreqEnd.setValue(selFreqEnd.getValue() + (newVal - (Integer) evt.getOldValue())))
+ throw new PropertyVetoException(">", evt);
+ }
+ };
+ VetoableChangeListener freqEndVetoable = evt -> {
+ Integer newVal = (Integer) evt.getNewValue();
+ if (newVal <= selFreqStart.getValue())
+ {
+ if (!selFreqStart.setValue(selFreqStart.getValue() - ((Integer) evt.getOldValue() - newVal)))
+ throw new PropertyVetoException(">", evt);
+ }
+ };
+
+ selFreqEnd.addVetoableChangeListener(freqEndVetoable);
+ selFreqStart.addVetoableChangeListener(freqStartVetoable);
+ }
+
+ public void addPropertyChangeListener(PropertyChangeListener propertyChangeListener) {
+ selFreqStart.addPropertyChangeListener("value", propertyChangeListener);
+ selFreqEnd.addPropertyChangeListener("value", propertyChangeListener);
+ }
+
+ public FrequencyRange getFrequencyRange() {
+ return new FrequencyRange(selFreqStart.getValue(), selFreqEnd.getValue());
+ }
+}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/GraphicsToolkit.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/GraphicsToolkit.java
new file mode 100644
index 0000000..42d7387
--- /dev/null
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/GraphicsToolkit.java
@@ -0,0 +1,26 @@
+package jspectrumanalyzer.ui;
+
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.Transparency;
+import java.awt.image.BufferedImage;
+
+public class GraphicsToolkit {
+
+ public static BufferedImage createAcceleratedImageTransparent(int width, int height) {
+ return createAcceleratedImage(width, height, Transparency.TRANSLUCENT);
+ }
+
+ public static BufferedImage createAcceleratedImageOpaque(int width, int height) {
+ return createAcceleratedImage(width, height, Transparency.OPAQUE);
+ }
+
+ private static BufferedImage createAcceleratedImage(int width, int height, int transparency) {
+ GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
+ BufferedImage image = gc.createCompatibleImage(width, height, transparency);
+ image.setAccelerationPriority(1);
+ return image;
+ }
+
+}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/HackRFSweepSettingsUI.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/HackRFSweepSettingsUI.java
new file mode 100644
index 0000000..c84360c
--- /dev/null
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/HackRFSweepSettingsUI.java
@@ -0,0 +1,455 @@
+package jspectrumanalyzer.ui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Desktop;
+import java.awt.Font;
+import java.awt.GridLayout;
+import java.awt.Label;
+import java.beans.PropertyChangeEvent;
+import java.math.BigDecimal;
+import java.net.URI;
+import java.util.Optional;
+import java.util.Vector;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import javax.swing.DefaultBoundedRangeModel;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.JSpinner;
+import javax.swing.JTabbedPane;
+import javax.swing.JSpinner.ListEditor;
+import javax.swing.JTextField;
+import javax.swing.SpinnerListModel;
+import javax.swing.UIManager;
+
+import jspectrumanalyzer.HackRFSweepSpectrumAnalyzer;
+import jspectrumanalyzer.Version;
+import jspectrumanalyzer.core.FrequencyAllocationTable;
+import jspectrumanalyzer.core.FrequencyAllocations;
+import jspectrumanalyzer.core.FrequencyRange;
+import jspectrumanalyzer.core.HackRFSettings;
+import jspectrumanalyzer.core.HackRFSettings.HackRFEventAdapter;
+import net.miginfocom.swing.MigLayout;
+import shared.mvc.MVCController;
+import javax.swing.border.BevelBorder;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.SwingUtilities;
+import javax.swing.JComboBox;
+import javax.swing.SwingConstants;
+
+public class HackRFSweepSettingsUI extends JPanel
+{
+ /**
+ *
+ */
+ private HackRFSettings hRF;
+ private static final long serialVersionUID = 7721079457485020637L;
+ private JTextField txtHackrfConnected;
+ private FrequencySelectorPanel frequencySelectorStart;
+ private FrequencySelectorPanel frequencySelectorEnd;
+ private JSpinner spinnerFFTBinHz;
+ private JSlider sliderGain;
+ private JSpinner spinner_numberOfSamples;
+ private JCheckBox chckbxAntennaPower;
+ private JSlider slider_waterfallPaletteStart;
+ private JSlider slider_waterfallPaletteSize;
+ private JCheckBox chckbxShowPeaks;
+ private JCheckBox chckbxRemoveSpurs;
+ private JButton btnPause;
+ private SpinnerListModel spinnerModelFFTBinHz;
+ private FrequencySelectorRangeBinder frequencyRangeSelector;
+ private JCheckBox chckbxFilterSpectrum;
+ private JSpinner spinnerPeakFallSpeed;
+ private JComboBox comboBoxFrequencyAllocationBands;
+ private JSlider sliderGainVGA;
+ private JSlider sliderGainLNA;
+ private JLabel lblPeakFall;
+ private JComboBox comboBoxLineThickness;
+ private JLabel lblPersistentDisplay;
+ private JCheckBox checkBoxPersistentDisplay;
+ private JCheckBox checkBoxWaterfallEnabled;
+ private JLabel lblDecayRate;
+ private JComboBox comboBoxDecayRate;
+ private JLabel lblDebugDisplay;
+ private JCheckBox checkBoxDebugDisplay;
+
+ /**
+ * Create the panel.
+ */
+ public HackRFSweepSettingsUI(HackRFSettings hackRFSettings)
+ {
+ this.hRF = hackRFSettings;
+ setForeground(Color.WHITE);
+ setBackground(Color.BLACK);
+ int minFreq = 1;
+ int maxFreq = 7250;
+ int freqStep = 1;
+
+ JPanel panelMainSettings = new JPanel(new MigLayout("", "[123.00px,grow,leading]", "[][][::0px][][]"));
+ panelMainSettings.setBorder(new EmptyBorder(UIManager.getInsets("TabbedPane.tabAreaInsets")));;
+ panelMainSettings.setBackground(Color.BLACK);
+ JLabel lblNewLabel = new JLabel("Frequency start [MHz]");
+ lblNewLabel.setForeground(Color.WHITE);
+ panelMainSettings.add(lblNewLabel, "cell 0 0,growx,aligny center");
+
+ frequencySelectorStart = new FrequencySelectorPanel(minFreq, maxFreq, freqStep, minFreq);
+ panelMainSettings.add(frequencySelectorStart, "cell 0 1,grow");
+
+ JLabel lblFrequencyEndmhz = new JLabel("Frequency end [MHz]");
+ lblFrequencyEndmhz.setForeground(Color.WHITE);
+ panelMainSettings.add(lblFrequencyEndmhz, "cell 0 3,alignx left,aligny center");
+
+ frequencySelectorEnd = new FrequencySelectorPanel(minFreq, maxFreq, freqStep, maxFreq);
+ panelMainSettings.add(frequencySelectorEnd, "cell 0 4,grow");
+
+
+ txtHackrfConnected = new JTextField();
+ txtHackrfConnected.setText("HackRF disconnected");
+ txtHackrfConnected.setForeground(Color.WHITE);
+ txtHackrfConnected.setBackground(Color.BLACK);
+ panelMainSettings.add(txtHackrfConnected, "cell 0 23,growx");
+ txtHackrfConnected.setColumns(10);
+ txtHackrfConnected.setBorder(null);
+
+ btnPause = new JButton("Pause");
+ panelMainSettings.add(btnPause, "cell 0 25,growx");
+ btnPause.setBackground(Color.black);
+
+
+
+
+ JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
+ setLayout(new BorderLayout());
+ add(panelMainSettings, BorderLayout.NORTH);
+ add(tabbedPane, BorderLayout.CENTER);
+ tabbedPane.setForeground(Color.WHITE);
+ tabbedPane.setBackground(Color.BLACK);
+
+ JPanel tab1 = new JPanel(new MigLayout("", "[123.00px,grow,leading]", "[][][0][][][0][][][0][][][0][][][0][][0][][grow,fill]"));
+ tab1.setForeground(Color.WHITE);
+ tab1.setBackground(Color.BLACK);
+
+ JPanel tab2 = new JPanel(new MigLayout("", "[123.00px,grow,leading]", "[][0][][][0][][][0][][0][][][0][][0][][][0][0][][][0][][0][grow,fill]"));
+ tab2.setForeground(Color.WHITE);
+ tab2.setBackground(Color.BLACK);
+
+ tabbedPane.addTab("HackRF Settings", tab1);
+ tabbedPane.addTab("Chart options", tab2);
+ tabbedPane.setForegroundAt(1, Color.BLACK);
+ tabbedPane.setBackgroundAt(1, Color.WHITE);
+
+ tabbedPane.setForegroundAt(0, Color.BLACK);
+ tabbedPane.setBackgroundAt(0, Color.WHITE);
+
+ JLabel lblNewLabel_2 = new JLabel("LNA Gain [dB]");
+ lblNewLabel_2.setForeground(Color.WHITE);
+ tab1.add(lblNewLabel_2, "cell 0 3");
+
+ sliderGainLNA = new JSlider(SwingConstants.HORIZONTAL, 0, 100, 2);
+ sliderGainLNA.setForeground(Color.WHITE);
+ sliderGainLNA.setFont(new Font("Monospaced", Font.BOLD, 16));
+ sliderGainLNA.setBackground(Color.BLACK);
+ tab1.add(sliderGainLNA, "cell 0 4,growx");
+
+ JLabel lblVgfaGaindb = new JLabel("VGA Gain [dB]");
+ lblVgfaGaindb.setForeground(Color.WHITE);
+ tab1.add(lblVgfaGaindb, "cell 0 6");
+
+ sliderGainVGA = new JSlider(SwingConstants.HORIZONTAL, 0, 100, 2);
+ sliderGainVGA.setForeground(Color.WHITE);
+ sliderGainVGA.setFont(new Font("Monospaced", Font.BOLD, 16));
+ sliderGainVGA.setBackground(Color.BLACK);
+ tab1.add(sliderGainVGA, "cell 0 7,growx");
+
+
+
+ JLabel lblFftBinhz = new JLabel("FFT Bin [Hz]");
+ lblFftBinhz.setForeground(Color.WHITE);
+ tab1.add(lblFftBinhz, "cell 0 9");
+
+ spinnerFFTBinHz = new JSpinner();
+ spinnerFFTBinHz.setFont(new Font("Monospaced", Font.BOLD, 16));
+ spinnerModelFFTBinHz = new SpinnerListModel(new String[] { "1 000", "2 000", "5 000", "10 000", "20 000",
+ "50 000", "100 000", "200 000", "500 000", "1 000 000", "2 000 000", "5 000 000" });
+ spinnerFFTBinHz.setModel(spinnerModelFFTBinHz);
+ tab1.add(spinnerFFTBinHz, "cell 0 10,growx");
+ ((ListEditor) spinnerFFTBinHz.getEditor()).getTextField().setHorizontalAlignment(JTextField.RIGHT);
+
+
+ JLabel lblGain = new JLabel("Gain [dB]");
+ lblGain.setForeground(Color.WHITE);
+ tab1.add(lblGain, "cell 0 0");
+
+ sliderGain = new JSlider(JSlider.HORIZONTAL, 0, 100, 2);
+ sliderGain.setFont(new Font("Monospaced", Font.BOLD, 16));
+ sliderGain.setBackground(Color.BLACK);
+ sliderGain.setForeground(Color.WHITE);
+ tab1.add(sliderGain, "flowy,cell 0 1,growx");
+
+ JLabel lbl_gainValue = new JLabel(hackRFSettings.getGain() + "dB");
+ lbl_gainValue.setForeground(Color.WHITE);
+ tab1.add(lbl_gainValue, "cell 0 1,alignx right");
+
+ hackRFSettings.getGain().addListener((gain) -> lbl_gainValue.setText(String.format(" %ddB [LNA: %ddB VGA: %ddB]",
+ gain, hackRFSettings.getGainLNA().getValue(), hackRFSettings.getGainVGA().getValue())));
+
+
+ JLabel lblNumberOfSamples = new JLabel("Number of samples");
+ lblNumberOfSamples.setForeground(Color.WHITE);
+ tab1.add(lblNumberOfSamples, "cell 0 12");
+
+ spinner_numberOfSamples = new JSpinner();
+ spinner_numberOfSamples.setModel(new SpinnerListModel(new String[] { "8192", "16384", "32768", "65536", "131072", "262144" }));
+ spinner_numberOfSamples.setFont(new Font("Monospaced", Font.BOLD, 16));
+ ((ListEditor) spinner_numberOfSamples.getEditor()).getTextField().setHorizontalAlignment(JTextField.RIGHT);
+ ((ListEditor) spinner_numberOfSamples.getEditor()).getTextField().setEditable(false);
+ tab1.add(spinner_numberOfSamples, "cell 0 13,growx");
+
+ JButton btnAbout = new JButton("Visit homepage");
+ btnAbout.addActionListener(e -> {
+ if (Desktop.isDesktopSupported()) {
+ Desktop desktop = Desktop.getDesktop();
+ try {
+ URI uri = new URI(Version.url);
+ desktop.browse(uri);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ });
+
+ Label labelVersion = new Label("Version: v"+Version.version);
+ tab1.add(labelVersion, "flowx,cell 0 17");
+ btnAbout.setBackground(Color.BLACK);
+ tab1.add(btnAbout, "cell 0 17,alignx right");
+
+ JLabel lblAntennaPower = new JLabel("Antenna power");
+ lblAntennaPower.setForeground(Color.WHITE);
+ tab1.add(lblAntennaPower, "flowx,cell 0 15,growx");
+
+ chckbxAntennaPower = new JCheckBox("");
+ chckbxAntennaPower.setHorizontalTextPosition(SwingConstants.LEADING);
+ chckbxAntennaPower.setBackground(Color.BLACK);
+ chckbxAntennaPower.setForeground(Color.WHITE);
+ tab1.add(chckbxAntennaPower, "cell 0 15,alignx right");
+
+ chckbxFilterSpectrum = new JCheckBox("Filter spectrum");
+ chckbxFilterSpectrum.setBackground(Color.BLACK);
+ chckbxFilterSpectrum.setForeground(Color.WHITE);
+
+ JLabel lblWaterfallEnabled = new JLabel("Waterfall enabled");
+ lblWaterfallEnabled.setForeground(Color.WHITE);
+ tab2.add(lblWaterfallEnabled, "flowx,cell 0 0,growx");
+
+
+
+
+ JLabel lblWaterfallPaletteStart = new JLabel("Waterfall palette start [dB]");
+ lblWaterfallPaletteStart.setForeground(Color.WHITE);
+ tab2.add(lblWaterfallPaletteStart, "cell 0 2");
+
+ slider_waterfallPaletteStart = new JSlider();
+ slider_waterfallPaletteStart.setForeground(Color.WHITE);
+ slider_waterfallPaletteStart.setBackground(Color.BLACK);
+ slider_waterfallPaletteStart.setMinimum(-100);
+ slider_waterfallPaletteStart.setMaximum(0);
+ slider_waterfallPaletteStart.setValue(-30);
+ tab2.add(slider_waterfallPaletteStart, "cell 0 3,growx");
+
+
+ JLabel lblWaterfallPaletteLength = new JLabel("Waterfall palette length [dB]");
+ lblWaterfallPaletteLength.setForeground(Color.WHITE);
+ tab2.add(lblWaterfallPaletteLength, "cell 0 5");
+
+ slider_waterfallPaletteSize = new JSlider(HackRFSweepSpectrumAnalyzer.SPECTRUM_PALETTE_SIZE_MIN, 100);
+ slider_waterfallPaletteSize.setBackground(Color.BLACK);
+ slider_waterfallPaletteSize.setForeground(Color.WHITE);
+ tab2.add(slider_waterfallPaletteSize, "cell 0 6,growx");
+
+ JLabel lblSpectrLineThickness = new JLabel("Spectr. Line Thickness");
+ lblSpectrLineThickness.setForeground(Color.WHITE);
+ tab2.add(lblSpectrLineThickness, "flowx,cell 0 8,growx");
+
+ JLabel lblShowPeaks = new JLabel("Show peaks");
+ lblShowPeaks.setForeground(Color.WHITE);
+ tab2.add(lblShowPeaks, "flowx,cell 0 10,growx");
+
+
+ chckbxShowPeaks = new JCheckBox("");
+ chckbxShowPeaks.setForeground(Color.WHITE);
+ chckbxShowPeaks.setBackground(Color.BLACK);
+ tab2.add(chckbxShowPeaks, "cell 0 10,alignx right");
+
+ JLabel lblSpurFiltermay = new JLabel("Spur filter (may distort real signals)");
+ lblSpurFiltermay.setForeground(Color.WHITE);
+ tab2.add(lblSpurFiltermay, "flowx,cell 0 13,growx");
+
+ chckbxRemoveSpurs = new JCheckBox("");
+ chckbxRemoveSpurs.setForeground(Color.WHITE);
+ chckbxRemoveSpurs.setBackground(Color.BLACK);
+ tab2.add(chckbxRemoveSpurs, "cell 0 13,alignx right");
+
+ lblPeakFall = new JLabel(" Fall speed [s]");
+ lblPeakFall.setForeground(Color.WHITE);
+ tab2.add(lblPeakFall, "flowx,cell 0 11,growx");
+
+ spinnerPeakFallSpeed = new JSpinner();
+ spinnerPeakFallSpeed.setModel(new SpinnerNumberModel(10, 0, 500, 1));
+ tab2.add(spinnerPeakFallSpeed, "cell 0 11,alignx right");
+
+ lblPersistentDisplay = new JLabel("Persistent Display");
+ lblPersistentDisplay.setForeground(Color.WHITE);
+ tab2.add(lblPersistentDisplay, "flowx,cell 0 15,growx");
+
+ lblDecayRate = new JLabel(" Persistence time [s]");
+ lblDecayRate.setForeground(Color.WHITE);
+ tab2.add(lblDecayRate, "flowx,cell 0 16,growx");
+
+ JLabel lblDisplayFrequencyAllocation = new JLabel("Frequency Allocation Bands");
+ lblDisplayFrequencyAllocation.setForeground(Color.WHITE);
+ tab2.add(lblDisplayFrequencyAllocation, "cell 0 19");
+
+
+ FrequencyAllocations frequencyAllocations = new FrequencyAllocations();
+ Vector freqAllocValues = new Vector<>();
+ freqAllocValues.add(null);
+ freqAllocValues.addAll(frequencyAllocations.getTable().values());
+ DefaultComboBoxModel freqAllocModel = new DefaultComboBoxModel<>(freqAllocValues);
+ comboBoxFrequencyAllocationBands = new JComboBox(freqAllocModel);
+ tab2.add(comboBoxFrequencyAllocationBands, "cell 0 20,growx");
+
+ comboBoxLineThickness = new JComboBox(new BigDecimal[] {
+ new BigDecimal("1"), new BigDecimal("1.5"), new BigDecimal("2"), new BigDecimal("3")
+ });
+ tab2.add(comboBoxLineThickness, "cell 0 8,alignx right");
+
+ checkBoxPersistentDisplay = new JCheckBox("");
+ checkBoxPersistentDisplay.setForeground(Color.WHITE);
+ checkBoxPersistentDisplay.setBackground(Color.BLACK);
+ tab2.add(checkBoxPersistentDisplay, "cell 0 15,alignx right");
+
+ checkBoxWaterfallEnabled = new JCheckBox("");
+ checkBoxWaterfallEnabled.setForeground(Color.WHITE);
+ checkBoxWaterfallEnabled.setBackground(Color.BLACK);
+ tab2.add(checkBoxWaterfallEnabled, "cell 0 0,alignx right");
+
+ comboBoxDecayRate = new JComboBox(
+ new Vector<>(IntStream.rangeClosed(hRF.getPersistentDisplayDecayRate().getMin(), hRF.getPersistentDisplayDecayRate().getMax()).
+ boxed().collect(Collectors.toList())));
+ tab2.add(comboBoxDecayRate, "cell 0 16,alignx right");
+
+ lblDebugDisplay = new JLabel("Debug display");
+ lblDebugDisplay.setForeground(Color.WHITE);
+ tab2.add(lblDebugDisplay, "flowx,cell 0 22,growx");
+
+ checkBoxDebugDisplay = new JCheckBox("");
+ checkBoxDebugDisplay.setForeground(Color.WHITE);
+ checkBoxDebugDisplay.setBackground(Color.BLACK);
+ tab2.add(checkBoxDebugDisplay, "cell 0 22,alignx right");
+
+
+ bindViewToModel();
+ }
+
+ private void bindViewToModel() {
+ frequencyRangeSelector = new FrequencySelectorRangeBinder(frequencySelectorStart, frequencySelectorEnd);
+
+ new MVCController(spinnerFFTBinHz, hRF.getFFTBinHz(),
+ viewValue -> Integer.parseInt(viewValue.toString().replaceAll("\\s", "")),
+ modelValue -> {
+ Optional> val = spinnerModelFFTBinHz.getList().stream().filter(value -> modelValue <= Integer.parseInt(value.toString().replaceAll("\\s", ""))).findFirst();
+ if (val.isPresent())
+ return val.get();
+ else
+ return spinnerModelFFTBinHz.getList().get(0);
+ });
+ new MVCController(sliderGain, hRF.getGain());
+ new MVCController(spinner_numberOfSamples, hRF.getSamples(), val -> Integer.parseInt(val.toString()), val -> val.toString());
+ new MVCController(chckbxAntennaPower, hRF.getAntennaPowerEnable());
+ new MVCController(slider_waterfallPaletteStart, hRF.getSpectrumPaletteStart());
+ new MVCController(slider_waterfallPaletteSize, hRF.getSpectrumPaletteSize());
+ new MVCController( (Consumer valueChangedCall) ->
+ frequencyRangeSelector.addPropertyChangeListener((PropertyChangeEvent evt) -> valueChangedCall.accept(frequencyRangeSelector.getFrequencyRange()) ) ,
+ (FrequencyRange newComponentValue) -> {
+ if(frequencyRangeSelector.selFreqStart.getValue() != newComponentValue.getStartMHz())
+ frequencyRangeSelector.selFreqStart.setValue(newComponentValue.getStartMHz());
+ if(frequencyRangeSelector.selFreqEnd.getValue() != newComponentValue.getEndMHz())
+ frequencyRangeSelector.selFreqEnd.setValue(newComponentValue.getEndMHz());
+ },
+ hRF.getFrequency()
+ );
+ new MVCController(chckbxShowPeaks, hRF.isChartsPeaksVisible());
+ new MVCController(chckbxFilterSpectrum, hRF.isFilterSpectrum());
+ new MVCController(chckbxRemoveSpurs, hRF.isSpurRemoval());
+
+ new MVCController((valueChangedCall) -> btnPause.addActionListener((event) -> valueChangedCall.accept(!hRF.isCapturingPaused().getValue())),
+ isCapt -> btnPause.setText(!isCapt ? "Pause" : "Resume"),
+ hRF.isCapturingPaused());
+
+ new MVCController(spinnerPeakFallSpeed, hRF.getPeakFallRate(), in -> (Integer)in, in -> in);
+
+ new MVCController(comboBoxFrequencyAllocationBands, hRF.getFrequencyAllocationTable());
+
+ sliderGainLNA.setModel(new DefaultBoundedRangeModel(hRF.getGainLNA().getValue(), 0, hRF.getGainLNA().getMin(), hRF.getGainLNA().getMax()));
+ sliderGainVGA.setModel(new DefaultBoundedRangeModel(hRF.getGainVGA().getValue(), 0, hRF.getGainVGA().getMin(), hRF.getGainVGA().getMax()));
+
+ sliderGainLNA.setSnapToTicks(true);
+ sliderGainLNA.setMinorTickSpacing(hRF.getGainLNA().getStep());
+
+ sliderGainVGA.setSnapToTicks(true);
+ sliderGainVGA.setMinorTickSpacing(hRF.getGainVGA().getStep());
+
+ new MVCController(sliderGainLNA, hRF.getGainLNA());
+ new MVCController(sliderGainVGA, hRF.getGainVGA());
+
+ new MVCController(comboBoxLineThickness, hRF.getSpectrumLineThickness());
+
+ new MVCController(checkBoxPersistentDisplay, hRF.isPersistentDisplayVisible());
+
+ new MVCController(checkBoxWaterfallEnabled, hRF.isWaterfallVisible());
+
+ new MVCController(checkBoxDebugDisplay, hRF.isDebugDisplay());
+
+ hRF.isChartsPeaksVisible().addListener((enabled) -> {
+ SwingUtilities.invokeLater(()->{
+ spinnerPeakFallSpeed.setEnabled(enabled);
+ spinnerPeakFallSpeed.setVisible(enabled);
+ lblPeakFall.setVisible(enabled);
+ });
+ });
+ hRF.isChartsPeaksVisible().callObservers();
+
+ new MVCController(comboBoxDecayRate, hRF.getPersistentDisplayDecayRate());
+ hRF.isPersistentDisplayVisible().addListener((visible) -> {
+ SwingUtilities.invokeLater(()->{
+ comboBoxDecayRate.setVisible(visible);
+ lblDecayRate.setVisible(visible);
+ });
+ });
+ hRF.isPersistentDisplayVisible().callObservers();
+
+ hRF.registerListener(new HackRFSettings.HackRFEventAdapter()
+ {
+ @Override public void captureStateChanged(boolean isCapturing)
+ {
+// btnPause.setText(isCapturing ? "Pause" : "Resume");
+ }
+ @Override public void hardwareStatusChanged(boolean hardwareSendingData)
+ {
+ txtHackrfConnected.setText("HackRF "+(hardwareSendingData ? "connected":"disconnected"));
+ }
+ });;
+
+ }
+
+}
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/HotIronBluePalette.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/HotIronBluePalette.java
similarity index 95%
rename from src/hackrf-sweep/src-java/jspectrumanalyzer/core/HotIronBluePalette.java
rename to src/hackrf-sweep/src-java/jspectrumanalyzer/ui/HotIronBluePalette.java
index 3570fd2..5520398 100644
--- a/src/hackrf-sweep/src-java/jspectrumanalyzer/core/HotIronBluePalette.java
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/HotIronBluePalette.java
@@ -1,4 +1,4 @@
-package jspectrumanalyzer.core;
+package jspectrumanalyzer.ui;
import java.awt.Color;
@@ -62,12 +62,12 @@ public HotIronBluePalette()
@Override public Color getColorNormalized(double value)
{
- int index = (int) (size() * value);
+ int index = (int) (colors.length * value);
if (index < 0)
index = 0;
- if (index >= size())
- index = size() - 1;
- return getColor(index);
+ if (index >= colors.length)
+ index = colors.length - 1;
+ return colors[index];
}
@Override public int size()
diff --git a/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/WaterfallPlot.java b/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/WaterfallPlot.java
new file mode 100644
index 0000000..0ce67ed
--- /dev/null
+++ b/src/hackrf-sweep/src-java/jspectrumanalyzer/ui/WaterfallPlot.java
@@ -0,0 +1,366 @@
+package jspectrumanalyzer.ui;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.Toolkit;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionAdapter;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.util.Arrays;
+
+import javax.swing.JPanel;
+
+import org.jfree.chart.ChartPanel;
+
+import jspectrumanalyzer.core.DatasetSpectrum;
+import jspectrumanalyzer.core.EMA;
+
+public class WaterfallPlot extends JPanel {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3249110968962287324L;
+ private BufferedImage bufferedImages[] = new BufferedImage[2];
+ private int chartXOffset = 0, chartWidth = 100;
+ private boolean displayMarker = false;
+ private double displayMarkerFrequency = 0;
+ private int displayMarkerX = 0;
+ private int drawIndex = 0;
+ /**
+ * stores max value in pixel
+ */
+ private float drawMaxBuffer[];
+ private EMA fps = new EMA(3);
+ private int fpsRenderedFrames = 0;
+ private long lastFPSRecalculated = 0;
+ private DatasetSpectrum lastSpectrum = null;
+ private ColorPalette palette = new HotIronBluePalette();
+ private Rectangle2D.Float rect = new Rectangle2D.Float(0f, 0f, 1f, 1f);
+ private String renderingInfo = "";
+ private int screenWidth;
+ private double spectrumPaletteSize = 65;
+ private double spectrumPaletteStart = -90;
+ private String[] statusMessage = new String[4];
+
+ public WaterfallPlot(ChartPanel chartPanel, int maxHeight) {
+ setPreferredSize(new Dimension(100, 200));
+ setMinimumSize(new Dimension(100, 200));
+
+ addComponentListener(new ComponentAdapter() {
+ @Override
+ public void componentResized(ComponentEvent e) {
+ setHistorySize(getHeight());
+ }
+ });
+
+ screenWidth = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
+ drawMaxBuffer = new float[screenWidth];
+
+ bufferedImages[0] = GraphicsToolkit.createAcceleratedImageOpaque(screenWidth, maxHeight);
+ bufferedImages[1] = GraphicsToolkit.createAcceleratedImageOpaque(screenWidth, maxHeight);
+
+ /**
+ * setup frequency marker
+ */
+ addMouseMotionListener(new MouseMotionAdapter() {
+ @Override
+ public void mouseMoved(MouseEvent e) {
+ displayMarker = false;
+ int x = e.getX();
+ if (x < chartXOffset || x > chartXOffset + chartWidth) {
+ return;
+ }
+ double freq = translateChartXToFrequency(x - chartXOffset);
+ if (freq != -1) {
+ displayMarker = true;
+ displayMarkerFrequency = freq;
+ displayMarkerX = x;
+ }
+ WaterfallPlot.this.repaint();
+ }
+ });
+ addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseExited(MouseEvent e) {
+ displayMarker = false;
+ }
+ });
+ }
+
+ private EMA newDataTimeEMA = new EMA(100);
+ /**
+ * Adds new data to the waterfall plot and renders it
+ *
+ * @param spectrum
+ */
+ public synchronized void addNewData(DatasetSpectrum spectrum) {
+ long start = System.nanoTime();
+
+ int size = spectrum.spectrumLength();
+ double startFreq = spectrum.getFreqStartMHz() * 1000000d;
+ double freqRange = (spectrum.getFreqStopMHz() - spectrum.getFreqStartMHz()) * 1000000d;
+ double width = bufferedImages[0].getWidth();
+ double spectrumPalleteMax = spectrumPaletteStart + spectrumPaletteSize;
+
+ this.lastSpectrum = spectrum;
+
+ /**
+ * shift image by one pixel down
+ */
+ BufferedImage previousImage = bufferedImages[drawIndex];
+ drawIndex = (drawIndex + 1) % 2;
+ Graphics2D g = bufferedImages[drawIndex].createGraphics();
+ g.drawImage(previousImage, 0, 1, null);
+ g.setColor(Color.black);
+ g.fillRect(0, 0, (int) width, 1);
+
+ float binWidth = (float) (spectrum.getFFTBinSizeHz() / freqRange * width);
+ rect.x = 0;
+ rect.y = 0;
+ rect.height = 0;
+ rect.width = binWidth;
+
+ float minimumValueDrawBuffer = -150;
+ Arrays.fill(drawMaxBuffer, minimumValueDrawBuffer);
+
+ /**
+ * draw in two passes - first determines maximum power for the pixel,
+ * second draws it
+ */
+ if (true) {
+ //optimized drawing
+ double widthDivSize = (double)width / size;
+ double inverseSpectrumPaletteSize = 1d/spectrumPaletteSize;
+ double spectrumPaletteStartDivSpectrumPaletteSize = (double)spectrumPaletteStart/spectrumPaletteSize;
+ for (int i = 0; i < size; i++) {
+ double power = spectrum.getPower(i);
+ double percentagePower = 0;
+ if (power > spectrumPaletteStart) {
+ if ( power < spectrumPalleteMax) {
+// percentagePower = (power - spectrumPaletteStart) / spectrumPaletteSize;
+ //percentagePower = power/spectrumPaletteSize - spectrumPaletteStart/spectrumPaletteSize;
+ percentagePower = power*inverseSpectrumPaletteSize - spectrumPaletteStartDivSpectrumPaletteSize;
+ }
+ else
+ percentagePower = 1;
+ }
+ int pixelX = (int) Math.round(widthDivSize * i);
+ pixelX = pixelX >= drawMaxBuffer.length ? drawMaxBuffer.length - 1 : pixelX < 0 ? 0 : pixelX;
+ if (percentagePower > drawMaxBuffer[pixelX])
+ drawMaxBuffer[pixelX] = (float) percentagePower;
+ }
+ } else {
+ //unoptimized drawing
+ for (int i = 0; i < size; i++) {
+ double freq = spectrum.getFrequency(i);
+ double power = spectrum.getPower(i);
+ double percentageFreq = (freq - startFreq) / freqRange;
+ double percentagePower = power < spectrumPaletteStart ? 0
+ : power > spectrumPalleteMax ? 1 : (power - spectrumPaletteStart) / spectrumPaletteSize;
+ int pixelX = (int) Math.round(width * percentageFreq);
+ pixelX = pixelX >= drawMaxBuffer.length ? drawMaxBuffer.length - 1 : pixelX < 0 ? 0 : pixelX;
+ if (percentagePower > drawMaxBuffer[pixelX])
+ drawMaxBuffer[pixelX] = (float) percentagePower;
+ }
+ }
+
+ /**
+ * fill in pixels that do not have power with last bin's color in order
+ * to smooth the spectrum
+ */
+ Color lastValidColor = palette.getColor(0);
+ for (int x = 0; x < drawMaxBuffer.length; x++) {
+ Color color;
+ if (drawMaxBuffer[x] == minimumValueDrawBuffer)
+ color = lastValidColor;
+ else {
+ color = palette.getColorNormalized(drawMaxBuffer[x]);
+ lastValidColor = color;
+ }
+ rect.x = x;
+ g.setColor(color);
+ g.draw(rect);
+ }
+
+ renderingInfo = String.format("RBW %.1fkHz / FFT bins: %d%s / %.1ffps",
+ lastSpectrum == null ? 0 : lastSpectrum.getFFTBinSizeHz() / 1000d, size >= 10000 ? size / 1000 : size,
+ size >= 10000 ? "k" : "", fps.getEma());
+ fpsRenderedFrames++;
+ if (System.currentTimeMillis() - lastFPSRecalculated > 1000) {
+ double rawfps = fpsRenderedFrames / ((System.currentTimeMillis() - (double) lastFPSRecalculated) / 1000d);
+ fps.addNewValue(rawfps);
+ lastFPSRecalculated = System.currentTimeMillis();
+ fpsRenderedFrames = 0;
+ }
+ g.dispose();
+
+// double time = newDataTimeEMA.addNewValue(((System.nanoTime()-start)/1000));
+// System.out.println("draw "+(int)time+"us");
+
+// repaint();
+ }
+
+ /**
+ * Draws color palette into given area from bottom (0%) to top (100%)
+ *
+ * @param g
+ * @param x
+ * @param y
+ * @param w
+ * @param h
+ */
+ public void drawScale(Graphics2D g, int x, int y, int w, int h) {
+ g = (Graphics2D) g.create(x, y, w, h);
+ int step = 3;
+ for (int i = 0; i < h; i += step) {
+ Color c = palette.getColorNormalized(1 - (double) i / h);
+ g.setColor(c);
+ g.fillRect(0, i, w, step);
+ }
+
+ /**
+ * draw border around the scale
+ */
+ int thickness = 2;
+ g.setColor(Color.darkGray);
+ g.fillRect(0, 0, w, thickness);
+ g.fillRect(w - thickness, 0, thickness, h);
+ g.fillRect(0, h - thickness, w, thickness);
+ g.dispose();
+ }
+
+ public int getHistorySize() {
+ return bufferedImages[0].getHeight();
+ }
+
+ public double getSpectrumPaletteSize() {
+ return spectrumPaletteSize;
+ }
+
+ public double getSpectrumPaletteStart() {
+ return spectrumPaletteStart;
+ }
+
+ public void setDrawingOffsets(int xOffsetLeft, int width) {
+ this.chartXOffset = xOffsetLeft;
+ this.chartWidth = width;
+ }
+
+ public synchronized void setHistorySize(int historyInPixels) {
+ BufferedImage bufferedImages[] = new BufferedImage[2];
+ bufferedImages[0] = GraphicsToolkit.createAcceleratedImageOpaque(screenWidth, historyInPixels);
+ bufferedImages[1] = GraphicsToolkit.createAcceleratedImageOpaque(screenWidth, historyInPixels);
+ copyImage(this.bufferedImages[0], bufferedImages[0]);
+ copyImage(this.bufferedImages[1], bufferedImages[1]);
+ this.bufferedImages = bufferedImages;
+ }
+
+ public void setSpectrumPaletteSize(int dB) {
+ this.spectrumPaletteSize = dB;
+ }
+
+ /**
+ * Sets start and end of the color scale
+ *
+ * @param minFreqency
+ * @param maxFrequency
+ */
+ public void setSpectrumPaletteStart(int dB) {
+ this.spectrumPaletteStart = dB;
+ }
+
+ /**
+ * Sets status message to be drawn near bottom right corner
+ *
+ * @param message
+ * @param index
+ * max array length is 4
+ */
+ public void setStatusMessage(String message, int index) {
+ this.statusMessage[index] = message;
+ }
+
+ private void copyImage(BufferedImage src, BufferedImage dst) {
+ Graphics2D g = dst.createGraphics();
+ g.drawImage(src, 0, 0, null);
+ g.dispose();
+ }
+
+ private double translateChartXToFrequency(int x) {
+ if (lastSpectrum != null) {
+ double startFreq = lastSpectrum.getFreqStartMHz() * 1000000d;
+ double stopFreq = lastSpectrum.getFreqStopMHz() * 1000000d;
+ double freqRange = (stopFreq - startFreq);
+ double width = bufferedImages[0].getWidth();
+ double percentageFreq = x / (double) chartWidth;
+ double freq = percentageFreq * freqRange + startFreq;
+ if (freq > stopFreq)
+ freq = stopFreq;
+ if (freq < startFreq)
+ freq = startFreq;
+ return freq;
+ }
+ return -1;
+ }
+
+ Rectangle2D stringBounds;
+ @Override
+ protected void paintComponent(Graphics arg0) {
+ long drawStart = System.nanoTime();
+ Graphics2D g = (Graphics2D) arg0;
+ g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ int w = chartWidth;
+ int h = getHeight();
+ g.setColor(Color.black);
+ g.fillRect(0, 0, getWidth(), getHeight());
+
+ g.drawImage(bufferedImages[drawIndex], chartXOffset, 0, w, h, null);
+
+ if (displayMarker) {
+ g.setColor(Color.gray);
+ g.drawLine(displayMarkerX, 0, displayMarkerX, h);
+ g.drawString(String.format("%.1fMHz", displayMarkerFrequency / 1000000.0), displayMarkerX + 5, h / 2);
+ } //finish marker
+
+ g.setColor(Color.white);
+ if (stringBounds == null)
+ stringBounds = g.getFontMetrics().getStringBounds("TEST", g);
+ int fontHeight = (int) stringBounds.getHeight();
+ int x = chartXOffset + w - 350;
+ int y = h - fontHeight * (statusMessage.length + 1);
+ g.drawString(renderingInfo, x, y);
+
+ for (int i = 0; i < statusMessage.length; i++) {
+ if (statusMessage[i] != null)
+ g.drawString(statusMessage[i], x, y + fontHeight * (i + 1));
+ }
+
+ long drawingTime = System.nanoTime()-drawStart;
+ drawingTimeSum += drawingTime;
+ drawingCounter++;
+ }
+ private volatile long drawingTimeSum = 0;
+ private volatile int drawingCounter = 0;
+ public int getDrawingCounterAndReset() {
+ int val = drawingCounter;
+ drawingCounter = 0;
+ return val;
+ }
+ /**
+ * Retrieves time in nanos the component spent in drawing itself and resets
+ * the counter to zero.
+ * @return
+ */
+ public long getDrawTimeSumAndReset() {
+ long val = drawingTimeSum;
+ drawingTimeSum = 0;
+ return val;
+ }
+}
diff --git a/src/hackrf-sweep/src-java/resources/freq-europe.csv b/src/hackrf-sweep/src-java/resources/freq-europe.csv
new file mode 100644
index 0000000..f26f9a8
--- /dev/null
+++ b/src/hackrf-sweep/src-java/resources/freq-europe.csv
@@ -0,0 +1,374 @@
+"Country";"Frequency Range";"Allocations";"Applications"
+"- Europe (ECA) -";"526.500 - 1606.500 kHz";"Broadcasting";"Inductive applications/Broadcasting"
+"- Europe (ECA) -";"1606.500 - 1625.000 kHz";"Fixed/Land Mobile/Maritime Mobile/Radiolocation";"Radiodetermination applications/Inductive applications/Maritime communications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"1625.000 - 1635.000 kHz";"Radiolocation";"Radiolocation (military)/Inductive applications/Radiodetermination applications"
+"- Europe (ECA) -";"1635.000 - 1800.000 kHz";"Fixed/Land Mobile/Maritime Mobile";"Radiodetermination applications/Inductive applications/Maritime communications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"1800.000 - 1810.000 kHz";"Radiolocation";"Radiolocation (military)/Inductive applications/Radiodetermination applications"
+"- Europe (ECA) -";"1810.000 - 1850.000 kHz";"Amateur";"Inductive applications/Amateur"
+"- Europe (ECA) -";"1850.000 - 2000.000 kHz";"Fixed/Mobile except aeronautical mobile/Amateur";"Amateur/Maritime communications/Inductive applications/Radiodetermination applications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"2000.000 - 2025.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Land military systems/Maritime military systems/Radiodetermination applications/Inductive applications/Maritime communications"
+"- Europe (ECA) -";"2025.000 - 2045.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Maritime communications/Oceanographic buoys/Inductive applications/Radiodetermination applications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"2045.000 - 2160.000 kHz";"Fixed/Land Mobile/Maritime Mobile";"Land military systems/Maritime military systems/Inductive applications/Maritime communications"
+"- Europe (ECA) -";"2160.000 - 2170.000 kHz";"Radiolocation";"Inductive applications/Radiodetermination applications/Radiolocation (military)"
+"- Europe (ECA) -";"2170.000 - 2173.500 kHz";"Maritime Mobile";"Maritime military systems/Inductive applications/Maritime communications"
+"- Europe (ECA) -";"2173.500 - 2190.500 kHz";"Mobile (distress and calling)";"DSC/Inductive applications/Maritime communications"
+"- Europe (ECA) -";"2190.500 - 2194.000 kHz";"Maritime Mobile";"Inductive applications/Maritime communications/Maritime military systems"
+"- Europe (ECA) -";"2194.000 - 2300.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Land military systems/Maritime military systems/Maritime communications/Inductive applications/Radiodetermination applications"
+"- Europe (ECA) -";"2300.000 - 2498.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Inductive applications/Maritime communications/Maritime military systems/Land military systems"
+"- Europe (ECA) -";"2498.000 - 2501.000 kHz";"Standard frequency and time signal (2 500 kHz)";"Inductive applications"
+"- Europe (ECA) -";"2501.000 - 2502.000 kHz";"Space Research/Standard Frequency and Time Signal";"Inductive applications"
+"- Europe (ECA) -";"2502.000 - 2625.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Inductive applications/Radiodetermination applications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"2625.000 - 2650.000 kHz";"Maritime Mobile/Maritime Radionavigation";"Maritime military systems/Inductive applications/Maritime communications"
+"- Europe (ECA) -";"2650.000 - 2850.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Inductive applications/Radiodetermination applications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"2850.000 - 3025.000 kHz";"Aeronautical Mobile-Satellite (R)";"Aeronautical military systems/SAR (communications)/Inductive applications/Aeronautical communications"
+"- Europe (ECA) -";"3025.000 - 3155.000 kHz";"Aeronautical Mobile (OR)";"Aeronautical communications/Inductive applications/Aeronautical military systems"
+"- Europe (ECA) -";"3155.000 - 3200.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Land military systems/Maritime military systems/Inductive applications/Maritime communications"
+"- Europe (ECA) -";"3200.000 - 3230.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Inductive applications/Maritime communications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"3230.000 - 3400.000 kHz";"Fixed/Mobile except aeronautical mobile";"Land military systems/Maritime military systems/Inductive applications/Maritime communications"
+"- Europe (ECA) -";"3400.000 - 3500.000 kHz";"Aeronautical Mobile (R)";"Aeronautical communications/Inductive applications/Aeronautical military systems"
+"- Europe (ECA) -";"3500.000 - 3800.000 kHz";"Amateur/Fixed/Mobile except aeronautical mobile";"Land military systems/Maritime military systems/Inductive applications/Amateur/Maritime communications"
+"- Europe (ECA) -";"3800.000 - 3900.000 kHz";"Aeronautical Mobile (OR)/Fixed/Land Mobile";"Aeronautical communications/Inductive applications/Aeronautical military systems/Land military systems"
+"- Europe (ECA) -";"3900.000 - 3950.000 kHz";"Aeronautical Mobile (OR)";"Aeronautical military systems/Inductive applications/Aeronautical communications"
+"- Europe (ECA) -";"3950.000 - 4000.000 kHz";"Broadcasting/Fixed";"Inductive applications/Broadcasting/Land military systems"
+"- Europe (ECA) -";"4000.000 - 4063.000 kHz";"Fixed/Maritime Mobile";"Land military systems/Maritime military systems/Inductive applications/Maritime communications"
+"- Europe (ECA) -";"4063.000 - 4438.000 kHz";"Maritime Mobile";"DSC/Maritime communications/Inductive applications/Railway applications/NAVTEX/Maritime military systems"
+"- Europe (ECA) -";"4438.000 - 4488.000 kHz";"Fixed/Mobile except aeronautical mobile (R)/Radiolocation";"Land military systems/Maritime military systems/Radiolocation (military)/Inductive applications"
+"- Europe (ECA) -";"4488.000 - 4650.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Inductive applications/Maritime military systems/Land military systems"
+"- Europe (ECA) -";"4650.000 - 4700.000 kHz";"Aeronautical Mobile (R)";"Aeronautical military systems/Inductive applications/Aeronautical communications"
+"- Europe (ECA) -";"4700.000 - 4750.000 kHz";"Aeronautical Mobile (OR)";"Aeronautical communications/Inductive applications/Aeronautical military systems"
+"- Europe (ECA) -";"4750.000 - 4850.000 kHz";"Aeronautical Mobile (OR)/Fixed/Land Mobile";"Aeronautical military systems/Land military systems/Inductive applications/Aeronautical communications"
+"- Europe (ECA) -";"4850.000 - 4995.000 kHz";"Fixed/Land Mobile";"Inductive applications/Land military systems"
+"- Europe (ECA) -";"4995.000 - 5003.000 kHz";"Standard frequency and time signal (5 000 kHz)";"Inductive applications"
+"- Europe (ECA) -";"5003.000 - 5005.000 kHz";"Standard Frequency and Time Signal/Space Research";"Inductive applications"
+"- Europe (ECA) -";"5005.000 - 5060.000 kHz";"Fixed";"Inductive applications/Land military systems"
+"- Europe (ECA) -";"5060.000 - 5250.000 kHz";"Fixed/Mobile except aeronautical mobile";"Land military systems/Maritime military systems/Inductive applications"
+"- Europe (ECA) -";"5250.000 - 5275.000 kHz";"Fixed/Mobile except aeronautical mobile/Radiolocation";"Inductive applications/Land military systems/Maritime military systems/Radiolocation (military)"
+"- Europe (ECA) -";"5275.000 - 5351.500 kHz";"Fixed/Mobile except aeronautical mobile";"Inductive applications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"5351.500 - 5366.500 kHz";"Fixed/Mobile except aeronautical mobile/Amateur";"Amateur/Inductive applications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"5366.500 - 5450.000 kHz";"Fixed/Mobile except aeronautical mobile";"Inductive applications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"5450.000 - 5480.000 kHz";"Aeronautical Mobile (OR)/Fixed/Land Mobile";"Aeronautical military systems/Land military systems/Inductive applications/Aeronautical communications"
+"- Europe (ECA) -";"5480.000 - 5680.000 kHz";"Aeronautical Mobile-Satellite (R)";"Aeronautical communications/Inductive applications/SAR (communications)/Aeronautical military systems"
+"- Europe (ECA) -";"5680.000 - 5730.000 kHz";"Aeronautical Mobile (OR)";"Aeronautical military systems/SAR (communications)/Inductive applications/Aeronautical communications"
+"- Europe (ECA) -";"5730.000 - 5900.000 kHz";"Fixed/Land Mobile";"Inductive applications/Land military systems"
+"- Europe (ECA) -";"5900.000 - 5950.000 kHz";"Broadcasting";"Inductive applications/Broadcasting"
+"- Europe (ECA) -";"5950.000 - 6200.000 kHz";"Broadcasting";"Broadcasting/Inductive applications"
+"- Europe (ECA) -";"6200.000 - 6525.000 kHz";"Maritime Mobile";"Inductive applications/DSC/Maritime communications/Maritime military systems"
+"- Europe (ECA) -";"6525.000 - 6685.000 kHz";"Aeronautical Mobile (R)";"Aeronautical military systems/Aeronautical communications/Inductive applications"
+"- Europe (ECA) -";"6685.000 - 6765.000 kHz";"Aeronautical Mobile (OR)";"Inductive applications/Aeronautical communications/Aeronautical military systems"
+"- Europe (ECA) -";"6765.000 - 7000.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Maritime military systems/Land military systems/Inductive applications/ISM"
+"- Europe (ECA) -";"7000.000 - 7100.000 kHz";"Amateur/Amateur-Satellite";"Amateur/Inductive applications"
+"- Europe (ECA) -";"7100.000 - 7200.000 kHz";"Amateur";"Inductive applications/Amateur"
+"- Europe (ECA) -";"7200.000 - 7300.000 kHz";"Broadcasting";"Inductive applications/Broadcasting"
+"- Europe (ECA) -";"7300.000 - 7400.000 kHz";"Broadcasting";"Broadcasting/Inductive applications"
+"- Europe (ECA) -";"7400.000 - 7450.000 kHz";"Broadcasting";"Broadcasting/Inductive applications"
+"- Europe (ECA) -";"7450.000 - 8100.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Inductive applications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"8100.000 - 8195.000 kHz";"Fixed/Maritime Mobile";"Land military systems/Maritime military systems/Inductive applications/Maritime communications"
+"- Europe (ECA) -";"8195.000 - 8815.000 kHz";"Maritime Mobile";"DSC/Inductive applications/Maritime communications/Maritime military systems"
+"- Europe (ECA) -";"8815.000 - 8965.000 kHz";"Aeronautical Mobile (R)";"Aeronautical military systems/Aeronautical communications/Inductive applications"
+"- Europe (ECA) -";"8965.000 - 9040.000 kHz";"Aeronautical Mobile (OR)";"Inductive applications/Aeronautical communications/Aeronautical military systems"
+"- Europe (ECA) -";"9040.000 - 9305.000 kHz";"Fixed";"Land military systems/Inductive applications"
+"- Europe (ECA) -";"9305.000 - 9355.000 kHz";"Fixed/Radiolocation";"Inductive applications/Land military systems"
+"- Europe (ECA) -";"9355.000 - 9400.000 kHz";"Fixed";"Land military systems/Inductive applications"
+"- Europe (ECA) -";"9400.000 - 9500.000 kHz";"Broadcasting";"Broadcasting/Inductive applications"
+"- Europe (ECA) -";"9500.000 - 9900.000 kHz";"Broadcasting";"Inductive applications/Broadcasting"
+"- Europe (ECA) -";"9900.000 - 9995.000 kHz";"Fixed";"Inductive applications/Land military systems"
+"- Europe (ECA) -";"9995.000 - 10003.000 kHz";"Standard frequency and time signal (10 000 kHz)";"Inductive applications"
+"- Europe (ECA) -";"10003.000 - 10005.000 kHz";"Standard Frequency and Time Signal/Space Research";"Inductive applications/SAR (communications)"
+"- Europe (ECA) -";"10005.000 - 10100.000 kHz";"Aeronautical Mobile (R)";"Aeronautical communications/Inductive applications/Aeronautical military systems"
+"- Europe (ECA) -";"10100.000 - 10150.000 kHz";"Fixed/Amateur";"Land military systems/Inductive applications/Amateur"
+"- Europe (ECA) -";"10150.000 - 11175.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Inductive applications/Railway applications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"11175.000 - 11275.000 kHz";"Aeronautical Mobile (OR)";"Aeronautical military systems/Inductive applications/Railway applications/Aeronautical communications"
+"- Europe (ECA) -";"11275.000 - 11400.000 kHz";"Aeronautical Mobile (R)";"Aeronautical communications/Railway applications/Inductive applications/Aeronautical military systems"
+"- Europe (ECA) -";"11400.000 - 11600.000 kHz";"Fixed";"Land military systems/Inductive applications/Railway applications"
+"- Europe (ECA) -";"11600.000 - 11650.000 kHz";"Broadcasting";"Railway applications/Inductive applications/Broadcasting"
+"- Europe (ECA) -";"11650.000 - 12050.000 kHz";"Broadcasting";"Broadcasting/Inductive applications/Railway applications"
+"- Europe (ECA) -";"12050.000 - 12100.000 kHz";"Broadcasting";"Railway applications/Inductive applications/Broadcasting"
+"- Europe (ECA) -";"12100.000 - 12230.000 kHz";"Fixed";"Inductive applications/Railway applications/Land military systems"
+"- Europe (ECA) -";"12230.000 - 13200.000 kHz";"Maritime Mobile";"Maritime military systems/Railway applications/Inductive applications/DSC/Maritime communications"
+"- Europe (ECA) -";"13200.000 - 13260.000 kHz";"Aeronautical Mobile (OR)";"Aeronautical communications/Inductive applications/Railway applications/Aeronautical military systems"
+"- Europe (ECA) -";"13260.000 - 13360.000 kHz";"Aeronautical Mobile (R)";"Aeronautical military systems/Railway applications/Inductive applications/Aeronautical communications"
+"- Europe (ECA) -";"13360.000 - 13410.000 kHz";"Fixed/Radio Astronomy";"Radio astronomy/Inductive applications/Railway applications/Land military systems"
+"- Europe (ECA) -";"13410.000 - 13450.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Maritime military systems/Land military systems/Railway applications/Inductive applications"
+"- Europe (ECA) -";"13450.000 - 13550.000 kHz";"Mobile except aeronautical mobile (R)/Fixed/Radiolocation";"Inductive applications/Railway applications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"13550.000 - 13570.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Maritime military systems/Land military systems/Railway applications/Non-specific SRDs/ISM/Inductive applications"
+"- Europe (ECA) -";"13570.000 - 13600.000 kHz";"Broadcasting";"Broadcasting/Railway applications/Inductive applications"
+"- Europe (ECA) -";"13600.000 - 13800.000 kHz";"Broadcasting";"Inductive applications/Railway applications/Broadcasting"
+"- Europe (ECA) -";"13800.000 - 13870.000 kHz";"Broadcasting";"Broadcasting/Railway applications/Inductive applications"
+"- Europe (ECA) -";"13870.000 - 14000.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Inductive applications/Railway applications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"14000.000 - 14250.000 kHz";"Amateur/Amateur-Satellite";"Railway applications/Inductive applications/Amateur/Amateur-satellite"
+"- Europe (ECA) -";"14250.000 - 14350.000 kHz";"Amateur";"Amateur/Inductive applications/Railway applications"
+"- Europe (ECA) -";"14350.000 - 14990.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Railway applications/Inductive applications/Maritime military systems/Land military systems"
+"- Europe (ECA) -";"14990.000 - 15005.000 kHz";"Standard frequency and time signal (15 000 kHz)";"Inductive applications/Railway applications/SAR (communications)"
+"- Europe (ECA) -";"15005.000 - 15010.000 kHz";"Standard Frequency and Time Signal/Space Research";"Railway applications/Inductive applications"
+"- Europe (ECA) -";"15010.000 - 15100.000 kHz";"Aeronautical Mobile (OR)";"Inductive applications/Railway applications/Aeronautical communications/Aeronautical military systems"
+"- Europe (ECA) -";"15100.000 - 15600.000 kHz";"Broadcasting";"Railway applications/Inductive applications/Broadcasting"
+"- Europe (ECA) -";"15600.000 - 15800.000 kHz";"Broadcasting";"Broadcasting/Inductive applications/Railway applications"
+"- Europe (ECA) -";"15800.000 - 16100.000 kHz";"Fixed";"Railway applications/Inductive applications/Land military systems"
+"- Europe (ECA) -";"16100.000 - 16200.000 kHz";"Fixed/Radiolocation";"Land military systems/Inductive applications"
+"- Europe (ECA) -";"16200.000 - 16360.000 kHz";"Fixed";"Inductive applications/Land military systems"
+"- Europe (ECA) -";"16360.000 - 17410.000 kHz";"Maritime Mobile";"Maritime military systems/Inductive applications/DSC/Maritime communications"
+"- Europe (ECA) -";"17410.000 - 17480.000 kHz";"Fixed";"Inductive applications/Land military systems"
+"- Europe (ECA) -";"17480.000 - 17550.000 kHz";"Broadcasting";"Inductive applications/Broadcasting"
+"- Europe (ECA) -";"17550.000 - 17900.000 kHz";"Broadcasting";"Broadcasting/Inductive applications"
+"- Europe (ECA) -";"17900.000 - 17970.000 kHz";"Aeronautical Mobile (R)";"Inductive applications/Aeronautical communications/Aeronautical military systems"
+"- Europe (ECA) -";"17970.000 - 18030.000 kHz";"Aeronautical Mobile (OR)";"Aeronautical military systems/Aeronautical communications/Inductive applications"
+"- Europe (ECA) -";"18030.000 - 18052.000 kHz";"Fixed";"Inductive applications/Land military systems"
+"- Europe (ECA) -";"18052.000 - 18068.000 kHz";"Fixed/Space Research";"Land military systems/Inductive applications"
+"- Europe (ECA) -";"18068.000 - 18168.000 kHz";"Amateur/Amateur-Satellite";"Inductive applications/Amateur/Amateur-satellite"
+"- Europe (ECA) -";"18168.000 - 18780.000 kHz";"Fixed/Mobile except aeronautical mobile";"DSC/Inductive applications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"18780.000 - 18900.000 kHz";"Maritime Mobile";"Maritime military systems/Inductive applications/Maritime communications"
+"- Europe (ECA) -";"18900.000 - 19020.000 kHz";"Broadcasting";"Inductive applications/Broadcasting"
+"- Europe (ECA) -";"19020.000 - 19680.000 kHz";"Fixed";"Inductive applications/Land military systems"
+"- Europe (ECA) -";"19680.000 - 19800.000 kHz";"Maritime Mobile";"Maritime military systems/Inductive applications/DSC/Maritime communications"
+"- Europe (ECA) -";"19800.000 - 19990.000 kHz";"Fixed";"Inductive applications/Land military systems"
+"- Europe (ECA) -";"19990.000 - 19995.000 kHz";"Standard Frequency and Time Signal/Space Research";"Inductive applications/SAR (communications)"
+"- Europe (ECA) -";"19995.000 - 20010.000 kHz";"Standard frequency and time signal (20 000 kHz)";"Inductive applications"
+"- Europe (ECA) -";"20010.000 - 21000.000 kHz";"Fixed/Mobile";"Inductive applications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"21000.000 - 21450.000 kHz";"Amateur/Amateur-Satellite";"Inductive applications/Amateur/Amateur-satellite"
+"- Europe (ECA) -";"21450.000 - 21850.000 kHz";"Broadcasting";"Inductive applications/Broadcasting"
+"- Europe (ECA) -";"21850.000 - 21870.000 kHz";"Fixed";"Inductive applications/Land military systems"
+"- Europe (ECA) -";"21870.000 - 21924.000 kHz";"Fixed";"Land military systems/Inductive applications"
+"- Europe (ECA) -";"21924.000 - 22000.000 kHz";"Aeronautical Mobile (R)";"Inductive applications/Aeronautical communications/Aeronautical military systems"
+"- Europe (ECA) -";"22000.000 - 22855.000 kHz";"Maritime Mobile";"Maritime military systems/DSC/Maritime communications/Inductive applications"
+"- Europe (ECA) -";"22855.000 - 23000.000 kHz";"Fixed";"Inductive applications/Land military systems"
+"- Europe (ECA) -";"23000.000 - 23200.000 kHz";"Fixed/Mobile except aeronautical mobile (R)";"Land military systems/Maritime military systems/Inductive applications"
+"- Europe (ECA) -";"23200.000 - 23350.000 kHz";"Aeronautical Mobile (OR)/Fixed";"Inductive applications/Aeronautical communications/Aeronautical military systems/Land military systems"
+"- Europe (ECA) -";"23350.000 - 24000.000 kHz";"Fixed/Mobile except aeronautical mobile";"Maritime military systems/Land military systems/Inductive applications"
+"- Europe (ECA) -";"24000.000 - 24450.000 kHz";"Fixed/Land Mobile";"Inductive applications/Land military systems"
+"- Europe (ECA) -";"24450.000 - 24600.000 kHz";"Fixed/Land Mobile/Radiolocation";"Land military systems/Inductive applications"
+"- Europe (ECA) -";"24600.000 - 24890.000 kHz";"Fixed/Land Mobile";"Inductive applications/Land military systems"
+"- Europe (ECA) -";"24890.000 - 24990.000 kHz";"Amateur/Amateur-Satellite";"Inductive applications/Amateur/Amateur-satellite"
+"- Europe (ECA) -";"24990.000 - 25005.000 kHz";"Standard frequency and time signal (25 000 kHz)";"Inductive applications"
+"- Europe (ECA) -";"25005.000 - 25010.000 kHz";"Standard Frequency and Time Signal/Space Research";"Inductive applications/Space research"
+"- Europe (ECA) -";"25010.000 - 25070.000 kHz";"Fixed/Mobile except aeronautical mobile";"Inductive applications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"25070.000 - 25210.000 kHz";"Maritime Mobile";"Maritime military systems/Inductive applications/DSC/Maritime communications"
+"- Europe (ECA) -";"25210.000 - 25550.000 kHz";"Fixed/Mobile except aeronautical mobile";"Inductive applications/Maritime military systems/Land military systems"
+"- Europe (ECA) -";"25550.000 - 25670.000 kHz";"Radio Astronomy";"Inductive applications/Radio astronomy"
+"- Europe (ECA) -";"25670.000 - 26100.000 kHz";"Broadcasting";"Inductive applications/Broadcasting"
+"- Europe (ECA) -";"26100.000 - 26175.000 kHz";"Maritime Mobile";"Inductive applications/DSC/Maritime communications/Maritime military systems"
+"- Europe (ECA) -";"26175.000 - 26200.000 kHz";"Fixed/Mobile except aeronautical mobile";"Maritime military systems/Land military systems/Inductive applications"
+"- Europe (ECA) -";"26200.000 - 26350.000 kHz";"Fixed/Mobile except aeronautical mobile/Radiolocation";"Inductive applications/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"26350.000 - 27500.000 kHz";"Fixed/Mobile except aeronautical mobile";"Maritime military systems/Land military systems/Model control/Non-specific SRDs/ISM/CB radio/Inductive applications/Railway applications"
+"- Europe (ECA) -";"27500.000 - 28000.000 kHz";"Fixed/Meteorological Aids/Mobile";"Inductive applications/Aeronautical military systems/Land military systems/Maritime military systems"
+"- Europe (ECA) -";" 28.000 - 29.700 MHz";"Amateur/Amateur-Satellite";"Inductive applications/Amateur/Amateur-satellite"
+"- Europe (ECA) -";" 29.700 - 30.005 MHz";"Mobile";"Radio microphones and ALD/Inductive applications/Active medical implants/Aeronautical military systems/Maritime military systems/Land military systems"
+"- Europe (ECA) -";" 30.005 - 30.010 MHz";"Mobile";"Land military systems/Aeronautical military systems/Maritime military systems/Satellite systems (military)/Active medical implants/Radio microphones and ALD"
+"- Europe (ECA) -";" 30.010 - 37.500 MHz";"Mobile";"Model control/PMR/Radio microphones and ALD/Active medical implants/Aeronautical military systems/Maritime military systems/Land military systems"
+"- Europe (ECA) -";" 37.500 - 38.250 MHz";"Mobile/Radio Astronomy";"Aeronautical military systems/Maritime military systems/Land military systems/PMR/Radio astronomy/Radio microphones and ALD"
+"- Europe (ECA) -";" 38.250 - 39.000 MHz";"Mobile";"PMR/Radio microphones and ALD/Land military systems/Aeronautical military systems/Maritime military systems"
+"- Europe (ECA) -";" 39.000 - 39.500 MHz";"Mobile/Radiolocation";"Aeronautical military systems/Maritime military systems/Land military systems/Meteor scatter communications/PMR/Radio microphones and ALD"
+"- Europe (ECA) -";" 39.500 - 39.986 MHz";"Mobile";"Radio microphones and ALD/PMR/Meteor scatter communications/Land military systems/Aeronautical military systems/Maritime military systems"
+"- Europe (ECA) -";" 39.986 - 40.020 MHz";"Mobile/Space Research";"Aeronautical military systems/Maritime military systems/Land military systems/PMR/Radio microphones and ALD"
+"- Europe (ECA) -";" 40.020 - 40.660 MHz";"Mobile";"PMR/Radio microphones and ALD/Maritime military systems/Land military systems/Aeronautical military systems"
+"- Europe (ECA) -";" 40.660 - 40.700 MHz";"Mobile";"Land military systems/Aeronautical military systems/Maritime military systems/ISM/Model control/Non-specific SRDs/Radio microphones and ALD"
+"- Europe (ECA) -";" 40.700 - 40.980 MHz";"Mobile";"PMR/Radio microphones and ALD/Aeronautical military systems/Maritime military systems/Land military systems"
+"- Europe (ECA) -";" 40.980 - 41.015 MHz";"Mobile/Space Research";"Land military systems/Aeronautical military systems/Maritime military systems/PMR/Radio microphones and ALD"
+"- Europe (ECA) -";" 41.015 - 42.000 MHz";"Mobile";"PMR/Radio microphones and ALD/Aeronautical military systems/Maritime military systems/Land military systems"
+"- Europe (ECA) -";" 42.000 - 42.500 MHz";"Mobile/Fixed/Radiolocation";"Aeronautical military systems/Maritime military systems/Land military systems/PMR/Radio microphones and ALD"
+"- Europe (ECA) -";" 42.500 - 44.000 MHz";"Mobile";"Radio microphones and ALD/PMR/Aeronautical military systems/Maritime military systems/Land military systems"
+"- Europe (ECA) -";" 44.000 - 47.000 MHz";"Mobile";"Land military systems/Aeronautical military systems/Maritime military systems/PMR/Radio microphones and ALD/Wind profilers"
+"- Europe (ECA) -";" 47.000 - 50.000 MHz";"Land Mobile";"On-site paging/PMR/Wind profilers/Earth exploration-satellite/Land military systems"
+"- Europe (ECA) -";" 50.000 - 52.000 MHz";"Land Mobile/Amateur";"Land military systems/Amateur/PMR/Wind profilers"
+"- Europe (ECA) -";" 52.000 - 68.000 MHz";"Land Mobile";"PMR/Wind profilers/Land military systems"
+"- Europe (ECA) -";" 68.000 - 70.450 MHz";"Mobile/Amateur";"Amateur/Land military systems/Maritime military systems/PMR/PAMR"
+"- Europe (ECA) -";" 70.450 - 74.800 MHz";"Amateur/Mobile except aeronautical mobile/Radio Astronomy";"PMR/PAMR/Radio astronomy/Maritime military systems/Land military systems/Amateur"
+"- Europe (ECA) -";" 74.800 - 75.200 MHz";"Aeronautical Radionavigation";"ILS"
+"- Europe (ECA) -";" 75.200 - 87.500 MHz";"Mobile";"PMR/PAMR/Land military systems/Maritime military systems"
+"- Europe (ECA) -";" 87.500 - 100.000 MHz";"Broadcasting";"FM sound analogue/Wireless audio/multimedia"
+"- Europe (ECA) -";"100.000 - 108.000 MHz";"Broadcasting";"FM sound analogue/Wireless audio/multimedia"
+"- Europe (ECA) -";"108.000 - 117.975 MHz";"Aeronautical Radionavigation/Aeronautical Mobile (R)";"Aeronautical communications/ILS/VOR/GBAS"
+"- Europe (ECA) -";"117.975 - 121.450 MHz";"Aeronautical Mobile-Satellite (R)";"Aeronautical communications"
+"- Europe (ECA) -";"121.450 - 121.550 MHz";"Aeronautical Mobile (R)";"EPIRBs/-"
+"- Europe (ECA) -";"121.550 - 136.000 MHz";"Aeronautical Mobile (R)";"Aeronautical communications"
+"- Europe (ECA) -";"136.000 - 137.000 MHz";"Aeronautical Mobile (R)";"Aeronautical communications"
+"- Europe (ECA) -";"137.000 - 137.025 MHz";"Meteorological-Satellite (space-to-Earth)/Mobile/Mobile-Satellite (space-to-Earth)/Space Operation (space-to-Earth)/Space Research (space-to-Earth)";"S-PCS/Weather satellites/Land mobile/Land military systems/Satellite systems (military)/Aeronautical military systems"
+"- Europe (ECA) -";"137.025 - 137.175 MHz";"Meteorological-Satellite (space-to-Earth)/Mobile/Mobile-Satellite (space-to-Earth)/Space Operation (space-to-Earth)/Space Research (space-to-Earth)";"Land military systems/Satellite systems (military)/Aeronautical military systems/S-PCS/Weather satellites/Land mobile"
+"- Europe (ECA) -";"137.175 - 137.825 MHz";"Meteorological-Satellite (space-to-Earth)/Mobile/Mobile-Satellite (space-to-Earth)/Space Operation (space-to-Earth)/Space Research (space-to-Earth)";"S-PCS/Weather satellites/Land mobile/Land military systems/Satellite systems (military)/Aeronautical military systems"
+"- Europe (ECA) -";"137.825 - 138.000 MHz";"Meteorological-Satellite (space-to-Earth)/Mobile/Mobile-Satellite (space-to-Earth)/Space Operation (space-to-Earth)/Space Research (space-to-Earth)";"Land military systems/Satellite systems (military)/Aeronautical military systems/S-PCS/Weather satellites/Land mobile"
+"- Europe (ECA) -";"138.000 - 143.600 MHz";"Aeronautical Mobile (OR)/Land Mobile/Space Research (space-to-Earth)";"Land mobile/Non-specific SRDs/Land military systems/Aeronautical military systems/Maritime military systems"
+"- Europe (ECA) -";"143.600 - 143.650 MHz";"Aeronautical Mobile (OR)/Land Mobile/Space Research (space-to-Earth)";"Land military systems/Aeronautical military systems/Maritime military systems/Land mobile"
+"- Europe (ECA) -";"143.650 - 144.000 MHz";"Aeronautical Mobile (OR)/Land Mobile";"Land mobile/Land military systems/Aeronautical military systems/Maritime military systems"
+"- Europe (ECA) -";"144.000 - 146.000 MHz";"Amateur/Amateur-Satellite";"Amateur/Amateur-satellite"
+"- Europe (ECA) -";"146.000 - 148.000 MHz";"Mobile";"PMR/PAMR"
+"- Europe (ECA) -";"148.000 - 149.900 MHz";"Mobile/Mobile-Satellite (Earth-to-space)";"S-PCS/PMR/PAMR"
+"- Europe (ECA) -";"149.900 - 150.050 MHz";"Mobile/Mobile-Satellite (Earth-to-space)";"S-PCS/PMR/PAMR"
+"- Europe (ECA) -";"150.050 - 153.000 MHz";"Mobile except aeronautical mobile/Radio Astronomy";"PMR/PAMR/Radio astronomy"
+"- Europe (ECA) -";"153.000 - 154.000 MHz";"Mobile except aeronautical mobile (R)";"PMR/PAMR"
+"- Europe (ECA) -";"154.0000 - 156.4875 MHz";"Mobile except aeronautical mobile (R)";"PMR/PAMR/Maritime communications"
+"- Europe (ECA) -";"156.4875 - 156.5125 MHz";"Maritime Mobile (distress and calling via DSC)";"Maritime communications"
+"- Europe (ECA) -";"156.5125 - 156.5375 MHz";"Maritime Mobile (distress and calling via DSC)";"DSC"
+"- Europe (ECA) -";"156.5375 - 156.5625 MHz";"Maritime Mobile (distress and calling via DSC)/Mobile except aeronautical mobile (R)";"Maritime communications"
+"- Europe (ECA) -";"156.5625 - 156.7625 MHz";"Mobile except aeronautical mobile (R)";"Maritime communications"
+"- Europe (ECA) -";"156.7625 - 156.7875 MHz";"Maritime Mobile (distress and calling)";"Maritime communications"
+"- Europe (ECA) -";"156.7875 - 156.8125 MHz";"Maritime Mobile (distress and calling)";"Maritime communications"
+"- Europe (ECA) -";"156.8125 - 156.8375 MHz";"Maritime Mobile";"Maritime communications"
+"- Europe (ECA) -";"156.8375 - 161.9375 MHz";"Mobile except aeronautical mobile";"Maritime communications/PMR/PAMR"
+"- Europe (ECA) -";"161.9375 - 161.9625 MHz";"Mobile except aeronautical mobile/Maritime Mobile-Satellite (Earth-to-space)";"Maritime communications/PMR/PAMR"
+"- Europe (ECA) -";"161.9625 - 161.9875 MHz";"";"Maritime communications/AIS"
+"- Europe (ECA) -";"161.9875 - 162.0125 MHz";"Mobile except aeronautical mobile/Maritime Mobile-Satellite (Earth-to-space)";"Maritime communications"
+"- Europe (ECA) -";"162.0125 - 162.0375 MHz";"Mobile except aeronautical mobile";"Maritime communications/AIS"
+"- Europe (ECA) -";"162.0375 - 169.4000 MHz";"Mobile except aeronautical mobile";"PMR/PAMR"
+"- Europe (ECA) -";"169.4000 - 169.8125 MHz";"Mobile except aeronautical mobile";"Aids for hearing impaired/Meter reading/Non-specific SRDs"
+"- Europe (ECA) -";"169.8125 - 174.0000 MHz";"Mobile except aeronautical mobile";"Radio microphones and ALD/PMR/PAMR/Aids for hearing impaired"
+"- Europe (ECA) -";"174.000 - 223.000 MHz";"Broadcasting/Land Mobile";"PMSE/Radio microphones and ALD/Broadcasting (terrestrial)"
+"- Europe (ECA) -";"223.000 - 225.000 MHz";"Broadcasting";"Broadcasting (terrestrial)"
+"- Europe (ECA) -";"225.000 - 230.000 MHz";"Broadcasting/Land Mobile";"Broadcasting (terrestrial)/Defence systems"
+"- Europe (ECA) -";"230.000 - 235.000 MHz";"Mobile";"Defence systems/T-DAB"
+"- Europe (ECA) -";"235.000 - 240.000 MHz";"Mobile";"Defence systems/T-DAB"
+"- Europe (ECA) -";"240.000 - 242.950 MHz";"Mobile";"Defence systems"
+"- Europe (ECA) -";"242.950 - 243.050 MHz";"Aeronautical Mobile";"EPIRBs"
+"- Europe (ECA) -";"243.050 - 267.000 MHz";"Mobile";"Defence systems"
+"- Europe (ECA) -";"267.000 - 272.000 MHz";"Mobile";"Defence systems"
+"- Europe (ECA) -";"272.000 - 273.000 MHz";"Mobile";"Defence systems"
+"- Europe (ECA) -";"273.000 - 312.000 MHz";"Mobile";"Defence systems"
+"- Europe (ECA) -";"312.000 - 315.000 MHz";"Mobile";"Defence systems"
+"- Europe (ECA) -";"315.000 - 322.000 MHz";"Mobile";"Defence systems"
+"- Europe (ECA) -";"322.000 - 328.600 MHz";"Mobile/Radio Astronomy";"Defence systems/Radio astronomy"
+"- Europe (ECA) -";"328.600 - 335.400 MHz";"Aeronautical Radionavigation";"ILS"
+"- Europe (ECA) -";"380.000 - 385.000 MHz";"Mobile";"Defence systems/PPDR"
+"- Europe (ECA) -";"385.000 - 387.000 MHz";"Mobile";"Defence systems/PMR/PAMR"
+"- Europe (ECA) -";"387.000 - 390.000 MHz";"Mobile";"Defence systems/PMR/PAMR"
+"- Europe (ECA) -";"390.000 - 395.000 MHz";"Mobile";"Defence systems/PPDR"
+"- Europe (ECA) -";"395.000 - 399.900 MHz";"Mobile";"Defence systems/PMR/PAMR"
+"- Europe (ECA) -";"399.900 - 400.050 MHz";"Mobile-Satellite (Earth-to-space)";"PPDR"
+"- Europe (ECA) -";"400.050 - 400.150 MHz";"Standard frequency and time signal-satellite (400.1 MHz)";"PPDR"
+"- Europe (ECA) -";"400.150 - 401.000 MHz";"Meteorological Aids/Meteorological-Satellite (space-to-Earth)/Mobile-Satellite (space-to-Earth)/Space Research (space-to-Earth)/Space Operation (space-to-Earth)";"PPDR/Sondes/Weather satellites/S-PCS"
+"- Europe (ECA) -";"401.000 - 402.000 MHz";"Earth Exploration-Satellite (Earth-to-space)/Meteorological Aids/Meteorological-Satellite (Earth-to-space)";"Sondes/Weather satellites/Active medical implants"
+"- Europe (ECA) -";"402.000 - 403.000 MHz";"Earth Exploration-Satellite (Earth-to-space)/Meteorological Aids/Meteorological-Satellite (Earth-to-space)";"Sondes/Active medical implants/Weather satellites"
+"- Europe (ECA) -";"403.000 - 406.000 MHz";"Meteorological Aids";"Sondes/Active medical implants"
+"- Europe (ECA) -";"406.000 - 406.100 MHz";"Mobile-Satellite (Earth-to-space)";"EPIRBs"
+"- Europe (ECA) -";"406.100 - 410.000 MHz";"Land Mobile/Radio Astronomy";"PMR/PAMR/Radio astronomy/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"410.000 - 420.000 MHz";"Mobile except aeronautical mobile";"Land military systems/Maritime military systems/PMR/PAMR"
+"- Europe (ECA) -";"420.000 - 430.000 MHz";"Mobile except aeronautical mobile/Radiolocation";"PMR/PAMR/Land military systems/Maritime military systems/Radiolocation (military)"
+"- Europe (ECA) -";"430.000 - 432.000 MHz";"Amateur/Radiolocation";"Radiolocation (military)/ULP-WMCE/Amateur"
+"- Europe (ECA) -";"432.000 - 433.050 MHz";"Amateur/Radiolocation/Earth Exploration-Satellite (active)";"Active sensors (satellite)/Amateur/ULP-WMCE/Radiolocation (military)"
+"- Europe (ECA) -";"433.050 - 434.790 MHz";"Amateur/Radiolocation/Land Mobile/Earth Exploration-Satellite (active)";"Radiolocation (military)/ULP-WMCE/Amateur/ISM/Non-specific SRDs/Active sensors (satellite)"
+"- Europe (ECA) -";"434.790 - 438.000 MHz";"Amateur/Amateur-Satellite/Radiolocation/Earth Exploration-Satellite (active)";"Amateur/Amateur-satellite/Active sensors (satellite)/ULP-WMCE/Radiolocation (military)"
+"- Europe (ECA) -";"438.000 - 440.000 MHz";"Amateur/Radiolocation";"Radiolocation (military)/ULP-WMCE/Amateur"
+"- Europe (ECA) -";"440.000 - 450.000 MHz";"Mobile except aeronautical mobile/Radiolocation";"Wind profilers/On-site paging/PMR 446/PMR/PAMR/Land military systems/Maritime military systems/Radiolocation (military)"
+"- Europe (ECA) -";"450.000 - 455.000 MHz";"Mobile";"On-site paging/PMR/PAMR"
+"- Europe (ECA) -";"455.000 - 456.000 MHz";"Mobile";"Land mobile/On-site paging/PMR/PAMR"
+"- Europe (ECA) -";"456.000 - 459.000 MHz";"Mobile";"Land mobile/On-board communications/PMR/PAMR/On-site paging"
+"- Europe (ECA) -";"459.000 - 460.000 MHz";"Mobile";"Land mobile/On-site paging/PMR/PAMR"
+"- Europe (ECA) -";"460.000 - 470.000 MHz";"Mobile";"Land mobile/On-board communications/PMR/PAMR/On-site paging/Space research/Meteorological aids (military)"
+"- Europe (ECA) -";"470.000 - 694.000 MHz";"Broadcasting";"Radio microphones and ALD/PMSE/Broadcasting (terrestrial)/Wind profilers/Radio astronomy"
+"- Europe (ECA) -";"694.000 - 790.000 MHz";"Broadcasting/Mobile except aeronautical mobile";"Radio microphones and ALD/PMSE/Broadcasting (terrestrial)/MFCN/PPDR"
+"- Europe (ECA) -";"790.000 - 862.000 MHz";"Mobile except aeronautical mobile/Broadcasting";"MFCN/-/Radio microphones and ALD/Broadcasting (terrestrial)"
+"- Europe (ECA) -";"862.000 - 870.000 MHz";"Mobile";"Radio microphones and ALD/Alarms/Non-specific SRDs/RFID/Tracking, tracing and data acquisition/-/Maritime military systems/Land military systems/Wideband data transmission systems"
+"- Europe (ECA) -";"870.000 - 876.000 MHz";"Mobile";"-/Land military systems/Maritime military systems/Non-specific SRDs/PMR/PAMR/Tracking, tracing and data acquisition"
+"- Europe (ECA) -";"876.000 - 880.000 MHz";"Mobile";"-/Land military systems/Maritime military systems/GSM-R"
+"- Europe (ECA) -";"880.000 - 890.000 MHz";"Mobile";"GSM/MCV/IMT"
+"- Europe (ECA) -";"890.000 - 915.000 MHz";"Mobile/Radiolocation";"IMT/MCV/GSM/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"915.000 - 921.000 MHz";"Mobile/Radiolocation";"Maritime military systems/Land military systems/PMR/PAMR/-/Non-specific SRDs/RFID"
+"- Europe (ECA) -";"921.000 - 925.000 MHz";"Mobile/Radiolocation";"GSM-R/Land military systems/Maritime military systems/-"
+"- Europe (ECA) -";"925.000 - 942.000 MHz";"Radiolocation/Mobile";"GSM/IMT/MCV/Land military systems/Maritime military systems"
+"- Europe (ECA) -";"942.000 - 960.000 MHz";"Mobile";"GSM/IMT/MCV"
+"- Europe (ECA) -";"960.000 - 1164.000 MHz";"Aeronautical Radionavigation/Aeronautical Mobile-Satellite (R)/Aeronautical Mobile (R)";"Aeronautical/Aeronautical military systems"
+"- Europe (ECA) -";"1164.000 - 1215.000 MHz";"Aeronautical Radionavigation/Radionavigation-Satellite (space-to-Earth) (space-to-space)";"Aeronautical military systems/Satellite systems (military)/GALILEO/Aeronautical navigation/GNSS Repeater/GLONASS"
+"- Europe (ECA) -";"1215.000 - 1240.000 MHz";"Earth Exploration-Satellite (active)/Radiolocation/Radionavigation-Satellite (space-to-Earth) (space-to-space)/Space Research (active)";"GLONASS/GNSS Repeater/GPS/Radiolocation (civil)/Active sensors (satellite)/Satellite systems (military)/Radiolocation (military)"
+"- Europe (ECA) -";"1240.000 - 1300.000 MHz";"Earth Exploration-Satellite (active)/Radionavigation-Satellite (space-to-Earth) (space-to-space)/Radiolocation/Space Research (active)/Amateur/Amateur-Satellite";"Radiolocation (military)/Satellite systems (military)/Amateur-satellite/GALILEO/Wind profilers/Amateur/GLONASS/Radiolocation (civil)/Active sensors (satellite)/GNSS Repeater"
+"- Europe (ECA) -";"1300.000 - 1350.000 MHz";"Aeronautical Radionavigation/Radiolocation/Radionavigation-Satellite (Earth-to-space)";"Satellite navigation systems/Radiolocation (civil)/Radio astronomy/Satellite systems (military)/Radiolocation (military)"
+"- Europe (ECA) -";"1350.000 - 1400.000 MHz";"Fixed/Mobile/Radiolocation";"Land military systems/Maritime military systems/Aeronautical military systems/Radiolocation (military)/Radio microphones and ALD/Fixed/Radio astronomy"
+"- Europe (ECA) -";"1400.000 - 1427.000 MHz";"Earth Exploration-Satellite (passive)/Radio Astronomy/Space Research (passive)";"Passive sensors (satellite)/Radio astronomy"
+"- Europe (ECA) -";"1427.000 - 1429.000 MHz";"Fixed/Mobile except aeronautical mobile/Space Operation (Earth-to-space)";"Fixed/MFCN/Maritime military systems/Land military systems"
+"- Europe (ECA) -";"1429.000 - 1452.000 MHz";"Fixed/Mobile except aeronautical mobile";"Land military systems/Maritime military systems/MFCN/Fixed"
+"- Europe (ECA) -";"1452.000 - 1492.000 MHz";"Broadcasting/Fixed/Mobile except aeronautical mobile";"T-DAB/MFCN"
+"- Europe (ECA) -";"1492.000 - 1518.000 MHz";"Fixed/Mobile except aeronautical mobile";"Fixed/MFCN/Maritime military systems/Land military systems/Radio microphones and ALD"
+"- Europe (ECA) -";"1518.000 - 1525.000 MHz";"Fixed/Mobile except aeronautical mobile/Mobile-Satellite (space-to-Earth)";"Maritime military systems/Land military systems/Radio microphones and ALD/MSS Earth stations/Fixed/IMT-2000 satellite component"
+"- Europe (ECA) -";"1525.000 - 1530.000 MHz";"Fixed/Mobile-Satellite (space-to-Earth)/Space Operation (space-to-Earth)";"IMT-2000 satellite component/MSS Earth stations/Fixed"
+"- Europe (ECA) -";"1530.000 - 1535.000 MHz";"Mobile-Satellite (space-to-Earth)/Space Operation (space-to-Earth)/Earth Exploration-Satellite/Fixed/Mobile except aeronautical mobile (R)";"IMT-2000 satellite component/MSS Earth stations"
+"- Europe (ECA) -";"1535.000 - 1559.000 MHz";"Mobile-Satellite (space-to-Earth)";"MSS Earth stations/IMT-2000 satellite component"
+"- Europe (ECA) -";"1559.000 - 1610.000 MHz";"Aeronautical Radionavigation/Radionavigation-Satellite (space-to-Earth)/Radionavigation-Satellite (space-to-space)";"GNSS Pseudolites/GNSS Repeater/GALILEO/GLONASS/GPS"
+"- Europe (ECA) -";"1610.000 - 1610.600 MHz";"Aeronautical Radionavigation/Mobile-Satellite (Earth-to-space)";"MSS Earth stations/IMT-2000 satellite component/GLONASS"
+"- Europe (ECA) -";"1610.600 - 1613.800 MHz";"Aeronautical Radionavigation/Mobile-Satellite (Earth-to-space)/Radio Astronomy";"IMT-2000 satellite component/MSS Earth stations/Radio astronomy"
+"- Europe (ECA) -";"1613.800 - 1626.500 MHz";"Aeronautical Radionavigation/Mobile-Satellite (Earth-to-space)/Mobile-Satellite (space-to-Earth)";"MSS Earth stations/IMT-2000 satellite component"
+"- Europe (ECA) -";"1626.500 - 1660.000 MHz";"Mobile-Satellite (Earth-to-space)";"IMT-2000 satellite component/MSS Earth stations"
+"- Europe (ECA) -";"1660.000 - 1660.500 MHz";"Mobile-Satellite (Earth-to-space)/Radio Astronomy";"MSS Earth stations/Radio astronomy/IMT-2000 satellite component"
+"- Europe (ECA) -";"1660.500 - 1668.000 MHz";"Radio Astronomy/Space Research (passive)/Fixed/Mobile except aeronautical mobile";"Radio astronomy"
+"- Europe (ECA) -";"1668.000 - 1668.400 MHz";"Mobile-Satellite (Earth-to-space)/Radio Astronomy/Space Research (passive)/Fixed/Mobile except aeronautical mobile";"Radio astronomy/IMT-2000 satellite component"
+"- Europe (ECA) -";"1668.400 - 1670.000 MHz";"Fixed/Meteorological Aids/Mobile except aeronautical mobile/Mobile-Satellite (Earth-to-space)/Radio Astronomy";"IMT-2000 satellite component/Meteorology/Radio astronomy"
+"- Europe (ECA) -";"1670.000 - 1675.000 MHz";"Meteorological Aids/Meteorological-Satellite (space-to-Earth)/Mobile/Mobile-Satellite (Earth-to-space)/Fixed";"Weather satellites/MSS Earth stations/IMT-2000 satellite component/Meteorology"
+"- Europe (ECA) -";"1675.000 - 1690.000 MHz";"Fixed/Meteorological Aids/Meteorological-Satellite (space-to-Earth)/Mobile except aeronautical mobile";"Land military systems/Maritime military systems/Meteorological aids (military)/Sondes/Weather satellites"
+"- Europe (ECA) -";"1690.000 - 1700.000 MHz";"Meteorological Aids/Meteorological-Satellite (space-to-Earth)/Fixed/Mobile except aeronautical mobile";"Weather satellites/Land military systems/Meteorological aids (military)/Maritime military systems"
+"- Europe (ECA) -";"1700.000 - 1710.000 MHz";"Fixed/Meteorological-Satellite (space-to-Earth)/Mobile except aeronautical mobile";"Land military systems/Maritime military systems/Meteorological aids (military)/Weather satellites"
+"- Europe (ECA) -";"1710.000 - 1785.000 MHz";"Fixed/Mobile";"GSM/Radio astronomy/IMT/MCV/MCA"
+"- Europe (ECA) -";"1785.000 - 1800.000 MHz";"Fixed/Mobile";"-/Land mobile/Radio microphones and ALD/Land military systems"
+"- Europe (ECA) -";"1800.000 - 1805.000 MHz";"Mobile/Fixed";"Land military systems/Radio microphones and ALD/-"
+"- Europe (ECA) -";"1805.000 - 1880.000 MHz";"Fixed/Mobile";"MCA/MCV/IMT/GSM"
+"- Europe (ECA) -";"1880.000 - 1885.000 MHz";"Mobile/Fixed";"DECT"
+"- Europe (ECA) -";"1885.000 - 1900.000 MHz";"Mobile/Fixed";"DECT"
+"- Europe (ECA) -";"1900.000 - 1930.000 MHz";"Mobile/Fixed";"MCA/-/MFCN/MCV/DA2GC"
+"- Europe (ECA) -";"1930.000 - 1970.000 MHz";"Fixed/Mobile";"MFCN/MCV/-/MCA"
+"- Europe (ECA) -";"1970.000 - 1980.000 MHz";"Mobile/Fixed";"MCA/-/MFCN/MCV"
+"- Europe (ECA) -";"1980.000 - 2010.000 MHz";"Mobile/Mobile-Satellite (Earth-to-space)";"-/MSS Earth stations"
+"- Europe (ECA) -";"2010.000 - 2025.000 MHz";"Mobile/Fixed";"IMT/-/PMSE"
+"- Europe (ECA) -";"2025.000 - 2110.000 MHz";"Earth Exploration-Satellite (Earth-to-space) (space-to-space)/Fixed/Mobile/Space Operation (Earth-to-space) (space-to-space)/Space Research (Earth-to-space) (space-to-space)";"Land military systems/Telemetry/Telecommand (military)/Aeronautical military systems/Maritime military systems/Fixed/PMSE/Space research"
+"- Europe (ECA) -";"2110.000 - 2120.000 MHz";"Mobile/Space Research (deep space) (Earth-to-space)/Fixed";"-/MCA/MFCN/MCV"
+"- Europe (ECA) -";"2120.000 - 2170.000 MHz";"Mobile/Fixed";"MFCN/MCV/MCA/-"
+"- Europe (ECA) -";"2170.000 - 2200.000 MHz";"Mobile/Mobile-Satellite (space-to-Earth)";"-/MSS Earth stations"
+"- Europe (ECA) -";"2200.000 - 2290.000 MHz";"Fixed/Mobile/Space Operation (space-to-Earth) (space-to-space)/Space Research (space-to-Earth) (space-to-space)/Earth Exploration-Satellite (space-to-Earth) (space-to-space)";"Fixed/Radio astronomy/Space research/PMSE/Land military systems/Telemetry/Telecommand (military)/Aeronautical military systems/Maritime military systems"
+"- Europe (ECA) -";"2290.000 - 2300.000 MHz";"Fixed/Mobile except aeronautical mobile/Space Research (deep space) (space-to-Earth)";"PMSE/Land mobile/Space research"
+"- Europe (ECA) -";"2300.000 - 2400.000 MHz";"Fixed/Mobile/Amateur/Radiolocation";"Aeronautical telemetry/Amateur/PMSE/MFCN/Land military systems/Telemetry/Telecommand (military)/Aeronautical military systems/Maritime military systems"
+"- Europe (ECA) -";"2400.000 - 2450.000 MHz";"Fixed/Mobile/Amateur-Satellite/Radiolocation/Amateur";"PMSE/Radiodetermination applications/Amateur/Amateur-satellite/ISM/Non-specific SRDs/Wideband data transmission systems/RFID"
+"- Europe (ECA) -";"2450.000 - 2483.500 MHz";"Fixed/Mobile";"ISM/Non-specific SRDs/Wideband data transmission systems/RFID/Radiodetermination applications/PMSE"
+"- Europe (ECA) -";"2483.500 - 2500.000 MHz";"Fixed/Mobile/Mobile-Satellite (space-to-Earth)";"PMSE/MBANS/Active medical implants/ISM/Land mobile/MSS Earth stations/IMT-2000 satellite component"
+"- Europe (ECA) -";"2500.000 - 2520.000 MHz";"Mobile except aeronautical mobile/Fixed";"MCV/MFCN"
+"- Europe (ECA) -";"2520.000 - 2655.000 MHz";"Fixed/Mobile except aeronautical mobile";"MFCN/MCV"
+"- Europe (ECA) -";"2655.000 - 2670.000 MHz";"Fixed/Mobile except aeronautical mobile/Earth Exploration-Satellite (passive)/Radio Astronomy/Space Research (passive)";"MCV/MFCN/Radio astronomy"
+"- Europe (ECA) -";"2670.000 - 2690.000 MHz";"Mobile except aeronautical mobile/Fixed/Radio Astronomy";"Radio astronomy/MFCN/MCV"
+"- Europe (ECA) -";"2690.000 - 2700.000 MHz";"Earth Exploration-Satellite (passive)/Radio Astronomy/Space Research (passive)";"Passive sensors (satellite)/Radio astronomy"
+"- Europe (ECA) -";"2700.000 - 2900.000 MHz";"Aeronautical Radionavigation/Radiolocation";"Radiolocation (civil)/Aeronautical navigation/Weather radar/Radiolocation (military)/PMSE"
+"- Europe (ECA) -";"2900.000 - 3100.000 MHz";"Radiolocation/Radionavigation";"Radiolocation (military)/Radiolocation (civil)"
+"- Europe (ECA) -";"3100.000 - 3300.000 MHz";"Radiolocation/Earth Exploration-Satellite (active)/Space Research (active)";"Radiolocation (civil)/Active sensors (satellite)/Radiolocation (military)/UWB applications/Radio astronomy"
+"- Europe (ECA) -";"3300.000 - 3400.000 MHz";"Radiolocation";"Radio astronomy/Radiolocation (military)/Radiolocation (civil)/UWB applications"
+"- Europe (ECA) -";"3400.000 - 3600.000 MHz";"Fixed/Fixed-Satellite (space-to-Earth)/Amateur/Radiolocation/Mobile except aeronautical mobile";"Amateur/FSS Earth stations/MFCN/PMSE/Radiolocation (civil)/Radiolocation (military)/UWB applications/BWA"
+"- Europe (ECA) -";"3600.000 - 4200.000 MHz";"Mobile/Fixed/Fixed-Satellite (space-to-Earth)";"-/BWA/FSS Earth stations/Fixed/UWB applications/MFCN/ESV"
+"- Europe (ECA) -";"4200.000 - 4400.000 MHz";"Aeronautical Radionavigation/Aeronautical Mobile (R)";"WAIC/Aeronautical military systems/UWB applications/Altimeters/Passive sensors (satellite)"
+"- Europe (ECA) -";"4400.000 - 4500.000 MHz";"Fixed/Mobile";"PMSE/UWB applications/Aeronautical military systems/Land military systems/Maritime military systems/Telemetry/Telecommand (military)"
+"- Europe (ECA) -";"4500.000 - 4800.000 MHz";"Fixed/Fixed-Satellite (space-to-Earth)/Mobile";"Land military systems/Maritime military systems/Telemetry/Telecommand (military)/Aeronautical military systems/UWB applications/Radiodetermination applications/FSS Earth stations/PMSE"
+"- Europe (ECA) -";"4800.000 - 4990.000 MHz";"Fixed/Radio Astronomy/Mobile";"PMSE/Passive sensors (satellite)/Radio astronomy/Radiodetermination applications/BBDR/Aeronautical military systems/Land military systems/Telemetry/Telecommand (military)/Maritime military systems"
+"- Europe (ECA) -";"4990.000 - 5000.000 MHz";"Fixed/Mobile except aeronautical mobile/Radio Astronomy";"Telemetry/Telecommand (military)/Land military systems/Maritime military systems/Aeronautical military systems/Radiodetermination applications/PMSE/Radio astronomy"
+"- Europe (ECA) -";"5000.000 - 5010.000 MHz";"Aeronautical Radionavigation/Radionavigation-Satellite (Earth-to-space)/Radio Astronomy/Space Research (passive)/Aeronautical Mobile-Satellite (R)";"Radio astronomy/Satellite navigation systems/GALILEO/Radiodetermination applications"
+"- Europe (ECA) -";"5010.000 - 5030.000 MHz";"Aeronautical Mobile-Satellite (R)/Aeronautical Radionavigation/Radionavigation-Satellite (space-to-Earth) (space-to-space)/Radio Astronomy/Space Research (passive)";"Radiodetermination applications/GALILEO/Radio astronomy/Satellite navigation systems"
+"- Europe (ECA) -";"5030.000 - 5091.000 MHz";"Aeronautical Radionavigation/Aeronautical Mobile-Satellite (R)/Aeronautical Mobile (R)";"MLS/Radiodetermination applications"
+"- Europe (ECA) -";"5091.000 - 5150.000 MHz";"Aeronautical Mobile-Satellite (R)/Aeronautical Radionavigation/Fixed-Satellite (Earth-to-space)/Aeronautical Mobile";"Radiodetermination applications/-"
+"- Europe (ECA) -";"5150.000 - 5250.000 MHz";"Aeronautical Radionavigation/Fixed-Satellite (Earth-to-space)/Mobile except aeronautical mobile";"Radiodetermination applications/BBDR/Aeronautical telemetry/Feeder links/Radio LANs"
+"- Europe (ECA) -";"5250.000 - 5255.000 MHz";"Earth Exploration-Satellite (active)/Mobile except aeronautical mobile/Radiolocation/Space Research";"Active sensors (satellite)/Radiodetermination applications/Maritime radar/Weather radar/Radio LANs/-/Radiolocation (military)"
+"- Europe (ECA) -";"5255.000 - 5350.000 MHz";"Earth Exploration-Satellite (active)/Mobile except aeronautical mobile/Radiolocation/Space Research (active)";"Radiolocation (military)/-/Radiodetermination applications/Radio LANs/Active sensors (satellite)/Maritime radar/Weather radar"
+"- Europe (ECA) -";"5350.000 - 5460.000 MHz";"Aeronautical Radionavigation/Earth Exploration-Satellite (active)/Radiolocation/Space Research (active)";"Active sensors (satellite)/Maritime radar/Weather radar/Radiodetermination applications/-/Radiolocation (military)"
+"- Europe (ECA) -";"5460.000 - 5470.000 MHz";"Earth Exploration-Satellite (active)/Radiolocation/Radionavigation/Space Research (active)";"Radiolocation (military)/-/Radiodetermination applications/Active sensors (satellite)/Maritime radar/Weather radar"
+"- Europe (ECA) -";"5470.000 - 5570.000 MHz";"Earth Exploration-Satellite (active)/Maritime Radionavigation/Mobile except aeronautical mobile/Radiolocation/Space Research (active)";"Active sensors (satellite)/-/Maritime radar/Weather radar/Radio LANs/Radiodetermination applications/Radiolocation (military)"
+"- Europe (ECA) -";"5570.000 - 5650.000 MHz";"Maritime Radionavigation/Mobile except aeronautical mobile/Radiolocation";"Radiolocation (military)/Radiodetermination applications/-/Maritime radar/Radio LANs/Weather radar"
+"- Europe (ECA) -";"5650.000 - 5725.000 MHz";"Mobile except aeronautical mobile/Radiolocation/Amateur/Amateur-Satellite (Earth-to-space)";"Amateur/-/Maritime radar/Weather radar/Radio LANs/Radiodetermination applications/Radiolocation (military)/Amateur-satellite"
+"- Europe (ECA) -";"5725.000 - 5830.000 MHz";"Radiolocation/Amateur/Mobile/Fixed-Satellite (Earth-to-space)/Fixed";"WIA/Radiolocation (military)/Radiodetermination applications/BFWA/Amateur/ISM/Non-specific SRDs/TTT/Weather radar"
+"- Europe (ECA) -";"5830.000 - 5850.000 MHz";"Fixed/Fixed-Satellite (Earth-to-space)/Radiolocation/Amateur/Amateur-Satellite (space-to-Earth)/Mobile";"ISM/Non-specific SRDs/Weather radar/Radiodetermination applications/Amateur-satellite/Radiolocation (military)/WIA/Amateur/BFWA"
+"- Europe (ECA) -";"5850.000 - 5925.000 MHz";"Fixed/Mobile/Fixed-Satellite (Earth-to-space)";"MBR/WIA/DA2GC/Radiodetermination applications/BFWA/ITS/FSS Earth stations/ISM/Non-specific SRDs"
+"- Europe (ECA) -";"5925.000 - 6700.000 MHz";"Fixed/Fixed-Satellite (Earth-to-space)/Earth Exploration-Satellite (passive)";"Passive sensors (satellite)/Fixed/FSS Earth stations/Radiodetermination applications/UWB applications/-/ESV/Radio astronomy"
+"- Europe (ECA) -";"6700.000 - 7075.000 MHz";"Fixed/Earth Exploration-Satellite (passive)/Fixed-Satellite (Earth-to-space) (space-to-Earth)";"PMSE/Radiodetermination applications/UWB applications/Passive sensors (satellite)/Feeder links/Fixed/FSS Earth stations"
+"- Europe (ECA) -";"7075.000 - 7145.000 MHz";"Fixed/Earth Exploration-Satellite (passive)";"Passive sensors (satellite)/Fixed/UWB applications/Radiodetermination applications/PMSE"
+"- Europe (ECA) -";"7145.000 - 7190.000 MHz";"Fixed/Mobile/Space Research (deep space) (Earth-to-space)/Space Operation (Earth-to-space)";"PMSE/Fixed/UWB applications/Radiodetermination applications"
+"- Europe (ECA) -";"7190.000 - 7235.000 MHz";"Earth Exploration-Satellite (Earth-to-space)/Fixed/Space Research (Earth-to-space)/Mobile";"Fixed/Passive sensors (satellite)/UWB applications/Radiodetermination applications/PMSE"
+"- Europe (ECA) -";"7235.000 - 7250.000 MHz";"Fixed/Earth Exploration-Satellite (Earth-to-space)/Space Research (Earth-to-space)";"PMSE/UWB applications/Radiodetermination applications/Passive sensors (satellite)/Fixed"
+"- Europe (ECA) -";"7250.000 - 7300.000 MHz";"Fixed/Fixed-Satellite (space-to-Earth)/Mobile";"Fixed/MSS Earth stations/Radiodetermination applications/UWB applications/PMSE/Satellite systems (military)/Land military systems"
+"- Europe (ECA) -";"7300.000 - 7375.000 MHz";"Fixed/Fixed-Satellite (space-to-Earth)/Mobile except aeronautical mobile";"Land military systems/Fixed/MSS Earth stations/UWB applications/Radiodetermination applications/Satellite systems (military)/PMSE"
+"- Europe (ECA) -";"7375.000 - 7450.000 MHz";"Fixed/Fixed-Satellite (space-to-Earth)/Mobile except aeronautical mobile/Maritime Mobile-Satellite (space-to-Earth)";"PMSE/Satellite systems (military)/Land military systems/Fixed/MSS Earth stations/UWB applications/Radiodetermination applications"
+"- Europe (ECA) -";"7450.000 - 7550.000 MHz";"Maritime Mobile-Satellite (space-to-Earth)/Fixed/Fixed-Satellite (space-to-Earth)/Meteorological-Satellite (space-to-Earth)/Mobile except aeronautical mobile";"PMSE/Satellite systems (military)/Land military systems/UWB applications/Radiodetermination applications/Fixed/Weather satellites"
+"- Europe (ECA) -";"7550.000 - 7750.000 MHz";"Fixed/Fixed-Satellite (space-to-Earth)/Mobile except aeronautical mobile/Maritime Mobile-Satellite (space-to-Earth)";"Fixed/Radiodetermination applications/UWB applications/Land military systems/Satellite systems (military)/PMSE"
+"- Europe (ECA) -";"7750.000 - 7900.000 MHz";"Fixed/Meteorological-Satellite (space-to-Earth)/Mobile except aeronautical mobile";"PMSE/UWB applications/Radiodetermination applications/Fixed/Weather satellites"
+"- Europe (ECA) -";"7900.000 - 8025.000 MHz";"Fixed/Mobile/Fixed-Satellite (Earth-to-space)";"Fixed/MSS Earth stations/Radiodetermination applications/UWB applications/PMSE/Land military systems/Satellite systems (military)"
+"- Europe (ECA) -";"8025.000 - 8175.000 MHz";"Fixed-Satellite (Earth-to-space)/Earth Exploration-Satellite (space-to-Earth)/Fixed/Mobile";"Land military systems/PMSE/Satellite systems (military)/UWB applications/Radiodetermination applications/Earth exploration-satellite/Fixed/Land mobile"
+"- Europe (ECA) -";"8175.000 - 8215.000 MHz";"Earth Exploration-Satellite (space-to-Earth)/Fixed/Meteorological-Satellite (Earth-to-space)/Mobile/Fixed-Satellite (Earth-to-space)";"Earth exploration-satellite/Fixed/Land mobile/Radiodetermination applications/UWB applications/Land military systems/Satellite systems (military)/PMSE"
+"- Europe (ECA) -";"8215.000 - 8400.000 MHz";"Fixed-Satellite (Earth-to-space)/Earth Exploration-Satellite (space-to-Earth)/Fixed";"PMSE/Land military systems/Satellite systems (military)/UWB applications/Radiodetermination applications/Earth exploration-satellite/Fixed/Radio astronomy"
+"- Europe (ECA) -";"8400.000 - 8500.000 MHz";"Fixed/Space Research (space-to-Earth)/Radiolocation";"Fixed/Space research/Radiodetermination applications/UWB applications/PMSE"
+"- Europe (ECA) -";"8500.000 - 8550.000 MHz";"Radiolocation";"Aeronautical military systems/Radiolocation (military)/UWB applications/Radiodetermination applications/Aeronautical navigation/Radiolocation (civil)"
+"- Europe (ECA) -";"8550.000 - 8650.000 MHz";"Earth Exploration-Satellite (active)/Radiolocation/Space Research (active)";"Active sensors (satellite)/Aeronautical navigation/Radiolocation (civil)/Radiodetermination applications/UWB applications/Radiolocation (military)/Aeronautical military systems"
+"- Europe (ECA) -";"8650.000 - 8750.000 MHz";"Radiolocation";"Aeronautical military systems/Radiolocation (military)/UWB applications/Radiodetermination applications/Aeronautical navigation/Radiolocation (civil)"
+"- Europe (ECA) -";"8750.000 - 8850.000 MHz";"Aeronautical Radionavigation/Radiolocation/Space Research";"Aeronautical navigation/Radiolocation (civil)/Radiodetermination applications/UWB applications/Radiolocation (military)/Aeronautical military systems"
+"- Europe (ECA) -";"8850.000 - 9000.000 MHz";"Maritime Radionavigation/Radiolocation/Space Research";"Aeronautical military systems/Radiolocation (military)/UWB applications/Radiodetermination applications/Aeronautical navigation/Radiolocation (civil)"
+"- Europe (ECA) -";"9000.000 - 9200.000 MHz";"Aeronautical Radionavigation/Radiolocation/Space Research";"Aeronautical navigation/Radiolocation (civil)/Radiodetermination applications/Radiolocation (military)/Aeronautical military systems"
+"- Europe (ECA) -";"9200.000 - 9300.000 MHz";"Maritime Radionavigation/Radiolocation/Space Research/Earth Exploration-Satellite (active)";"Aeronautical military systems/Synthetic aperture radar/Radiolocation (military)/Radiodetermination applications/Aeronautical navigation/Radiolocation (civil)"
+"- Europe (ECA) -";"9300.000 - 9500.000 MHz";"Radionavigation/Radiolocation/Space Research (active)/Earth Exploration-Satellite (active)";"Aeronautical navigation/Weather radar/Radiodetermination applications/Radiolocation (civil)/Radiolocation (military)/Aeronautical military systems/Satellite systems (military)"
+"- Europe (ECA) -";"9500.000 - 9800.000 MHz";"Earth Exploration-Satellite (active)/Radiolocation/Space Research (active)";"Aeronautical military systems/Satellite systems (military)/Radiolocation (military)/Radiodetermination applications/Active sensors (satellite)/Aeronautical navigation/Radiolocation (civil)"
+"- Europe (ECA) -";"9800.000 - 9900.000 MHz";"Radiolocation/Space Research (active)/Earth Exploration-Satellite (active)";"Aeronautical navigation/Radiolocation (civil)/Radiodetermination applications/Radiolocation (military)/Aeronautical military systems/Satellite systems (military)"
+"- Europe (ECA) -";"9900.000 - 10000.000 MHz";"Radiolocation/Fixed/Earth Exploration-Satellite (active)";"Synthetic aperture radar/Aeronautical military systems/Satellite systems (military)/Radiolocation (military)/Radiodetermination applications/Aeronautical navigation/Radiolocation (civil)"
+"- Europe (ECA) -";"10000.000 - 10400.000 MHz";"Fixed/Mobile/Radiolocation/Amateur/Earth Exploration-Satellite (active)";"Synthetic aperture radar/Amateur/Radiolocation (military)/Land military systems/Aeronautical military systems/Maritime military systems/PMSE/Radiodetermination applications/Fixed/Radiolocation (civil)"
\ No newline at end of file
diff --git a/src/hackrf-sweep/src-java/shared/mvc/MVCController.java b/src/hackrf-sweep/src-java/shared/mvc/MVCController.java
new file mode 100644
index 0000000..f46dab1
--- /dev/null
+++ b/src/hackrf-sweep/src-java/shared/mvc/MVCController.java
@@ -0,0 +1,139 @@
+package shared.mvc;
+
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JSlider;
+import javax.swing.JSpinner;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ListDataEvent;
+import javax.swing.event.ListDataListener;
+
+import shared.mvc.ModelValue.ModelValueBoolean;
+import shared.mvc.ModelValue.ModelValueInt;
+
+/**
+ * In MVC model, this class is the Controller, listening for change events from
+ * both the model and the view and ensuring their states are synchronized.
+ *
+ * @param
+ */
+public class MVCController {
+ public static interface ViewAddChangeListener {
+ public void addChangeListener(Consumer viewValueChangedCall);
+ }
+
+ /**
+ * Flag indicating the view is being updated to prevent its listeners from
+ * changing the {@link ModelValue} causing an infinite loop.
+ */
+ protected boolean disableViewListeners = false;
+
+ public MVCController(ViewAddChangeListener viewAddChangeListener, Consumer viewSetValue,
+ ModelValue model) {
+ this(viewAddChangeListener, viewSetValue, model, (T val) -> val, (T val) -> val);
+ }
+
+ /**
+ * Generic ({@link JComponent} independent) constructor
+ *
+ * @param viewAddChangeListener
+ * @param viewSetValue
+ * @param model
+ * @param conversionViewToModel
+ * @param conversionModelToView
+ */
+ public MVCController(ViewAddChangeListener viewAddChangeListener,
+ Consumer viewSetValue, ModelValue model, Function conversionViewToModel,
+ Function conversionModelToView) {
+ viewAddChangeListener.addChangeListener((VIEW_T newViewValue) -> updateModelValue(
+ () -> model.setValue(conversionViewToModel.apply(newViewValue))));
+ model.addListener(() -> updateView(() -> viewSetValue.accept(conversionModelToView.apply(model.getValue()))));
+ sync(model);
+ }
+
+ public MVCController(JCheckBox checkbox, ModelValueBoolean model) {
+ checkbox.addChangeListener((ChangeEvent e) -> updateModelValue(() -> model.setValue(checkbox.isSelected())));
+ model.addListener(() -> updateView(() -> checkbox.setSelected(model.getValue())));
+ sync(model);
+ }
+
+ public MVCController(JSlider slider, ModelValueInt model) {
+ this(slider, model, val -> val, val -> val);
+ }
+
+ public MVCController(JSlider slider, ModelValue model, Function conversionViewToModel,
+ Function conversionModelToView) {
+ slider.addChangeListener((ChangeEvent e) -> updateModelValue(
+ () -> model.setValue(conversionViewToModel.apply(slider.getValue()))));
+ model.addListener(() -> updateView(() -> slider.setValue(conversionModelToView.apply(model.getValue()))));
+ sync(model);
+ }
+
+ public MVCController(JSpinner spinner, ModelValue model, Function