Add benchmark and batch decoding switches

This patch adds a new configure switch (--enable-benchmark) which builds a
binary suitable for measuring the modems' decoding speed.  The new
--benchmark-* switches can also be used to batch-decode audio files
if sndfile support is enabled.
pull/2/head
Stelios Bounanos 2009-02-04 05:20:24 +00:00
rodzic 3ab8df2b6c
commit f134124ddd
15 zmienionych plików z 676 dodań i 111 usunięć

Wyświetl plik

@ -126,6 +126,12 @@ AC_FLDIGI_OPT
# Substitute RDYNAMIC in Makefile
AC_FLDIGI_DEBUG
### benchmark mode
# Set ac_cv_benchmark to yes/no
# Define BENCHMARK_MODE in config.h
# Set ENABLE_BENCHMARK Makefile conditional
AC_FLDIGI_BENCHMARK
### TLS flag
# Set ac_cv_tls to yes/no
# Define USE_TLS in config.h

17
m4/benchmark.m4 100644
Wyświetl plik

@ -0,0 +1,17 @@
AC_DEFUN([AC_FLDIGI_BENCHMARK], [
AC_ARG_ENABLE([benchmark],
AC_HELP_STRING([--enable-benchmark], [build for benchmark-only operation]),
[case "${enableval}" in
yes|no) ac_cv_benchmark="${enableval}" ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-benchmark]) ;;
esac],
[ac_cv_benchmark=no])
if test "x$ac_cv_benchmark" = "xyes"; then
AC_DEFINE(BENCHMARK_MODE, 1, [Defined if we are building for benchmarking])
else
AC_DEFINE(BENCHMARK_MODE, 0, [Defined if we are building for benchmarking])
fi
AM_CONDITIONAL([ENABLE_BENCHMARK], [test "x$ac_cv_benchmark" = "xyes"])
])

Wyświetl plik

@ -24,9 +24,10 @@ HAMLIB_SRC = include/hamlib.h rigcontrol/hamlib.cxx include/rigclass.h rigcontro
XMLRPC_SRC = include/xmlrpc.h misc/xmlrpc.cxx
WIN32_RES_SRC = fldigirc.rc
LOCATOR_SRC = misc/locator.c
BENCHMARK_SRC = include/benchmark.h misc/benchmark.cxx
# We distribute these but do not always compile them
EXTRA_fldigi_SOURCES = $(HAMLIB_SRC) $(XMLRPC_SRC) $(WIN32_RES_SRC) $(LOCATOR_SRC)
EXTRA_fldigi_SOURCES = $(HAMLIB_SRC) $(XMLRPC_SRC) $(WIN32_RES_SRC) $(LOCATOR_SRC) $(BENCHMARK_SRC)
fldigi_SOURCES =
@ -48,6 +49,10 @@ if ENABLE_XMLRPC
fldigi_SOURCES += $(XMLRPC_SRC)
endif
if ENABLE_BENCHMARK
fldigi_SOURCES += $(BENCHMARK_SRC)
endif
FLDIGI_VERSION_MAJOR = @FLDIGI_VERSION_MAJOR@
FLDIGI_VERSION_MINOR = @FLDIGI_VERSION_MINOR@
FLDIGI_VERSION_PATCH = @FLDIGI_VERSION_PATCH@

Wyświetl plik

