Compare commits

...

4 Commits

22 changed files with 592 additions and 386 deletions

2
.idea/misc.xml generated
View File

@@ -4,7 +4,7 @@
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="liberica-18.0.1-fx" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="liberica-19.0.1.fx" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@@ -28,7 +28,7 @@ repositories {
maven { url "https://jitpack.io" }
}
version = '0.5.0-beta5'
version = '0.5.0-beta6'
sourceCompatibility = '17'
sourceSets {
@@ -43,10 +43,10 @@ test {
dependencies {
// JUnit Tests
testImplementation 'junit:junit:4.12'
testImplementation 'org.assertj:assertj-core:3.8.0'
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
testImplementation 'org.mockito:mockito-core:3.+'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.assertj:assertj-core:3.23.1'
testImplementation('org.junit.jupiter:junit-jupiter-api:5.9.0')
testImplementation 'org.mockito:mockito-core:4.8.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
@@ -56,33 +56,33 @@ dependencies {
implementation 'com.github.nwaldispuehl:java-lame:v3.98.4'
//mavenCentral/jcenter imports
implementation 'ch.qos.logback:logback-classic:1.2.3'
implementation 'ch.qos.logback:logback-core:1.2.3'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.13.2'
implementation 'com.fazecast:jSerialComm:2.5.0'
implementation 'ch.qos.logback:logback-classic:1.4.4'
implementation 'ch.qos.logback:logback-core:1.4.4'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.0'
implementation 'com.fazecast:jSerialComm:2.9.2'
implementation 'com.github.jiconfont:jiconfont-font_awesome:4.7.0.1'
implementation 'com.github.jiconfont:jiconfont-javafx:1.0.0'
implementation 'com.github.jiconfont:jiconfont-swing:1.0.1'
implementation 'com.github.wendykierp:JTransforms:3.1'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.google.guava:guava:27.0.1-jre'
implementation 'com.google.code.gson:gson:2.10'
implementation 'com.google.guava:guava:31.1-jre'
implementation 'com.jidesoft:jide-oss:3.6.18'
implementation 'com.miglayout:miglayout-swing:5.2'
implementation 'com.miglayout:miglayout-swing:11.0'
implementation 'com.mpatric:mp3agic:0.9.1'
implementation 'commons-io:commons-io:2.7'
implementation 'commons-io:commons-io:2.11.0'
implementation 'eu.hansolo:charts:1.0.5'
implementation 'io.github.dsheirer:radio-reference-api:15.1.8'
implementation 'javax.usb:usb-api:1.0.2'
implementation 'net.coderazzi:tablefilter-swing:5.4.0'
implementation 'org.apache.commons:commons-compress:1.20'
implementation 'org.apache.commons:commons-lang3:3.8.1'
implementation 'net.coderazzi:tablefilter-swing:5.5.4'
implementation 'org.apache.commons:commons-compress:1.21'
implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation 'org.apache.commons:commons-math3:3.6.1'
implementation 'org.apache.commons:commons-csv:1.9.0'
implementation 'org.apache.mina:mina-core:2.1.3'
implementation 'org.apache.mina:mina-http:2.1.3'
implementation 'org.controlsfx:controlsfx:11.1.0'
implementation 'org.rauschig:jarchivelib:1.0.0'
implementation 'org.slf4j:slf4j-api:1.7.25'
implementation 'org.apache.mina:mina-core:2.2.1'
implementation 'org.apache.mina:mina-http:2.2.1'
implementation 'org.controlsfx:controlsfx:11.1.2'
implementation 'org.rauschig:jarchivelib:1.2.0'
implementation 'org.slf4j:slf4j-api:2.0.3'
implementation 'org.usb4java:libusb4java:1.3.0'
implementation 'org.usb4java:usb4java:1.3.0'
implementation 'org.usb4java:usb4java-javax:1.3.0'
@@ -139,11 +139,11 @@ String targetWindowsX86_64 = 'windows-x86_64-v' + version
* author's development environment, but can be changed to your environment if you want to use this build pattern.
*/
String jdk_base = '/home/denny/java_jdks/'
String jdk_linux_aarch64 = jdk_base + 'linux-arm64/jdk-18.0.1-full'
String jdk_linux_x86_64 = jdk_base + 'linux-x64/jdk-18.0.1-full'
String jdk_osx_x86_64 = jdk_base + 'osx-x64/jdk-18.0.1-full.jdk'
String jdk_osx_aarch64 = jdk_base + 'osx-arm64/jdk-18.0.1-full.jdk'
String jdk_windows_x86_64 = jdk_base + 'windows-x64/jdk-18.0.1-full'
String jdk_linux_aarch64 = jdk_base + 'linux-arm64/jdk-19.0.1-full'
String jdk_linux_x86_64 = jdk_base + 'linux-x64/jdk-19.0.1-full'
String jdk_osx_x86_64 = jdk_base + 'osx-x64/jdk-19.0.1-full.jdk'
String jdk_osx_aarch64 = jdk_base + 'osx-arm64/jdk-19.0.1-full.jdk'
String jdk_windows_x86_64 = jdk_base + 'windows-x64/jdk-19.0.1-full'
boolean hasTargetJdks = file(jdk_linux_x86_64).exists() || file(jdk_linux_aarch64).exists() ||
file(jdk_osx_x86_64).exists() || file(jdk_osx_aarch64).exists() || file(jdk_windows_x86_64).exists()
@@ -172,19 +172,19 @@ runtime {
println("Building all runtime images")
println("The [ > jre: ] build phase downloads several target JDKs and this may take a while ... please wait")
targetPlatform(targetLinuxAarch64) {
jdkHome = jdkDownload("https://download.bell-sw.com/java/18.0.1+12/bellsoft-jdk18.0.1+12-linux-aarch64-full.tar.gz")
jdkHome = jdkDownload("https://download.bell-sw.com/java/19.0.1+11/bellsoft-jdk19.0.1+11-linux-aarch64-full.tar.gz")
}
targetPlatform(targetLinuxX86_64) {
jdkHome = jdkDownload("https://download.bell-sw.com/java/18.0.1+12/bellsoft-jdk18.0.1+12-linux-amd64-full.tar.gz")
jdkHome = jdkDownload("https://download.bell-sw.com/java/19.0.1+11/bellsoft-jdk19.0.1+11-linux-amd64-full.tar.gz")
}
targetPlatform(targetOsxAarch64) {
jdkHome = jdkDownload("https://download.bell-sw.com/java/18.0.1+12/bellsoft-jdk18.0.1+12-macos-aarch64-full.tar.gz")
jdkHome = jdkDownload("https://download.bell-sw.com/java/19.0.1+11/bellsoft-jdk19.0.1+11-macos-aarch64-full.tar.gz")
}
targetPlatform(targetOsxX86_64) {
jdkHome = jdkDownload("https://download.bell-sw.com/java/18.0.1+12/bellsoft-jdk18.0.1+12-macos-amd64-full.tar.gz")
jdkHome = jdkDownload("https://download.bell-sw.com/java/19.0.1+11/bellsoft-jdk19.0.1+11-macos-amd64-full.tar.gz")
}
targetPlatform(targetWindowsX86_64) {
jdkHome = jdkDownload("https://download.bell-sw.com/java/18.0.1+12/bellsoft-jdk18.0.1+12-windows-amd64-full.zip")
jdkHome = jdkDownload("https://download.bell-sw.com/java/19.0.1+11/bellsoft-jdk19.0.1+11-windows-amd64-full.zip")
}
}
//Build using pre-downloaded JDKs

Binary file not shown.

View File

@@ -19,6 +19,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-rc-3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

290
gradlew vendored
View File

@@ -1,94 +1,132 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# ******************************************************************************
# Copyright (C) 2014-2022 Dennis Sheirer
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# https://www.apache.org/licenses/LICENSE-2.0
# This program 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 General Public License for more details.
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
# *****************************************************************************
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -97,7 +135,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -105,79 +143,95 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

25
gradlew.bat vendored
View File

@@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -51,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -61,28 +64,14 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,21 +14,20 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
* ****************************************************************************
*/
package io.github.dsheirer.module.log;
import io.github.dsheirer.module.Module;
import io.github.dsheirer.util.TimeStamp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.file.Path;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class EventLogger extends Module
{
@@ -78,9 +77,6 @@ public abstract class EventLogger extends Module
sb.append(mFileNameSuffix);
mLogFileName = sb.toString();
mLog.info("Creating log file:" + mLogFileName);
mLogFile = new OutputStreamWriter(new FileOutputStream(mLogFileName));
write(getHeader());

View File

@@ -1,26 +1,26 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.settings;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import java.awt.*;
import java.awt.Color;
public class ColorSetting extends Setting
{
@@ -91,7 +91,7 @@ public class ColorSetting extends Setting
return new Color(temp.getRed(),
temp.getGreen(),
temp.getBlue(),
mAlpha);
getColorSettingName().getTranslucency());
}
public void setColor(Color color)
@@ -111,84 +111,81 @@ public class ColorSetting extends Setting
public enum ColorSettingName
{
CHANNEL_CONFIG(getTranslucent(Color.LIGHT_GRAY, CONFIG_TRANSLUCENCY),
"Channel", "Channel Color"),
CHANNEL_CONFIG_PROCESSING(getTranslucent(Color.GREEN, CONFIG_TRANSLUCENCY),
"Channel Processing", "Processing Channel Color"),
CHANNEL_CONFIG_SELECTED(getTranslucent(Color.BLUE, CONFIG_TRANSLUCENCY),
"Channel Selected", "Selected Channel Color"),
CHANNEL_STATE_BACKGROUND(Color.BLACK, "Background",
"Channel State Background"),
CHANNEL_STATE_GRADIENT_TOP_CALL(Color.BLACK,
"Call Gradient Top", "Channel Call State Gradient Top"),
CHANNEL_STATE_GRADIENT_MIDDLE_CALL(Color.BLUE,
"Call Gradient Middle", "Channel Call State Gradient Middle"),
CHANNEL_STATE_GRADIENT_TOP_CONTROL(Color.BLACK,
"Control Gradient Top", "Channel Control State Gradient Top"),
CHANNEL_STATE_GRADIENT_MIDDLE_CONTROL(new Color(0xC64F00),
"Control Gradient Middle", "Channel Control State Gradient Middle"),
CHANNEL_STATE_GRADIENT_TOP_DATA(Color.BLACK,
"Data Gradient Top", "Channel Data State Gradient Top"),
CHANNEL_STATE_GRADIENT_MIDDLE_DATA(new Color(0xCC00CC),
"Data Gradient Middle", "Channel Data State Gradient Middle"),
CHANNEL_STATE_GRADIENT_TOP_FADE(Color.BLACK,
"Fade Gradient Top", "Channel Fade State Gradient Top"),
CHANNEL_STATE_GRADIENT_MIDDLE_FADE(Color.DARK_GRAY,
"Fade Gradient Middle", "Channel Fade State Gradient Middle"),
CHANNEL_STATE_GRADIENT_TOP_IDLE(Color.BLACK,
"Idle Gradient Top", "Channel Idle State Gradient Top"),
CHANNEL_STATE_GRADIENT_MIDDLE_IDLE(Color.DARK_GRAY,
"Idle Gradient Middle", "Channel Idle State Gradient Middle"),
CHANNEL_STATE_GRADIENT_TOP_NO_TUNER(Color.RED,
"No Tuner Gradient Top", "Channel No Tuner State Gradient Top"),
CHANNEL_STATE_GRADIENT_MIDDLE_NO_TUNER(new Color(0x990000),
"No Tuner Gradient Middle", "Channel No Tuner State Gradient Middle"),
CHANNEL_STATE_LABEL_DETAILS(Color.LIGHT_GRAY,
"Details", "Details Label Color"),
CHANNEL_STATE_LABEL_DECODER(Color.GREEN,
"Decoder", "Decoder Label Color"),
CHANNEL_STATE_LABEL_AUX_DECODER(Color.YELLOW,
"Aux Decoder", "Aux Decoder Label Color"),
CHANNEL_STATE_SELECTED_CHANNEL(Color.YELLOW,
"Selected Channel Indicator", "Selected Channel Indicator Color"),
SPECTRUM_BACKGROUND(Color.BLACK,
"Background", "Spectrum Background Color"),
SPECTRUM_CURSOR(Color.ORANGE,
"Cursor", "Spectrum Cursor Color"),
SPECTRUM_GRADIENT_BOTTOM(getTranslucent(Color.GREEN, SPECTRUM_TRANSLUCENCY),
"Gradient Bottom", "Spectrum Gradient Bottom Color"),
SPECTRUM_GRADIENT_TOP(getTranslucent(Color.WHITE, SPECTRUM_TRANSLUCENCY),
"Gradient Top", "Spectrum Gradient Top Color"),
SPECTRUM_LINE(getTranslucent(Color.LIGHT_GRAY, SPECTRUM_TRANSLUCENCY),
"Line", "Spectrum Lines and Text Color"),
UNKNOWN(Color.RED, "Unknown", "Unknown Setting Color");
CHANNEL_CONFIG(Color.LIGHT_GRAY, CONFIG_TRANSLUCENCY, "Channel", "Channel Color"),
CHANNEL_CONFIG_PROCESSING(Color.GREEN, CONFIG_TRANSLUCENCY, "Channel Processing", "Processing Channel Color"),
CHANNEL_CONFIG_SELECTED(Color.BLUE, CONFIG_TRANSLUCENCY, "Channel Selected", "Selected Channel Color"),
CHANNEL_STATE_BACKGROUND(Color.BLACK, NO_TRANSLUCENCY, "Background", "Channel State Background"),
CHANNEL_STATE_GRADIENT_TOP_CALL(Color.BLACK, NO_TRANSLUCENCY, "Call Gradient Top", "Channel Call State Gradient Top"),
CHANNEL_STATE_GRADIENT_MIDDLE_CALL(Color.BLUE, NO_TRANSLUCENCY, "Call Gradient Middle", "Channel Call State Gradient Middle"),
CHANNEL_STATE_GRADIENT_TOP_CONTROL(Color.BLACK, NO_TRANSLUCENCY, "Control Gradient Top", "Channel Control State Gradient Top"),
CHANNEL_STATE_GRADIENT_MIDDLE_CONTROL(new Color(0xC64F00), NO_TRANSLUCENCY, "Control Gradient Middle", "Channel Control State Gradient Middle"),
CHANNEL_STATE_GRADIENT_TOP_DATA(Color.BLACK, NO_TRANSLUCENCY, "Data Gradient Top", "Channel Data State Gradient Top"),
CHANNEL_STATE_GRADIENT_MIDDLE_DATA(new Color(0xCC00CC), NO_TRANSLUCENCY, "Data Gradient Middle", "Channel Data State Gradient Middle"),
CHANNEL_STATE_GRADIENT_TOP_FADE(Color.BLACK, NO_TRANSLUCENCY, "Fade Gradient Top", "Channel Fade State Gradient Top"),
CHANNEL_STATE_GRADIENT_MIDDLE_FADE(Color.DARK_GRAY, NO_TRANSLUCENCY, "Fade Gradient Middle", "Channel Fade State Gradient Middle"),
CHANNEL_STATE_GRADIENT_TOP_IDLE(Color.BLACK, NO_TRANSLUCENCY, "Idle Gradient Top", "Channel Idle State Gradient Top"),
CHANNEL_STATE_GRADIENT_MIDDLE_IDLE(Color.DARK_GRAY, NO_TRANSLUCENCY, "Idle Gradient Middle", "Channel Idle State Gradient Middle"),
CHANNEL_STATE_GRADIENT_TOP_NO_TUNER(Color.RED, NO_TRANSLUCENCY, "No Tuner Gradient Top", "Channel No Tuner State Gradient Top"),
CHANNEL_STATE_GRADIENT_MIDDLE_NO_TUNER(new Color(0x990000), NO_TRANSLUCENCY, "No Tuner Gradient Middle", "Channel No Tuner State Gradient Middle"),
CHANNEL_STATE_LABEL_DETAILS(Color.LIGHT_GRAY, NO_TRANSLUCENCY, "Details", "Details Label Color"),
CHANNEL_STATE_LABEL_DECODER(Color.GREEN, NO_TRANSLUCENCY, "Decoder", "Decoder Label Color"),
CHANNEL_STATE_LABEL_AUX_DECODER(Color.YELLOW, NO_TRANSLUCENCY, "Aux Decoder", "Aux Decoder Label Color"),
CHANNEL_STATE_SELECTED_CHANNEL(Color.YELLOW, NO_TRANSLUCENCY, "Selected Channel Indicator", "Selected Channel Indicator Color"),
SPECTRUM_BACKGROUND(Color.BLACK, NO_TRANSLUCENCY, "Background", "Spectrum Background Color"),
SPECTRUM_CURSOR(Color.ORANGE, NO_TRANSLUCENCY, "Cursor", "Spectrum Cursor Color"),
SPECTRUM_GRADIENT_BOTTOM(Color.GREEN, SPECTRUM_TRANSLUCENCY, "Gradient Bottom", "Spectrum Gradient Bottom Color"),
SPECTRUM_GRADIENT_TOP(Color.WHITE, SPECTRUM_TRANSLUCENCY, "Gradient Top", "Spectrum Gradient Top Color"),
SPECTRUM_LINE(Color.LIGHT_GRAY, SPECTRUM_TRANSLUCENCY, "Line", "Spectrum Lines and Text Color"),
UNKNOWN(Color.RED, NO_TRANSLUCENCY,"Unknown", "Unknown Setting Color");
private Color mDefaultColor;
private int mTranslucency;
private String mLabel;
private String mDialogTitle;
private ColorSettingName(Color defaultColor,
String label,
String dialogTitle)
/**
* Enumeration of color names used in user interface, primarily in the spectral displays.
* @param defaultColor to use and for resets.
* @param translucency value for the color.
* @param label for menu items
* @param dialogTitle for selecting in the color chooser.
*/
ColorSettingName(Color defaultColor, int translucency, String label, String dialogTitle)
{
mDefaultColor = defaultColor;
mTranslucency = translucency;
mLabel = label;
mDialogTitle = dialogTitle;
}
/**
* Default color to use when resetting to default.
*/
public Color getDefaultColor()
{
return mDefaultColor;
}
/**
* Translucency to apply to the color
*/
public int getTranslucency()
{
return mTranslucency;
}
/**
* Label for the setting
*/
public String getLabel()
{
return mLabel;
}
/**
* Title to use in dialogs
* @return title
*/
public String getDialogTitle()
{
return mDialogTitle;

View File

@@ -197,7 +197,7 @@ public class SourceEvent
/**
* Creates a new locked state change event
*/
public static SourceEvent lockedState()
public static SourceEvent lockedSampleRateState()
{
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_LOCKED, 1);
}
@@ -205,7 +205,7 @@ public class SourceEvent
/**
* Creates a new unlocked state change event
*/
public static SourceEvent unlockedState()
public static SourceEvent unlockedSampleRateState()
{
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_UNLOCKED, 0);
}

View File

@@ -36,11 +36,11 @@ import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
import io.github.dsheirer.source.tuner.frequency.FrequencyController;
import io.github.dsheirer.source.tuner.frequency.FrequencyController.Tunable;
import io.github.dsheirer.source.tuner.manager.FrequencyErrorCorrectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import java.util.SortedSet;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class TunerController implements Tunable, ISourceEventProcessor, ISourceEventListener,
INativeBufferProvider, Listener<INativeBuffer>, ITunerErrorListener
@@ -70,6 +70,17 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
mFrequencyErrorCorrectionManager = new FrequencyErrorCorrectionManager(this);
}
/**
* Lock for the frequency controller. This should only be used by the channel source manager to lock access to the
* frequency controller while creating a channel source, to block multi-threaded access to the frequency controller
* which might put the center tuned frequency value in an indeterminant state.
* @return frequency controller lock
*/
public ReentrantLock getFrequencyControllerLock()
{
return mFrequencyController.getFrequencyControllerLock();
}
/**
* Frequency correction manager for this tuner controller.
*/
@@ -182,29 +193,30 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
}
/**
* Indicates if the frequency and sample rate controls are locked by another process. User interface controls
* should monitor source events and check the locked state via this method to correctly render the enabled state
* of the frequency and sample rate controls.
* Indicates if the sample rate control is locked by another process. User interface controls should monitor source
* events and check the locked state via this method to correctly render the enabled state of the sample rate control.
*
* @return true if the tuner controller is locked.
*/
public boolean isLocked()
public boolean isLockedSampleRate()
{
return mFrequencyController.isLocked();
//Note: this access is not protected by the mFrequencyControllerLock
return mFrequencyController.isSampleRateLocked();
}
/**
* Sets the frequency and sample rate locked state to the locked argument value. This should only be changed
* by a downstream consumer of samples to prevent users or other processes from modifying the center frequency
* and/or sample rate of the tuner while processing samples.
* Sets the sample rate locked state to the locked argument value. This should only be changed by a downstream
* consumer of samples to prevent users or other processes from modifying the sample rate of the tuner while
* processing samples.
*
* @param locked true to indicate the tuner controller is in a locked state, otherwise false.
*/
public void setLocked(boolean locked)
public void setLockedSampleRate(boolean locked)
{
try
{
mFrequencyController.setLocked(locked);
//Note: this access is not protected by the mFrequencyControllerLock
mFrequencyController.setSampleRateLocked(locked);
}
catch(SourceException se)
{
@@ -214,6 +226,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
public int getBandwidth()
{
//Note: this access is not protected by the mFrequencyControllerLock
return mFrequencyController.getBandwidth();
}
@@ -225,7 +238,15 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public void setFrequency(long frequency) throws SourceException
{
mFrequencyController.setFrequency(frequency);
try
{
getFrequencyControllerLock().lock();
mFrequencyController.setFrequency(frequency);
}
finally
{
getFrequencyControllerLock().unlock();
}
}
/**
@@ -235,28 +256,73 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public long getFrequency()
{
return mFrequencyController.getFrequency();
long frequency;
try
{
getFrequencyControllerLock().lock();
frequency = mFrequencyController.getFrequency();
}
finally
{
getFrequencyControllerLock().unlock();
}
return frequency;
}
@Override
public boolean canTune(long frequency)
{
return mFrequencyController.canTune(frequency);
boolean canTune;
try
{
getFrequencyControllerLock().lock();
canTune = mFrequencyController.canTune(frequency);
}
finally
{
getFrequencyControllerLock().unlock();
}
return canTune;
}
public double getSampleRate()
{
//Note: this access is not protected by the mFrequencyControllerLock
return mFrequencyController.getSampleRate();
}
public double getFrequencyCorrection()
{
return mFrequencyController.getFrequencyCorrection();
double correction;
try
{
getFrequencyControllerLock().lock();
correction = mFrequencyController.getFrequencyCorrection();
}
finally
{
getFrequencyControllerLock().unlock();
}
return correction;
}
public void setFrequencyCorrection(double correction) throws SourceException
{
mFrequencyController.setFrequencyCorrection(correction);
try
{
getFrequencyControllerLock().lock();
mFrequencyController.setFrequencyCorrection(correction);
}
finally
{
getFrequencyControllerLock().unlock();
}
}
/**
@@ -265,7 +331,19 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public long getMinimumFrequency()
{
return mFrequencyController.getMinimumFrequency();
long minimum;
try
{
getFrequencyControllerLock().lock();
minimum = mFrequencyController.getMinimumFrequency();
}
finally
{
getFrequencyControllerLock().unlock();
}
return minimum;
}
/**
@@ -274,7 +352,15 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public void setMinimumFrequency(long minimum)
{
mFrequencyController.setMinimumFrequency(minimum);
try
{
getFrequencyControllerLock().lock();
mFrequencyController.setMinimumFrequency(minimum);
}
finally
{
getFrequencyControllerLock().unlock();
}
}
/**
@@ -283,7 +369,19 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public long getMaximumFrequency()
{
return mFrequencyController.getMaximumFrequency();
long maximum;
try
{
getFrequencyControllerLock().lock();
maximum = mFrequencyController.getMaximumFrequency();
}
finally
{
getFrequencyControllerLock().unlock();
}
return maximum;
}
/**
@@ -292,17 +390,49 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public void setMaximumFrequency(long maximum)
{
mFrequencyController.setMaximumFrequency(maximum);
try
{
getFrequencyControllerLock().lock();
mFrequencyController.setMaximumFrequency(maximum);
}
finally
{
getFrequencyControllerLock().unlock();
}
}
public long getMinTunedFrequency() throws SourceException
{
return mFrequencyController.getFrequency() - (getUsableBandwidth() / 2);
long minTuned;
try
{
getFrequencyControllerLock().lock();
minTuned = mFrequencyController.getFrequency() - (getUsableBandwidth() / 2);
}
finally
{
getFrequencyControllerLock().unlock();
}
return minTuned;
}
public long getMaxTunedFrequency() throws SourceException
{
return mFrequencyController.getFrequency() + (getUsableBandwidth() / 2);
long maxTuned;
try
{
getFrequencyControllerLock().lock();
maxTuned = mFrequencyController.getFrequency() + (getUsableBandwidth() / 2);
}
finally
{
getFrequencyControllerLock().unlock();
}
return maxTuned;
}
/**
@@ -425,7 +555,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public void addListener( ISourceEventProcessor processor )
{
mFrequencyController.addListener(processor);
mFrequencyController.addSourceEventProcessor(processor);
}
/**
@@ -433,7 +563,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public void removeListener( ISourceEventProcessor processor )
{
mFrequencyController.removeFrequencyChangeProcessor(processor);
mFrequencyController.removeSourceEventProcessor(processor);
}
/**

View File

@@ -25,6 +25,9 @@ import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.source.tuner.manager.TunerStatus;
import io.github.dsheirer.source.tuner.ui.TunerEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,9 +43,6 @@ import javax.swing.JSlider;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
/**
* Airspy tuner editor/controller
@@ -102,7 +102,7 @@ public class AirspyTunerEditor extends TunerEditor<AirspyTuner, AirspyTunerConfi
getTunerStatusLabel().setText(status);
getButtonPanel().updateControls();
getFrequencyPanel().updateControls();
getSampleRateCombo().setEnabled(hasTuner() && !getTuner().getTunerController().isLocked());
getSampleRateCombo().setEnabled(hasTuner() && !getTuner().getTunerController().isLockedSampleRate());
getTunerInfoButton().setEnabled(hasTuner());
updateGainComponents((hasTuner() && hasConfiguration()) ? getConfiguration().getGain() : null);
@@ -626,7 +626,7 @@ public class AirspyTunerEditor extends TunerEditor<AirspyTuner, AirspyTunerConfi
*/
private void updateSampleRateToolTip()
{
if(hasTuner() && getTuner().getController().isLocked())
if(hasTuner() && getTuner().getController().isLockedSampleRate())
{
mSampleRateCombo.setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
}

View File

@@ -22,12 +22,11 @@ import io.github.dsheirer.source.ISourceEventProcessor;
import io.github.dsheirer.source.InvalidFrequencyException;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FrequencyController
{
@@ -40,8 +39,12 @@ public class FrequencyController
private long mMaximumFrequency = 0;
private double mFrequencyCorrection = 0.0d;
private double mSampleRate = 0.0d;
private boolean mLocked = false;
private boolean mSampleRateLocked = false;
private List<ISourceEventProcessor> mProcessors = new ArrayList<>();
/**
* Lock protecting access to frequency control plane, source event processor subscriptions and event broadcasting
*/
private ReentrantLock mLock = new ReentrantLock();
/**
@@ -53,6 +56,15 @@ public class FrequencyController
mTunable = tunable;
}
/**
* Lock for controlling access to frequency control plane, event processor subscriptions and source event broadcasts.
*/
public ReentrantLock getFrequencyControllerLock()
{
return mLock;
}
/**
* Prepare for disposal of this instance.
*/
@@ -63,36 +75,36 @@ public class FrequencyController
}
/**
* Indicates if this frequency controller is locked by a remote process. A locked state indicates that neither
* the frequency nor the sample rate should be changed. The remote process will typically be a downstream
* Indicates if the sample rate for this frequency controller is locked by a remote process. A locked state
* indicates that the sample rate cannot be changed. The remote process will typically be a downstream
* consumer of the data produced by the device being controlled (ie polyphase channelizer) that does not want
* the sample rate or frequency to be changed while processing is ongoing.
* the sample rate to be changed while processing (ie channels have been allocated) is ongoing.
*
* @return true if locked or false if not locked.
*/
public boolean isLocked()
public boolean isSampleRateLocked()
{
return mLocked;
return mSampleRateLocked;
}
/**
* Sets the lock state for this frequency controller. Set to true when a consumer process requires that the
* frequency and sample rate controls be locked so that only the singular consumer process makes changes. This
* sample rate control be locked so that only the single consumer process makes changes to the sample rate. This
* is primarily to lock down user interface controls when the polyphase channelizer is producing channels.
*
* @param locked state
* @param sampleRateLocked state
*/
public void setLocked(boolean locked) throws SourceException
public void setSampleRateLocked(boolean sampleRateLocked) throws SourceException
{
mLocked = locked;
mSampleRateLocked = sampleRateLocked;
if(mLocked)
if(mSampleRateLocked)
{
broadcast(SourceEvent.lockedState());
broadcast(SourceEvent.lockedSampleRateState());
}
else
{
broadcast(SourceEvent.unlockedState());
broadcast(SourceEvent.unlockedSampleRateState());
}
}
@@ -111,7 +123,7 @@ public class FrequencyController
{
if(sampleRate != mSampleRate)
{
if(!mLocked)
if(!mSampleRateLocked)
{
mSampleRate = sampleRate;
@@ -284,7 +296,7 @@ public class FrequencyController
/**
* Adds listener to receive frequency change events
*/
public void addListener(ISourceEventProcessor processor)
public void addSourceEventProcessor(ISourceEventProcessor processor)
{
mLock.lock();
@@ -304,7 +316,7 @@ public class FrequencyController
/**
* Removes listener from receiving frequency change events
*/
public void removeFrequencyChangeProcessor(ISourceEventProcessor processor)
public void removeSourceEventProcessor(ISourceEventProcessor processor)
{
mLock.lock();

View File

@@ -120,7 +120,7 @@ public class HackRFTunerEditor extends TunerEditor<HackRFTuner,HackRFTunerConfig
getTunerStatusLabel().setText(status);
getButtonPanel().updateControls();
getFrequencyPanel().updateControls();
getSampleRateCombo().setEnabled(hasTuner() && !getTuner().getTunerController().isLocked());
getSampleRateCombo().setEnabled(hasTuner() && !getTuner().getTunerController().isLockedSampleRate());
updateSampleRateToolTip();
getTunerInfoButton().setEnabled(hasTuner());
@@ -295,7 +295,7 @@ public class HackRFTunerEditor extends TunerEditor<HackRFTuner,HackRFTunerConfig
*/
private void updateSampleRateToolTip()
{
if(hasTuner() && getTuner().getController().isLocked())
if(hasTuner() && getTuner().getController().isLockedSampleRate())
{
mSampleRateCombo.setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
}

View File

@@ -93,38 +93,48 @@ public class HeterodyneChannelSourceManager extends ChannelSourceManager
return null;
}
if(CenterFrequencyCalculator.canTune(tunerChannel, mTunerController, mTunerChannels))
TunerChannelSource source = null;
try
{
try
mTunerController.getFrequencyControllerLock().lock();
if(CenterFrequencyCalculator.canTune(tunerChannel, mTunerController, mTunerChannels))
{
//Attempt to create the channel source first, in case we get a filter design exception
HalfBandTunerChannelSource tunerChannelSource = new HalfBandTunerChannelSource(mChannelSourceEventProcessor,
tunerChannel, mTunerController.getSampleRate(), channelSpecification);
try
{
//Attempt to create the channel source first, in case we get a filter design exception
HalfBandTunerChannelSource tunerChannelSource = new HalfBandTunerChannelSource(mChannelSourceEventProcessor,
tunerChannel, mTunerController.getSampleRate(), channelSpecification);
//Add to the list of channel sources so that it will receive the tuner frequency change
mChannelSources.add(tunerChannelSource);
//Add to the list of channel sources so that it will receive the tuner frequency change
mChannelSources.add(tunerChannelSource);
//Set the current tuner frequency
tunerChannelSource.setFrequency(mTunerController.getFrequency());
//Set the current tuner frequency
tunerChannelSource.setFrequency(mTunerController.getFrequency());
//Add to the channel list and update the tuner center frequency as needed
mTunerChannels.add(tunerChannel);
updateTunerFrequency();
//Add to the channel list and update the tuner center frequency as needed
mTunerChannels.add(tunerChannel);
updateTunerFrequency();
//Lock the tuner controller frequency and sample rate
mTunerController.setLocked(true);
//Lock the tuner controller frequency and sample rate
mTunerController.setLockedSampleRate(true);
broadcast(SourceEvent.channelCountChange(getTunerChannelCount()));
broadcast(SourceEvent.channelCountChange(getTunerChannelCount()));
return tunerChannelSource;
}
catch(FilterDesignException fde)
{
mLog.error("Error creating CIC tuner channel source - couldn't design cleanup filter", fde);
source = tunerChannelSource;
}
catch(FilterDesignException fde)
{
mLog.error("Error creating CIC tuner channel source - couldn't design cleanup filter", fde);
}
}
}
finally
{
mTunerController.getFrequencyControllerLock().unlock();
}
return null;
return source;
}
@Override
@@ -294,7 +304,7 @@ public class HeterodyneChannelSourceManager extends ChannelSourceManager
//Unlock the tuner controller if there are no more channels
if(getTunerChannelCount() == 0)
{
mTunerController.setLocked(false);
mTunerController.setLockedSampleRate(false);
}
broadcast(SourceEvent.channelCountChange(getTunerChannelCount()));
}

View File

@@ -82,18 +82,30 @@ public class PassThroughSourceManager extends ChannelSourceManager
@Override
public TunerChannelSource getSource(TunerChannel tunerChannel, ChannelSpecification channelSpecification)
{
if(!mRunning)
{
return null;
}
PassThroughChannelSource channelSource = new PassThroughChannelSource(new SourceEventProxy(),
mTunerController, tunerChannel);
TunerChannelSource source = null;
mTunerChannels.add(tunerChannel);
mTunerChannelSources.add(channelSource);
try
{
mTunerController.getFrequencyControllerLock().lock();
PassThroughChannelSource channelSource = new PassThroughChannelSource(new SourceEventProxy(),
mTunerController, tunerChannel);
return channelSource;
mTunerChannels.add(tunerChannel);
mTunerChannelSources.add(channelSource);
source = channelSource;
}
finally
{
mTunerController.getFrequencyControllerLock().unlock();
}
return source;
}
@Override

View File

@@ -25,12 +25,11 @@ import io.github.dsheirer.source.tuner.TunerController;
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
import io.github.dsheirer.source.tuner.channel.TunerChannel;
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
import java.util.SortedSet;
import org.apache.commons.math3.util.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.SortedSet;
/**
* PolyphaseChannelSourceManager is responsible for managing the tuner's center tuned frequency and providing access to
* polyphase tuner channel sources (ie DDCs). This class is responsible for determining IF a requested channel can
@@ -416,48 +415,56 @@ public class PolyphaseChannelSourceManager extends ChannelSourceManager
@Override
public TunerChannelSource getSource(TunerChannel tunerChannel, ChannelSpecification channelSpecification)
{
if(isTunable(tunerChannel))
TunerChannelSource tunerChannelSource = null;
try
{
//Get a new set of currently tuned channels
SortedSet<TunerChannel> tunerChannels = getTunerChannels();
//Add the requested channel to the list
tunerChannels.add(tunerChannel);
if(canTune(tunerChannels))
mTunerController.getFrequencyControllerLock().lock();
if(isTunable(tunerChannel))
{
long currentCenterFrequency = mTunerController.getFrequency();
long updatedCenterFrequency = 0;
//Get a new set of currently tuned channels
SortedSet<TunerChannel> tunerChannels = getTunerChannels();
//Attempt to adjust the center frequency before we allocate the channel
try
//Add the requested channel to the list
tunerChannels.add(tunerChannel);
if(canTune(tunerChannels))
{
updatedCenterFrequency = getCenterFrequency(tunerChannels, currentCenterFrequency);
long currentCenterFrequency = mTunerController.getFrequency();
long updatedCenterFrequency = 0;
if(updatedCenterFrequency != currentCenterFrequency && updatedCenterFrequency != 0)
//Attempt to adjust the center frequency before we allocate the channel
try
{
mTunerController.setFrequency(updatedCenterFrequency);
}
updatedCenterFrequency = getCenterFrequency(tunerChannels, currentCenterFrequency);
//If we're successful to here, allocate the channel
return mPolyphaseChannelManager.getChannel(tunerChannel);
}
catch(SourceException se)
{
//Tuner controller threw an error trying to tune to the updated frequency
mLog.error("Error while updating tuner controller with new center frequency [" +
updatedCenterFrequency + "] - unable to allocate new tuner channel", se);
}
catch(IllegalArgumentException iae)
{
//Center frequency calculation failed
// mLog.debug("Couldn't calculate new tuner center frequency for new tuner channel [" +
// tunerChannel + "] unable to allocate new tuner channel");
if(updatedCenterFrequency != currentCenterFrequency && updatedCenterFrequency != 0)
{
mTunerController.setFrequency(updatedCenterFrequency);
}
//If we're successful to here, allocate the channel
tunerChannelSource = mPolyphaseChannelManager.getChannel(tunerChannel);
}
catch(SourceException se)
{
//Tuner controller threw an error trying to tune to the updated frequency
mLog.error("Error while updating tuner controller with new center frequency [" +
updatedCenterFrequency + "] - unable to allocate new tuner channel", se);
}
catch(IllegalArgumentException iae)
{
//Center frequency calculation failed
}
}
}
}
finally
{
mTunerController.getFrequencyControllerLock().unlock();
}
return null;
return tunerChannelSource;
}
/**
@@ -474,7 +481,7 @@ public class PolyphaseChannelSourceManager extends ChannelSourceManager
broadcast(sourceEvent);
//Lock the frequency and sample rate controls on the tuner controller so users can't change them
//when the polyphase manager has channels allocated
mTunerController.setLocked(getTunerChannelCount() > 0);
mTunerController.setLockedSampleRate(getTunerChannelCount() > 0);
break;
case NOTIFICATION_MEASURED_FREQUENCY_ERROR_SYNC_LOCKED:
//Rebroadcast these frequency measurement errors to the tuner and tuner controller

View File

@@ -29,6 +29,8 @@ import io.github.dsheirer.source.tuner.rtl.e4k.E4KEmbeddedTuner.E4KGain;
import io.github.dsheirer.source.tuner.rtl.e4k.E4KEmbeddedTuner.E4KLNAGain;
import io.github.dsheirer.source.tuner.rtl.e4k.E4KEmbeddedTuner.E4KMixerGain;
import io.github.dsheirer.source.tuner.ui.TunerEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,8 +43,6 @@ import javax.swing.JOptionPane;
import javax.swing.JSeparator;
import javax.swing.SpinnerNumberModel;
import javax.usb.UsbException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* E4000 tuner editor
@@ -383,7 +383,7 @@ public class E4KTunerEditor extends TunerEditor<RTL2832Tuner, E4KTunerConfigurat
*/
private void updateSampleRateToolTip()
{
if(hasTuner() && getTuner().getTunerController().isLocked())
if(hasTuner() && getTuner().getTunerController().isLockedSampleRate())
{
getSampleRateCombo().setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
}

View File

@@ -416,7 +416,7 @@ public class R820TTunerEditor extends TunerEditor<RTL2832Tuner,R820TTunerConfigu
*/
private void updateSampleRateToolTip()
{
if(hasTuner() && getTuner().getTunerController().isLocked())
if(hasTuner() && getTuner().getTunerController().isLockedSampleRate())
{
getSampleRateCombo().setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
}

View File

@@ -25,10 +25,6 @@ import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
import io.github.dsheirer.source.tuner.manager.DiscoveredUSBTuner;
import io.github.dsheirer.source.tuner.manager.IDiscoveredTunerStatusListener;
import io.github.dsheirer.source.tuner.manager.TunerStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.table.AbstractTableModel;
import java.awt.EventQueue;
import java.text.DecimalFormat;
import java.util.ArrayList;
@@ -36,6 +32,10 @@ import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.table.AbstractTableModel;
/**
* Model for discovered tuners
@@ -449,7 +449,7 @@ public class DiscoveredTunerModel extends AbstractTableModel implements Listener
if(discoveredTuner.hasTuner())
{
int channelCount = discoveredTuner.getTuner().getChannelSourceManager().getTunerChannelCount();
return channelCount + " (" + (discoveredTuner.getTuner().getTunerController().isLocked() ? "LOCKED)" : "UNLOCKED)");
return channelCount + " (" + (discoveredTuner.getTuner().getTunerController().isLockedSampleRate() ? "LOCKED)" : "UNLOCKED)");
}
else
{

View File

@@ -619,8 +619,8 @@ public abstract class TunerEditor<T extends Tuner,C extends TunerConfiguration>
{
getFrequencyControl().clearListeners();
getFrequencyControl().addListener(mFrequencyAndCorrectionChangeListener);
getFrequencyControl().setEnabled(hasTuner() && !getTuner().getTunerController().isLocked());
getTunerLockedStatusLabel().setVisible(hasTuner() && getTuner().getTunerController().isLocked());
getFrequencyControl().setEnabled(hasTuner() && !getTuner().getTunerController().isLockedSampleRate());
getTunerLockedStatusLabel().setVisible(hasTuner() && getTuner().getTunerController().isLockedSampleRate());
getFrequencyCorrectionSpinner().setEnabled(hasTuner());
getAutoPPMCheckBox().setEnabled(hasTuner());

View File

@@ -143,7 +143,7 @@ public class TunerViewPanel extends JPanel
if(selectedTuner != null && selectedTuner.hasTuner() && tunerEvent.getTuner() == selectedTuner.getTuner())
{
mDiscoveredTunerEditor.setTunerLockState(selectedTuner.getTuner().getTunerController().isLocked());
mDiscoveredTunerEditor.setTunerLockState(selectedTuner.getTuner().getTunerController().isLockedSampleRate());
}
}
}

View File

@@ -1,7 +1,6 @@
<!--
~ *******************************************************************************
~ sdrtrunk
~ Copyright (C) 2014-2018 Dennis Sheirer
~ ******************************************************************************
~ Copyright (C) 2014-2022 Dennis Sheirer
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
@@ -15,7 +14,7 @@
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>
~ ******************************************************************************
~ *****************************************************************************
-->
<configuration>
<conversionRule conversionWord="memory_usage" converterClass="io.github.dsheirer.util.MemoryUsageLogger" />
@@ -24,7 +23,7 @@
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-12(%d{HH:mm:ss.SSS}) %-5level %logger{25} - %msg %memory_usage%n</pattern>
<pattern>%-12(%d{yyyy-MM-dd HH:mm:ss.SSS}) %-5level %logger{25} - %msg %memory_usage%n</pattern>
</encoder>
</appender>