Implemented simple cmd app.

master
Hannes Matuschek 11 years ago
parent 28b907dd9a
commit 7c5cfb2019

@ -6,6 +6,7 @@ include(InstallHeadersWithDirectory)
OPTION(BUILD_EXAMPLES "Build examples" OFF)
OPTION(BUILD_UNIT_TESTS "Build unit tests" OFF)
OPTION(BUILD_COMMANDLINETOOL "Build command line tool" ON)
SET(libsdr_VERSION_MAJOR "0")
SET(libsdr_VERSION_MINOR "1")
@ -84,13 +85,19 @@ ENDIF(UNIX AND APPLE)
# Add core library, and unit tests
add_subdirectory(src)
IF(BUILD_UNIT_TESTS)
add_subdirectory(test)
ENDIF(BUILD_UNIT_TESTS)
IF(BUILD_EXAMPLES)
add_subdirectory(examples)
ENDIF(BUILD_EXAMPLES)
IF(BUILD_COMMANDLINETOOL)
add_subdirectory(cmd)
endif(BUILD_COMMANDLINETOOL)
# Source distribution packages:
set(CPACK_PACKAGE_VERSION_MAJOR ${libsdr_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${libsdr_VERSION_MINOR})

@ -0,0 +1,2 @@
add_executable(sdr_cmd main.cc)
target_link_libraries(sdr_cmd ${LIBS} libsdr)

@ -0,0 +1,225 @@
#include "options.hh"
#include "queue.hh"
#include "logger.hh"
#include "wavfile.hh"
#include "autocast.hh"
#include "portaudio.hh"
#include "rtlsource.hh"
#include "baseband.hh"
#include "demod.hh"
#include <iostream>
#include <csignal>
using namespace sdr;
// On SIGINT -> stop queue properly
static void __sigint_handler(int signo) {
Queue::get().stop();
}
// Command line options
static Options::Definition options[] = {
{"rtl2832", 'R', Options::FLOAT,
"Specifies a RTL2832 USB dongle as the input source"},
{"rtl-device", 0, Options::INTEGER,
"Specifies the RTL2832 device index. (default 0)"},
{"disable-rtl-agc", 0 , Options::FLAG,
"Disables the IF AGC of the RTL2832 device, default on."},
{"rtl-agc-gain", 0, Options::INTEGER,
"In conjecture with --disable-rtl-agc, specifies the fixed IF gain of the RTL2832 device."},
{"rtl-ppm", 0, Options::FLOAT,
"Specifies the frequency correction for the RTL2832 device in parts-per-million (ppm)."},
{"audio", 'a', Options::FLAG,
"Specifies the system audio as the input source."},
{"audio-iq", 'a', Options::FLAG,
"Specifies the system audio as the input source (I/Q channels)."},
{"source-rate", 0, Options::FLOAT,
"Specifies the sample rate of the input device."},
{"file", 'f', Options::ANY,
"Specifies a WAV file as input source."},
{"demod", 'd', Options::ANY,
"Specifies the demodulator (wfm, nfm, am, usb, lsb)."},
{"demod-offset", 0, Options::FLOAT,
"Specifies the reception offset in Hz. (default 0)"},
{"loglevel", 0, Options::INTEGER,
"Specifies the log-level. 0 = DEBUG, 1 = INFO, 2 = WARNING, 3 = ERROR."},
{"help", '?', Options::FLAG,
"Prints this help."},
{0,0,Options::FLAG,0}
};
void print_help() {
std::cerr << "USAGE: sdr_cmd SOURCE [OPTIONS] OUTPUT" << std::endl << std::endl;
Options::print_help(std::cerr, options);
}
int main(int argc, char *argv[]) {
// Parse command line options.
Options opts;
if (! Options::parse(options, argc, argv, opts)) {
print_help(); return -1;
}
// If help flag is present -> print and done.
if (opts.has("help")) { print_help(); return 0; }
// Install log-handler
LogLevel loglevel = LOG_INFO;
if (opts.has("loglevel")) {
if (0 >= opts.get("loglevel").toInteger()) { loglevel = LOG_DEBUG; }
else if (1 >= opts.get("loglevel").toInteger()) { loglevel = LOG_INFO; }
else if (2 >= opts.get("loglevel").toInteger()) { loglevel = LOG_WARNING; }
else { loglevel = LOG_ERROR; }
}
sdr::Logger::get().addHandler(
new sdr::StreamLogHandler(std::cerr, loglevel));
// If no source has been selected -> error
if (! (opts.has("rtl2832")|opts.has("audio")|opts.has("file"))) {
std::cerr << "No source has been selected!" << std::endl;
print_help(); return -1;
}
// If no demodulator has been selected.
if (!opts.has("demod")) {
std::cerr << "No demodulator has been selected!" << std::endl;
print_help(); return -1;
}
double bbFc = 0, bbFf = 0, bbFw = 0, bbFs = 0;
// Configure baseband node depending on the selected demodulator
if ("wfm" == opts.get("demod").toString()) {
bbFw = 100e3; bbFs = 100e3;
} else if ("nfm" == opts.get("demod").toString()) {
bbFw = 12.5e3; bbFs = 22.05e3;
} else if ("am" == opts.get("demod").toString()) {
bbFw = 10.0e3; bbFs = 22.05e3;
} else if ("usb" == opts.get("demod").toString()) {
bbFf = 1.5e3; bbFw = 3e3; bbFs = 22.05e3;
} else if ("lsb" == opts.get("demod").toString()) {
bbFf = -1.5e3; bbFw = 3e3; bbFs = 22.05e3;
} else {
std::cerr << "Unknown demodulator '" << opts.get("demod").toString() << "'." << std::endl;
print_help(); return -1;
}
// Register signal handler to stop queue on SIGINT
signal(SIGINT, __sigint_handler);
// Init audio system
PortAudio::init();
// Get the global queue
Queue &queue = Queue::get();
// reference to selected source node
Source *source = 0;
// Nodes for file input
WavSource *wav_src=0;
AutoCast< std::complex<int16_t> > *wav_cast=0;
// nodes for real audio input
PortSource<int16_t> *raudio_src=0;
AutoCast< std::complex<int16_t> > *raudio_cast=0;
// nodes for IQ audio input
PortSource< std::complex<int16_t> > *iqaudio_src=0;
// nodes for RTL2832 input
RTLSource *rtl_source=0;
AutoCast< std::complex<int16_t> > *rtl_cast=0;
/* Demodulator nodes. */
Source *demod = 0;
FMDemod<int16_t> *fm_demod = 0;
FMDeemph<int16_t> *fm_deemph = 0;
AMDemod<int16_t> *am_demod = 0;
USBDemod<int16_t> *ssb_demod = 0;
// Dispatch by selected source
if (opts.has("rtl2832")) {
// Instantiate & config RTL2832 node
size_t devIdx = 0;
double sampleRate = 1e6;
if (opts.has("rtl-device")) { devIdx = opts.get("rtl-device").toInteger(); }
if (opts.has("source-rate")) { sampleRate = opts.get("source-rate").toFloat(); }
rtl_source = new RTLSource(opts.get("rtl2832").toFloat(), sampleRate, devIdx);
if (opts.has("rtl-disable-agc")) { rtl_source->enableAGC(false); }
if (opts.has("rtl-gain")) { rtl_source->setGain(opts.get("rtl-gain").toFloat()); }
if (opts.has("rtl-ppm")) { rtl_source->setFreqCorrection(opts.get("rtl-ppm").toFloat()); }
rtl_cast = new AutoCast< std::complex<int16_t> >();
rtl_source->connect(rtl_cast);
source = rtl_cast;
// Connect start & stop event to RTL2832 device
queue.addStart(rtl_source, &RTLSource::start);
queue.addStop(rtl_source, &RTLSource::stop);
} else if (opts.has("audio")) {
double sampleRate = 44100;
if (opts.has("source-rate")) { sampleRate = opts.get("source-rate").toFloat(); }
raudio_src = new PortSource<int16_t>(sampleRate, 1024);
raudio_cast = new AutoCast< std::complex<int16_t> >();
source = raudio_cast;
// Connect idle event to source
queue.addIdle(raudio_src, &PortSource<int16_t>::next);
} else if (opts.has("audio-iq")) {
double sampleRate = 44100;
if (opts.has("source-rate")) { sampleRate = opts.get("source-rate").toFloat(); }
iqaudio_src = new PortSource< std::complex<int16_t> >(sampleRate, 1024);
source = iqaudio_src;
// Connect idle event to source
queue.addIdle(iqaudio_src, &PortSource< std::complex<int16_t> >::next);
}
// Shift baseband by offset
if (opts.has("demod-offset")) {
bbFc += opts.get("demod-offset").toFloat();
bbFf += opts.get("demod-offset").toFloat();
}
IQBaseBand< int16_t > baseband(bbFc, bbFf, bbFw, 31, 0, bbFs);
source->connect(&baseband, true);
// Dispatch by selected demodulator
if (("wfm" == opts.get("demod").toString()) || ("nfm" == opts.get("demod").toString())) {
fm_demod = new FMDemod<int16_t>();
fm_deemph = new FMDeemph<int16_t>();
source->connect(fm_demod, true);
fm_demod->connect(fm_deemph, true);
demod = fm_deemph;
} else if ("am" == opts.get("demod").toString()) {
am_demod = new AMDemod<int16_t>();
source->connect(am_demod, true);
demod = am_demod;
} else if (("usb" == opts.get("demod").toString()) || ("lsb" == opts.get("demod").toString())) {
ssb_demod = new USBDemod<int16_t>();
source->connect(ssb_demod, true);
demod = ssb_demod;
}
// Enable playback
PortSink audio_sink;
demod->connect(&audio_sink, true);
// Start queue & processing
queue.start();
// Wait for queue to to stop
queue.wait();
// Free allocated input nodes
if (rtl_source) { delete rtl_source; }
if (rtl_cast) { delete rtl_cast; }
if (raudio_src) { delete raudio_src; }
if (raudio_cast) { delete raudio_cast; }
if (iqaudio_src) { delete iqaudio_src; }
if (wav_src) { delete wav_src; }
if (wav_cast) { delete wav_cast; }
if (fm_demod) { delete fm_demod; }
if (fm_deemph) { delete fm_deemph; }
if (am_demod) { delete am_demod; }
if (ssb_demod) { delete ssb_demod; }
PortAudio::terminate();
// Done.
return 0;
}

@ -114,7 +114,7 @@ int main(int argc, char *argv[])
rtl_source->setFreqCorrection(opts.get("correction").toFloat());
}
rtl_cast = new AutoCast< std::complex<int16_t> >();
rtl_baseband = new IQBaseBand<int16_t>(0, 12.5e3, 21, 0, 22050.0);
rtl_baseband = new IQBaseBand<int16_t>(0, 15.0e3, 21, 0, 22050.0);
rtl_demod = new FMDemod<int16_t>();
rtl_deemph = new FMDeemph<int16_t>();
// Connect nodes

@ -109,9 +109,9 @@ AX25::process(const Buffer<uint8_t> &buffer, bool allow_overwrite)
if ((1==_state) && ((_ptr - _rxbuffer) > 2)) {
*_ptr = 0;
if (! check_crc_ccitt(_rxbuffer, _ptr-_rxbuffer)) {
LogMessage msg(LOG_DEBUG);
/*LogMessage msg(LOG_DEBUG);
msg << "AX.25: Received invalid buffer: " << _rxbuffer;
Logger::get().log(msg);
Logger::get().log(msg); */
} else {
// Assemble message
Message msg(_rxbuffer, _ptr-_rxbuffer-2);

@ -10,7 +10,7 @@ namespace sdr {
/** Specifies the possible log levels. */
typedef enum {
LOG_DEBUG, ///< Every thing that may be of interest.
LOG_DEBUG = 0, ///< Every thing that may be of interest.
LOG_INFO, ///< Messages about state changes.
LOG_WARNING, ///< Non critical errors (i.e. data loss).
LOG_ERROR ///< Critical errors.

Loading…
Cancel
Save