@ -112,6 +112,9 @@
#if USE_XMLRPC
# include "xmlrpc.h"
#endif
#if BENCHMARK_MODE
# include "benchmark.h"
#endif
#include "debug.h"
#include "re.h"
#include "network.h"
@ -486,6 +489,9 @@ static void default_cursor(void*)
void startup_modem(modem *m)
{
trx_start_modem(m);
#if BENCHMARK_MODE
return;
#endif
restoreFocus();
@ -574,9 +580,6 @@ void init_modem(trx_mode mode)
{
ENSURE_THREAD(FLMAIN_TID);
quick_change = 0;
modem_config_tab = tabsModems->child(0);
switch (mode) {
case MODE_NEXT:
if ((mode = active_modem->get_mode() + 1) == NUM_MODES)
@ -691,6 +694,13 @@ void init_modem(trx_mode mode)
return init_modem(MODE_BPSK31);
}
#if BENCHMARK_MODE
return;
#endif
quick_change = 0;
modem_config_tab = tabsModems->child(0);
clear_StatusMessages();
progStatus.lastmode = mode;
@ -2907,6 +2917,14 @@ void set_zdata(complex *zarray, int len)
void put_rx_char(unsigned int data)
{
#if BENCHMARK_MODE
if (!benchmark.output.empty()) {
if (unlikely(benchmark.buffer.length() + 16 > benchmark.buffer.capacity()))
benchmark.buffer.reserve(benchmark.buffer.capacity() + BUFSIZ);
benchmark.buffer += (char)data;
}
return;
#endif
static unsigned int last = 0;
const char **asc = ascii;
trx_mode mode = active_modem->get_mode();

Wyświetl plik

@ -0,0 +1,22 @@
#ifndef BENCHMARK_H_
#define BENCHMARK_H_
#include <string>
#include <sys/types.h>
struct benchmark_params {
trx_mode modem;
int freq;
bool afc, sql;
double sqlevel;
double src_ratio;
int src_type;
std::string input, output, buffer;
size_t samples;
};
extern struct benchmark_params benchmark;
int setup_benchmark(void);
void do_benchmark(void);
#endif

Wyświetl plik

@ -1,6 +1,7 @@
#ifndef _MAIN_H
#define _MAIN_H
#include <config.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>

Wyświetl plik

@ -156,6 +156,13 @@ public:
extern qrunner *cbq[NUM_QRUNNER_THREADS];
#if BENCHMARK_MODE
#define REQ(...) ((void)0)
#define REQ_DROP(...) ((void)0)
#define REQ_SYNC(...) ((void)0)
#define REQ_FLUSH(...) ((void)0)
#define QRUNNER_DROP(...) ((void)0)
#else
#define REQ REQ_ASYNC
#define REQ_DROP REQ_ASYNC_DROP
@ -212,6 +219,7 @@ extern qrunner *cbq[NUM_QRUNNER_THREADS];
if ((GET_THREAD_ID() != FLMAIN_TID)) \
cbq[GET_THREAD_ID()]->drop_flag = v_; \
} while (0)
#endif // BENCHMARK_MODE
#endif // QRUNNER_H_

Wyświetl plik

@ -3,6 +3,7 @@
#include <config.h>
#include <time.h>
#include <sys/time.h>
#if !HAVE_CLOCK_GETTIME
enum clockid_t { CLOCK_REALTIME, CLOCK_MONOTONIC };
@ -13,7 +14,14 @@ int clock_gettime(clockid_t clock_id, struct timespec* tp);
struct timespec operator+(const struct timespec &t0, const double &t);
struct timespec operator-(const struct timespec &t0, const struct timespec &t1);
struct timespec& operator-=(struct timespec &t0, const struct timespec &t1);
bool operator>(const struct timespec &t0, const struct timespec &t1);
bool operator==(const struct timespec &t0, const struct timespec &t1);
struct timeval operator+(const struct timeval &t0, const double &t);
struct timeval operator-(const struct timeval &t0, const struct timeval &t1);
struct timeval& operator-=(struct timeval &t0, const struct timeval &t1);
bool operator>(const struct timeval &t0, const struct timeval &t1);
bool operator==(const struct timeval &t0, const struct timeval &t1);
#endif // TIMEOPS_H_

Wyświetl plik

@ -85,6 +85,10 @@
#include "xmlrpc.h"
#endif
#if BENCHMARK_MODE
#include "benchmark.h"
#endif
using namespace std;
string appname;
@ -253,6 +257,11 @@ int main(int argc, char ** argv)
Fl::scheme(progdefaults.ui_scheme.c_str());
create_fl_digi_main();
#if BENCHMARK_MODE
return setup_benchmark();
#endif
FSEL::create();
createConfig();
@ -372,6 +381,45 @@ void generate_option_help(void) {
<< " List all available methods\n\n"
#endif
#if BENCHMARK_MODE
<< " --benchmark-modem ID\n"
<< " Specify the modem\n"
<< " Default: " << mode_info[benchmark.modem].sname << "\n\n"
<< " --benchmark-frequency FREQ\n"
<< " Specify the modem frequency\n"
<< " Default: " << benchmark.freq << "\n\n"
<< " --benchmark-afc BOOLEAN\n"
<< " Set modem AFC\n"
<< " Default: " << benchmark.afc
<< " (" << boolalpha << benchmark.afc << noboolalpha << ")\n\n"
<< " --benchmark-squelch BOOLEAN\n"
<< " Set modem squelch\n"
<< " Default: " << benchmark.sql
<< " (" << boolalpha << benchmark.sql << noboolalpha << ")\n\n"
<< " --benchmark-squelch-level LEVEL\n"
<< " Set modem squelch level\n"
<< " Default: " << benchmark.sqlevel << " (%)\n\n"
<< " --benchmark-input INPUT\n"
<< " Specify the input\n"
<< " Must be a positive integer indicating the number of samples\n"
" of silence to generate as the input"
# if USE_SNDFILE
", or a filename containing\n"
" non-digit characters"
#endif
"\n\n"
<< " --benchmark-output FILE\n"
<< " Specify the output data file\n"
<< " Default: decoder output is discarded\n\n"
<< " --benchmark-src-ratio RATIO\n"
<< " Specify the sample rate conversion ratio\n"
<< " Default: 1.0 (input is not resampled)\n\n"
<< " --benchmark-src-type TYPE\n"
<< " Specify the sample rate conversion type\n"
<< " Default: " << benchmark.src_type << " (" << src_get_name(benchmark.src_type) << ")\n\n"
#endif
<< " --debug-level LEVEL\n"
<< " Set the event log verbosity\n\n"
@ -448,6 +496,13 @@ int parse_args(int argc, char **argv, int& idx)
OPT_CONFIG_XMLRPC_ADDRESS, OPT_CONFIG_XMLRPC_PORT,
OPT_CONFIG_XMLRPC_ALLOW, OPT_CONFIG_XMLRPC_DENY, OPT_CONFIG_XMLRPC_LIST,
#endif
#if BENCHMARK_MODE
OPT_BENCHMARK_MODEM, OPT_BENCHMARK_AFC, OPT_BENCHMARK_SQL, OPT_BENCHMARK_SQLEVEL,
OPT_BENCHMARK_FREQ, OPT_BENCHMARK_INPUT, OPT_BENCHMARK_OUTPUT,
OPT_BENCHMARK_SRC_RATIO, OPT_BENCHMARK_SRC_TYPE,
#endif
OPT_FONT, OPT_WFALL_HEIGHT, OPT_WFALL_WIDTH,
OPT_WINDOW_WIDTH, OPT_WINDOW_HEIGHT,
// OPT_TOGGLE_CHECK,
@ -478,6 +533,19 @@ int parse_args(int argc, char **argv, int& idx)
{ "xmlrpc-deny", 1, 0, OPT_CONFIG_XMLRPC_DENY },
{ "xmlrpc-list", 0, 0, OPT_CONFIG_XMLRPC_LIST },
#endif
#if BENCHMARK_MODE
{ "benchmark-modem", 1, 0, OPT_BENCHMARK_MODEM },
{ "benchmark-frequency", 1, 0, OPT_BENCHMARK_FREQ },
{ "benchmark-afc", 1, 0, OPT_BENCHMARK_AFC },
{ "benchmark-squelch", 1, 0, OPT_BENCHMARK_SQL },
{ "benchmark-squelch-level", 1, 0, OPT_BENCHMARK_SQLEVEL },
{ "benchmark-input", 1, 0, OPT_BENCHMARK_INPUT },
{ "benchmark-output", 1, 0, OPT_BENCHMARK_OUTPUT },
{ "benchmark-src-ratio", 1, 0, OPT_BENCHMARK_SRC_RATIO },
{ "benchmark-src-type", 1, 0, OPT_BENCHMARK_SRC_TYPE },
#endif
{ "font", 1, 0, OPT_FONT },
{ "wfall-width", 1, 0, OPT_WFALL_WIDTH },
@ -564,6 +632,52 @@ int parse_args(int argc, char **argv, int& idx)
exit(EXIT_SUCCESS);
#endif
#if BENCHMARK_MODE
case OPT_BENCHMARK_MODEM:
benchmark.modem = strtol(optarg, NULL, 10);
if (!(benchmark.modem >= 0 && benchmark.modem < NUM_MODES)) {
cerr << "Bad modem id\n";
exit(EXIT_FAILURE);
}
break;
case OPT_BENCHMARK_FREQ:
benchmark.freq = strtol(optarg, NULL, 10);
if (benchmark.freq < 0) {
cerr << "Bad frequency\n";
exit(EXIT_FAILURE);
}
break;
case OPT_BENCHMARK_AFC:
benchmark.afc = strtol(optarg, NULL, 10);
break;
case OPT_BENCHMARK_SQL:
benchmark.sql = strtol(optarg, NULL, 10);
break;
case OPT_BENCHMARK_SQLEVEL:
benchmark.sqlevel = strtod(optarg, NULL);
break;
case OPT_BENCHMARK_INPUT:
benchmark.input = optarg;
break;
case OPT_BENCHMARK_OUTPUT:
benchmark.output = optarg;
break;
case OPT_BENCHMARK_SRC_RATIO:
benchmark.src_ratio = strtod(optarg, NULL);
break;
case OPT_BENCHMARK_SRC_TYPE:
benchmark.src_type = strtol(optarg, NULL, 10);
break;
#endif
case OPT_FONT:
{
char *p;

Wyświetl plik

@ -0,0 +1,281 @@
// ----------------------------------------------------------------------------
// benchmark.cxx
//
// Copyright (C) 2009
// Stelios Bounanos, M0GLD
//
// This file is part of fldigi.
//
// fldigi 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.
//
// fldigi 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/>.
// ----------------------------------------------------------------------------
#include <config.h>
#include <fstream>
#include <string>
#include <cstdio>
#include <cstring>
#include <inttypes.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <time.h>
#if USE_SNDFILE
# include <sndfile.h>
#endif
#include "modem.h"
#include "trx.h"
#include "timeops.h"
#include "configuration.h"
#include "status.h"
#include "debug.h"
#include "benchmark.h"
struct benchmark_params benchmark = { MODE_BPSK31, 1000, false, false, 0.0, 1.0, SRC_SINC_FASTEST };
int setup_benchmark(void)
{
ENSURE_THREAD(FLMAIN_TID);
if (benchmark.input.empty()) {
LOG_ERROR("Missing input");
return 1;
}
else {
char* p;
benchmark.samples = (size_t)strtol(benchmark.input.c_str(), &p, 10);
if (*p != '\0') { // invalid char in input string
#if USE_SNDFILE
// treat as filename
benchmark.samples = 0;
#else
LOG_ERROR("Bad input string, \"%s\"", benchmark.input.c_str());
return 1;
#endif
}
}
if (!benchmark.output.empty())
benchmark.buffer.reserve(BUFSIZ);
progdefaults.rsid = false;
progdefaults.StartAtSweetSpot = false;
if (benchmark.modem != NUM_MODES)
progStatus.lastmode = benchmark.modem;
if (benchmark.freq)
progStatus.carrier = benchmark.freq;
progStatus.afconoff = benchmark.afc;
progStatus.sqlonoff = benchmark.sql;
progStatus.sldrSquelchValue = benchmark.sqlevel;
debug::level = debug::INFO_LEVEL;
TRX_WAIT(STATE_ENDED, trx_start(); init_modem(progStatus.lastmode));
if (!benchmark.output.empty()) {
ofstream out(benchmark.output.c_str());
if (out)
out << benchmark.buffer;
}
return 0;
}
#if USE_SNDFILE
SNDFILE* infile = 0;
#endif
static size_t do_rx(struct rusage ru[2], struct timespec wall_time[2]);
static size_t do_rx_src(struct rusage ru[2], struct timespec wall_time[2]);
void do_benchmark(void)
{
ENSURE_THREAD(TRX_TID);
if (benchmark.src_ratio != 1.0)
LOG_INFO("modem=%" PRIdPTR " (%s) rate=%d ratio=%f converter=%d (\"%s\")",
active_modem->get_mode(), mode_info[active_modem->get_mode()].sname,
active_modem->get_samplerate(),
benchmark.src_ratio, benchmark.src_type, src_get_name(benchmark.src_type));
else
LOG_INFO("modem=%" PRIdPTR " (%s) rate=%d", active_modem->get_mode(),
mode_info[active_modem->get_mode()].sname, active_modem->get_samplerate());
#if USE_SNDFILE
if (!benchmark.samples) {
SF_INFO info = { 0, 0, 0, 0, 0, 0 };
if ((infile = sf_open(benchmark.input.c_str(), SFM_READ, &info)) == NULL) {
LOG_ERROR("Could not open input file \"%s\"", benchmark.input.c_str());
return;
}
}
#endif
struct rusage ru[2];
struct timespec wall_time[2];
size_t nproc, nrx;
if (benchmark.src_ratio == 1.0)
nrx = nproc = do_rx(ru, wall_time);
else {
nproc = do_rx_src(ru, wall_time);
nrx = (size_t)(nproc * benchmark.src_ratio);
}
ru[1].ru_utime -= ru[0].ru_utime;
wall_time[1] -= wall_time[0];
#if USE_SNDFILE
if (infile) {
sf_close(infile);
infile = 0;
}
#endif
LOG_INFO("processed: %zu samples (decoded %zu) in %.3f seconds", nproc, nrx,
wall_time[1].tv_sec + wall_time[1].tv_nsec / 1e9);
double speed = nproc / (ru[1].ru_utime.tv_sec + ru[1].ru_utime.tv_usec / 1e6);
LOG_INFO("cpu time : %jd.%03jd; speed=%.3f samples/s; factor=%.3f",
(intmax_t)ru[1].ru_utime.tv_sec, (intmax_t)ru[1].ru_utime.tv_usec / 1000,
speed, speed / active_modem->get_samplerate());
}
// -----------------------------------------------------------------------------
static size_t do_rx(struct rusage ru[2], struct timespec wall_time[2])
{
size_t nread;
size_t inlen = 1 << 19;
double* inbuf = new double[inlen];
#if USE_SNDFILE
if (infile) {
nread = 0;
clock_gettime(CLOCK_MONOTONIC, &wall_time[0]);
getrusage(RUSAGE_SELF, &ru[0]);
for (size_t n; (n = sf_readf_double(infile, inbuf, inlen)); nread += n)
active_modem->rx_process(inbuf, n);
}
else
#endif
{
memset(inbuf, 0, sizeof(double) * inlen);
clock_gettime(CLOCK_MONOTONIC, &wall_time[0]);
getrusage(RUSAGE_SELF, &ru[0]);
for (nread = benchmark.samples; nread > inlen; nread -= inlen)
active_modem->rx_process(inbuf, inlen);
if (nread)
active_modem->rx_process(inbuf, nread);
nread = benchmark.samples;
}
getrusage(RUSAGE_SELF, &ru[1]);
clock_gettime(CLOCK_MONOTONIC, &wall_time[1]);
delete [] inbuf;
return nread;
}
size_t inlen = 1 << 19;
static float* inbuf = 0;
static long src_read(void* arg, float** data)
{
*data = inbuf;
return inlen;
}
#if USE_SNDFILE
static long src_readf(void* arg, float** data)
{
long n = (long)sf_readf_float(infile, inbuf, inlen);
*data = n ? inbuf : 0;
return n;
}
#endif
static size_t do_rx_src(struct rusage ru[2], struct timespec wall_time[2])
{
int err;
SRC_STATE* src_state;
#if USE_SNDFILE
if (infile)
src_state = src_callback_new(src_readf, benchmark.src_type, 1, &err, NULL);
else
#endif
src_state = src_callback_new(src_read, benchmark.src_type, 1, &err, NULL);
if (!src_state) {
LOG_ERROR("src_callback_new error %d: %s", err, src_strerror(err));
return 0;
}
inbuf = new float[inlen];
size_t outlen = (size_t)floor(inlen * benchmark.src_ratio);
float* outbuf = new float[outlen];
double* rxbuf = new double[outlen];
long n;
size_t nread;
#if USE_SNDFILE
if (infile) { // read until src returns 0
nread = 0;
clock_gettime(CLOCK_MONOTONIC, &wall_time[0]);
getrusage(RUSAGE_SELF, &ru[0]);
while ((n = src_callback_read(src_state, benchmark.src_ratio, outlen, outbuf))) {
for (long i = 0; i < n; i++)
rxbuf[i] = outbuf[i];
active_modem->rx_process(rxbuf, n);
nread += n;
}
nread = (size_t)round(nread * benchmark.src_ratio);
}
else
#endif
{ // read benchmark.samples * benchmark.src_ratio
nread = (size_t)round(benchmark.samples * benchmark.src_ratio);
clock_gettime(CLOCK_MONOTONIC, &wall_time[0]);
getrusage(RUSAGE_SELF, &ru[0]);
while (nread > outlen) {
if ((n = src_callback_read(src_state, benchmark.src_ratio, outlen, outbuf)) == 0)
break;
for (long i = 0; i < n; i++)
rxbuf[i] = outbuf[i];
active_modem->rx_process(rxbuf, n);
nread -= (size_t)n;
}
if (nread) {
if ((n = src_callback_read(src_state, benchmark.src_ratio, nread, outbuf))) {
for (long i = 0; i < n; i++)
rxbuf[i] = outbuf[i];
active_modem->rx_process(rxbuf, n);
}
}
nread = benchmark.samples;
}
getrusage(RUSAGE_SELF, &ru[1]);
clock_gettime(CLOCK_MONOTONIC, &wall_time[1]);
delete [] inbuf;
delete [] outbuf;
delete [] rxbuf;
return nread;
}

Wyświetl plik

@ -305,9 +305,7 @@ void status::initLastState()
if (!bLastStateRead)
loadLastState();
init_modem(lastmode);
while (!active_modem) MilliSleep(100);
init_modem_sync(lastmode);
wf->opmode();
wf->Mag(mag);

Wyświetl plik

@ -68,6 +68,18 @@ struct timespec operator-(const struct timespec &t0, const struct timespec &t1)
return r;
}
struct timespec& operator-=(struct timespec &t0, const struct timespec &t1)
{
if (t0.tv_nsec < t1.tv_nsec) {
--t0.tv_sec;
t0.tv_nsec += 1000000000L;
}
t0.tv_sec -= t1.tv_sec;
t0.tv_nsec -= t1.tv_nsec;
return t0;
}
bool operator>(const struct timespec &t0, const struct timespec &t1)
{
if (t0.tv_sec == t1.tv_sec)
@ -82,3 +94,57 @@ bool operator==(const struct timespec &t0, const struct timespec &t1)
{
return t0.tv_sec == t1.tv_sec && t0.tv_nsec == t1.tv_nsec;
}
struct timeval operator+(const struct timeval &t0, const double &t)
{
struct timeval r;
r.tv_sec = t0.tv_sec + static_cast<time_t>(t);
r.tv_usec = t0.tv_usec + static_cast<suseconds_t>((t - static_cast<time_t>(t)) * 1e9);
if (r.tv_usec > 1000000) {
r.tv_usec -= 1000000;
r.tv_sec++;
}
return r;
}
struct timeval operator-(const struct timeval &t0, const struct timeval &t1)
{
struct timeval r = t0;
if (r.tv_usec < t1.tv_usec) {
--r.tv_sec;
r.tv_usec += 1000000;
}
r.tv_sec -= t1.tv_sec;
r.tv_usec -= t1.tv_usec;
return r;
}
struct timeval& operator-=(struct timeval &t0, const struct timeval &t1)
{
if (t0.tv_usec < t1.tv_usec) {
--t0.tv_sec;
t0.tv_usec += 1000000L;
}
t0.tv_sec -= t1.tv_sec;
t0.tv_usec -= t1.tv_usec;
return t0;
}
bool operator>(const struct timeval &t0, const struct timeval &t1)
{
if (t0.tv_sec == t1.tv_sec)
return t0.tv_usec > t1.tv_usec;
else if (t0.tv_sec > t1.tv_sec)
return true;
else
return false;
}
bool operator==(const struct timeval &t0, const struct timeval &t1)
{
return t0.tv_sec == t1.tv_sec && t0.tv_usec == t1.tv_usec;
}

Wyświetl plik

@ -1829,17 +1829,19 @@ size_t SoundNull::Write_stereo(double* bufleft, double* bufright, size_t count)
size_t SoundNull::Read(double *buf, size_t count)
{
memset(buf, 0, count * sizeof(*buf));
#if USE_SNDFILE
if (capture)
write_file(ofCapture, buf, count);
if (playback) {
read_file(ifPlayback, buf, count);
if (progdefaults.EnableMixer)
for (size_t i = 0; i < count; i++)
buf[i] *= progStatus.RcvMixer;
}
else
#endif
memset(buf, 0, count * sizeof(*buf));
#if USE_SNDFILE
if (capture)
write_file(ofCapture, buf, count);
#endif
usleep((useconds_t)ceil((1e6 * count) / sample_frequency));

Wyświetl plik

@ -111,8 +111,10 @@ void modem::init()
else
set_freq(progdefaults.PSKsweetspot);
} else if (progStatus.carrier != 0) {
set_freq(progStatus.carrier);
progStatus.carrier = 0;
set_freq(progStatus.carrier);
#if !BENCHMARK_MODE
progStatus.carrier = 0;
#endif
} else
set_freq(wf->Carrier());
}

Wyświetl plik

@ -47,6 +47,10 @@
#include "qrunner.h"
#include "debug.h"
#if BENCHMARK_MODE
# include "benchmark.h"
#endif
LOG_SET_SOURCE(debug::LOG_MODEM);
using namespace std;
@ -96,118 +100,127 @@ void trx_trx_receive_loop()
int current_samplerate;
assert(powerof2(SCBLOCKSIZE));
if (!scard) {
if (unlikely(!active_modem)) {
MilliSleep(10);
return;
}
if (active_modem) {
try {
current_samplerate = active_modem->get_samplerate();
if (scard->Open(O_RDONLY, current_samplerate))
REQ(sound_update, progdefaults.btnAudioIOis);
}
catch (const SndException& e) {
LOG_ERROR("%s", e.what());
put_status(e.what(), 5);
scard->Close();
if (e.error() == EBUSY && progdefaults.btnAudioIOis == SND_IDX_PORT) {
sound_close();
sound_init();
}
MilliSleep(1000);
return;
}
active_modem->rx_init();
while (1) {
if (progdefaults.rsid == true && rsid_detecting == false) {
rsid_detecting = true;
try {
current_samplerate = ReedSolomon->samplerate();
scard->Open(O_RDONLY, current_samplerate);
}
catch (const SndException& e) {
LOG_ERROR("%s", e.what());
put_status(e.what(), 5);
scard->Close();
if (e.error() == EBUSY && progdefaults.btnAudioIOis == SND_IDX_PORT) {
sound_close();
sound_init();
}
MilliSleep(1000);
return;
}
}
if (progdefaults.rsid == false && rsid_detecting == true) {
rsid_detecting = false;
active_modem->rx_init();
try {
current_samplerate = active_modem->get_samplerate();
scard->Open(O_RDONLY, current_samplerate);
}
catch (const SndException& e) {
LOG_ERROR("%s", e.what());
put_status(e.what(), 5);
scard->Close();
if (e.error() == EBUSY && progdefaults.btnAudioIOis == SND_IDX_PORT) {
sound_close();
sound_init();
}
MilliSleep(1000);
return;
}
}
// If we change to an 8000Hz modem while RSID is on we'll never detect anything.
// Toggle rsid_detecting so that the audio device is reopened with the ReedSolomon
// samplerate in the next loop iteration.
if (progdefaults.rsid && rsid_detecting && current_samplerate != ReedSolomon->samplerate())
rsid_detecting = false;
#if BENCHMARK_MODE
do_benchmark();
trx_state = STATE_ENDED;
return;
#endif
if (unlikely(!scard)) {
MilliSleep(10);
return;
}
try {
current_samplerate = active_modem->get_samplerate();
if (scard->Open(O_RDONLY, current_samplerate))
REQ(sound_update, progdefaults.btnAudioIOis);
}
catch (const SndException& e) {
LOG_ERROR("%s", e.what());
put_status(e.what(), 5);
scard->Close();
if (e.error() == EBUSY && progdefaults.btnAudioIOis == SND_IDX_PORT) {
sound_close();
sound_init();
}
MilliSleep(1000);
return;
}
active_modem->rx_init();
while (1) {
if (progdefaults.rsid == true && rsid_detecting == false) {
rsid_detecting = true;
try {
if (trxrb.write_space() == 0) // discard some old data
trxrb.read_advance(SCBLOCKSIZE);
trxrb.get_wv(rbvec);
numread = 0;
while (numread < SCBLOCKSIZE && trx_state == STATE_RX)
numread += scard->Read(rbvec[0].buf + numread, SCBLOCKSIZE - numread);
current_samplerate = ReedSolomon->samplerate();
scard->Open(O_RDONLY, current_samplerate);
}
catch (const SndException& e) {
scard->Close();
LOG_ERROR("%s", e.what());
put_status(e.what(), 5);
MilliSleep(10);
scard->Close();
if (e.error() == EBUSY && progdefaults.btnAudioIOis == SND_IDX_PORT) {
sound_close();
sound_init();
}
MilliSleep(1000);
return;
}
if (trx_state != STATE_RX)
break;
trxrb.write_advance(numread);
REQ(&waterfall::sig_data, wf, rbvec[0].buf, numread, current_samplerate);
if (!bHistory) {
if (rsid_detecting == true)
ReedSolomon->search(rbvec[0].buf, numread);
else
active_modem->rx_process(rbvec[0].buf, numread);
}
if (progdefaults.rsid == false && rsid_detecting == true) {
rsid_detecting = false;
active_modem->rx_init();
try {
current_samplerate = active_modem->get_samplerate();
scard->Open(O_RDONLY, current_samplerate);
}
else {
bool afc = progStatus.afconoff;
progStatus.afconoff = false;
QRUNNER_DROP(true);
active_modem->HistoryON(true);
trxrb.get_rv(rbvec);
if (rbvec[0].len)
active_modem->rx_process(rbvec[0].buf, rbvec[0].len);
if (rbvec[1].len)
active_modem->rx_process(rbvec[1].buf, rbvec[1].len);
QRUNNER_DROP(false);
progStatus.afconoff = afc;
bHistory = false;
active_modem->HistoryON(false);
catch (const SndException& e) {
LOG_ERROR("%s", e.what());
put_status(e.what(), 5);
scard->Close();
if (e.error() == EBUSY && progdefaults.btnAudioIOis == SND_IDX_PORT) {
sound_close();
sound_init();
}
MilliSleep(1000);
return;
}
}
} else
MilliSleep(10);
// If we change to an 8000Hz modem while RSID is on we'll never detect anything.
// Toggle rsid_detecting so that the audio device is reopened with the ReedSolomon
// samplerate in the next loop iteration.
if (progdefaults.rsid && rsid_detecting && current_samplerate != ReedSolomon->samplerate())
rsid_detecting = false;
try {
if (trxrb.write_space() == 0) // discard some old data
trxrb.read_advance(SCBLOCKSIZE);
trxrb.get_wv(rbvec);
numread = 0;
while (numread < SCBLOCKSIZE && trx_state == STATE_RX)
numread += scard->Read(rbvec[0].buf + numread, SCBLOCKSIZE - numread);
}
catch (const SndException& e) {
scard->Close();
LOG_ERROR("%s", e.what());
put_status(e.what(), 5);
MilliSleep(10);
return;
}
if (trx_state != STATE_RX)
break;
trxrb.write_advance(numread);
REQ(&waterfall::sig_data, wf, rbvec[0].buf, numread, current_samplerate);
if (!bHistory) {
if (rsid_detecting == true)
ReedSolomon->search(rbvec[0].buf, numread);
else
active_modem->rx_process(rbvec[0].buf, numread);
}
else {
bool afc = progStatus.afconoff;
progStatus.afconoff = false;
QRUNNER_DROP(true);
active_modem->HistoryON(true);
trxrb.get_rv(rbvec);
if (rbvec[0].len)
active_modem->rx_process(rbvec[0].buf, rbvec[0].len);
if (rbvec[1].len)
active_modem->rx_process(rbvec[1].buf, rbvec[1].len);
QRUNNER_DROP(false);
progStatus.afconoff = afc;
bHistory = false;
active_modem->HistoryON(false);
}
}
}
@ -338,6 +351,8 @@ void *trx_loop(void *args)
delete scard;
scard = 0;
trx_state = STATE_ENDED;
// fall through
case STATE_ENDED:
return 0;
case STATE_RESTART:
trx_reset_loop();
@ -474,6 +489,7 @@ void trx_start_macro_timer()
//=============================================================================
void trx_start(void)
{
#if !BENCHMARK_MODE
if (trxrunning) {
LOG(debug::ERROR_LEVEL, debug::LOG_MODEM, "trx already running!");
return;
@ -507,7 +523,8 @@ void trx_start(void)
}
ReedSolomon = new cRsId;
#endif // !BENCHMARK_MODE
trx_state = STATE_RX;
_trx_tune = 0;
active_modem = 0;