Added some comments.

master
Hannes Matuschek 11 years ago
parent b18da61188
commit e6a9aa6c02

@ -2,12 +2,12 @@
set(LIBSDR_SOURCES set(LIBSDR_SOURCES
buffer.cc node.cc queue.cc traits.cc buffer.cc node.cc queue.cc traits.cc
portaudio.cc utils.cc wavfile.cc portaudio.cc utils.cc wavfile.cc
exception.cc logger.cc psk31.cc) exception.cc logger.cc psk31.cc options.cc)
set(LIBSDR_HEADERS sdr.hh math.hh set(LIBSDR_HEADERS sdr.hh math.hh
buffer.hh node.hh queue.hh buffernode.hh filternode.hh traits.hh autocast.hh buffer.hh node.hh queue.hh buffernode.hh filternode.hh traits.hh autocast.hh
siggen.hh portaudio.hh utils.hh wavfile.hh demod.hh firfilter.hh siggen.hh portaudio.hh utils.hh wavfile.hh demod.hh firfilter.hh
fftplan.hh fftplan_native.hh exception.hh baseband.hh freqshift.hh subsample.hh fftplan.hh fftplan_native.hh exception.hh baseband.hh freqshift.hh subsample.hh
combine.hh logger.hh psk31.hh interpolate.hh operators.hh) combine.hh logger.hh psk31.hh interpolate.hh operators.hh options.hh)
if(SDR_WITH_PORTAUDIO) if(SDR_WITH_PORTAUDIO)
set(LIBSDR_SOURCES ${LIBSDR_SOURCES} portaudio.cc) set(LIBSDR_SOURCES ${LIBSDR_SOURCES} portaudio.cc)

@ -0,0 +1,208 @@
#include "options.hh"
#include <getopt.h>
#include <stdlib.h>
#include <sstream>
#include <string.h>
#include <iostream>
using namespace sdr;
/* ********************************************************************************************* *
* Implementation of Options
* ********************************************************************************************* */
Options::Options()
: _options()
{
// pass...
}
bool
Options::has(const char *name) {
return _options.end() != _options.find(name);
}
const Options::Value &
Options::get(const char *name) {
return _options[name];
}
bool
Options::parse(const Definition defs[], int argc, char *argv[], Options &options)
{
// Get number of definitions
const Definition *def = defs;
int nopts = 0;
while (def->name) { nopts++; def++; }
struct option *getopt_options = (struct option *)malloc((nopts+1)*sizeof(struct option));
std::map<std::string, Definition> long_options;
std::map<char, Definition> short_options;
def = defs; struct option *getopt_opt = getopt_options;
std::string short_opt_str;
for (int i=0; i<nopts; i++, def++, getopt_opt++) {
getopt_opt->name = def->name;
if (FLAG == def->type) { getopt_opt->has_arg = no_argument; }
else { getopt_opt->has_arg = required_argument; }
getopt_opt->flag = 0;
getopt_opt->val = def->short_name;
long_options[def->name] = *def;
if (def->short_name) {
short_options[def->short_name] = *def;
short_opt_str += def->short_name;
if (FLAG != def->type) { short_opt_str += ':'; }
}
}
// add sentinel
getopt_opt->name = 0; getopt_opt->has_arg = 0; getopt_opt->flag = 0; getopt_opt->val = 0;
// Parse options using getopt
while (true) {
int option_index = 0;
int c = getopt_long(argc, argv, short_opt_str.c_str(), getopt_options, &option_index);
if (-1 == c) { break; }
// Handle long option:
if (0 == c) {
const char *name = getopt_options[option_index].name;
if (long_options.end() == long_options.find(name)) {
free(getopt_options);
return false;
}
const Definition &opt = long_options[name];
if (FLAG == opt.type) { options._options[name] = Value(); }
else if (INTEGER == opt.type) { options._options[name] = atol(optarg); }
else if (FLOAT == opt.type) { options._options[name] = atof(optarg); }
else if (ANY == opt.type) { options._options[name] = Value(optarg); }
} else {
if (short_options.end() == short_options.find(c)) {
free(getopt_options);
return false;
}
const Definition &opt = short_options[c];
const char *name = opt.name;
if (FLAG == opt.type) { options._options[name] = Value(); }
else if (INTEGER == opt.type) { options._options[name] = atol(optarg); }
else if (FLOAT == opt.type) { options._options[name] = atof(optarg); }
else if (ANY == opt.type) { options._options[name] = Value(optarg); }
}
}
free(getopt_options);
return true;
}
void
Options::print_help(std::ostream &stream, const Definition defs[])
{
for (const Definition *def = defs; def->name; def++) {
stream << "--" << def->name;
if (def->short_name) { stream << ", -" << def->short_name; }
if (INTEGER == def->type) { stream << " INTEGER"; }
else if (FLOAT == def->type) { stream << " FLOAT"; }
else if (ANY == def->type) { stream << " VALUE"; }
stream << std::endl;
if (def->help) {
std::istringstream iss(def->help);
std::string line(" ");
do {
std::string word; iss >> word;
if ((line.length()+word.length()) > 78) {
stream << line << std::endl;
line = " ";
}
line += word + " ";
} while (iss);
if (! line.empty()) { stream << line << std::endl; }
}
stream << std::endl;
}
}
/* ********************************************************************************************* *
* Implementation of Value
* ********************************************************************************************* */
Options::Value::Value()
: _type(NONE)
{
// pass...
}
Options::Value::Value(long value)
: _type(INTEGER)
{
_value.as_int = value;
}
Options::Value::Value(double value)
: _type(FLOAT)
{
_value.as_float = value;
}
Options::Value::Value(const std::string &value)
: _type(STRING)
{
_value.as_string = strdup(value.c_str());
}
Options::Value::~Value() {
if (STRING == _type) { free(_value.as_string); }
}
Options::Value::Value(const Value &other)
: _type(other._type), _value(other._value)
{
if (STRING == _type) { _value.as_string = strdup(_value.as_string); }
}
const Options::Value &
Options::Value::operator =(const Value &other) {
if (STRING == _type) { free(_value.as_string); }
_type = other._type;
if (NONE == _type) { /* pass...*/ }
else if (INTEGER == _type) { _value.as_int = other._value.as_int; }
else if (FLOAT == _type) { _value.as_float = other._value.as_float; }
else if (STRING == _type) { _value.as_string = strdup(other._value.as_string); }
return *this;
}
bool
Options::Value::isNone() const {
return NONE == _type;
}
bool
Options::Value::isInteger() const {
return INTEGER == _type;
}
bool
Options::Value::isFloat() const {
return FLOAT == _type;
}
bool
Options::Value::isString() const {
return STRING == _type;
}
long
Options::Value::toInteger() const {
return _value.as_int;
}
double
Options::Value::toFloat() const {
return _value.as_float;
}
std::string
Options::Value::toString() const {
return _value.as_string;
}

@ -0,0 +1,102 @@
#ifndef __SDR_OPTIONS_HH__
#define __SDR_OPTIONS_HH__
#include <string>
#include <map>
namespace sdr {
/** Convenience functions for command line arguments. */
class Options
{
public:
/** The argument value. */
class Value {
protected:
/** Value type. */
typedef enum {
NONE, ///< Empty or invalid value.
INTEGER, ///< An integer (long int).
FLOAT, ///< A floating point number (double).
STRING ///< An ASCII string.
} Type;
public:
/** Empty constructor. */
Value();
/** Integer constructor. */
Value(long value);
/** Floating point constructor. */
Value(double value);
/** String constructor. */
Value(const std::string &value);
/** Copy constructor. */
Value(const Value &other);
/** Destructor. */
~Value();
/** Assignment. */
const Value &operator=(const Value &other);
/** Returns @c true if the value is empty. */
bool isNone() const;
/** Returns @c true if the value is an integer. */
bool isInteger() const;
/** Returns @c true if the value is a floating point number. */
bool isFloat() const;
/** Returns @c true if the value is a string. */
bool isString() const;
/** Turns the value into an integer. */
long toInteger() const;
/** Turns the value into a floating point number. */
double toFloat() const;
/** Turns the value into a string. */
std::string toString() const;
protected:
/** The type of the value. */
Type _type;
/** Values. */
union {
long as_int;
double as_float;
char *as_string;
} _value;
};
/** Possible argument types. */
typedef enum {
FLAG, ///< No argument (flag).
INTEGER, ///< Integer argument.
FLOAT, ///< Floating point argument.
ANY ///< Any argument (string).
} ArgType;
/** Argument definition. */
typedef struct {
const char *name; ///< Argument name (long).
char short_name; ///< Argument name (short).
ArgType type; ///< Argument type.
const char *help; ///< Help string.
} Definition;
/** Parse the given arguments (@c argc, @c argv) using the definitions @c defs and stores
* the results into @c options. Returns @c false on error. */
static bool parse(const Definition defs[], int argc, char *argv[], Options &options);
/** Serializes a help text derived from given the definitions into @c stream. */
static void print_help(std::ostream &stream, const Definition defs[]);
public:
/** Empty constructor. */
Options();
/** Returns @c true if the specified option was found (long name). */
bool has(const char *name);
/** Returns the argument of the specified option (long name). */
const Value &get(const char *name);
protected:
/** The table of option names and argument values. */
std::map<std::string, Value> _options;
};
}
#endif // __SDR_OPTIONS_HH__

@ -1,4 +1,78 @@
/** @mainpage A C++ library for software defined radio (SDR). /** @mainpage A C++ library for software defined radio (SDR).
*
* libsdr is a simple C++ library allowing to assemble software defined radio (SDR) applications
* easily. The library is a collection of (mostly) template classes implementing a wide varity of
* procssing nodes. By connecting these processing nodes, a stream-processing chain is constructed
* which turns raw input data into something meaningful.
*
* Please note, I have written this library for my own amusement and to learn something about SDR.
* If you search for a more complete and efficient SDR library, consider GNU radio.
*
* A processing node is either a @c sdr::Source, @c sdr::Sink, both or may provide one or more
* sources or sinks. A source is always connected to a sink. Another important object is the
* @c sdr::Queue. It is a singleton class that orchestrates the processing of the data. It may
* request further data from the sources once all present data has been processed. It also
* routes the date from the sources to the sinks.
*
* The following examples shows a trivial application that recods some audio from the systems
* default audio source and play it back.
* \code
* #include <libsdr/sdr.hh>
*
* int main(int argc, char *argv[]) {
* // Initialize PortAudio system
* sdr::PortAudio::init();
*
* // Create an audio source using PortAudio
* sdr::PortSource<int16_t> source(44.1e3);
* // Create an audio sink using PortAudio
* sdr::PortSink sink;
*
* // Connect them
* source.connect(&sink);
*
* // Read new data from audio sink if queue is idle
* sdr::Queue::get().addIdle(&source, &sdr::PortSource<int16_t>::next);
*
* // Get and start queue
* sdr::Queue::get().start();
* // Wait for queue to stop
* sdr::Queue::get().wait();
*
* // Terminate PortAudio system
* sdr::PortAudio::terminate();
*
* // done.
* return 0;
* }
* \endcode
*
* First, the PortAudio system gets initialized.
*
* Then, the audio source is constructed. The
* argument specifies the sample rate in Hz. Here a sample rate of 44100 Hz is used. The template
* argument of @c sdr::PortSource specifies the input type. Here a signed 16bit integer is used.
* The audio source will have only one channel (mono).
*
* The second node is the audio (playback) sink, which takes no arguments. It gets configured once
* the source is connected to the sink with @c source.connect(&sink).
*
* In a next step, the sources @c next method gets connected to the "idle" signal of the queue.
* This is necessary as the audio source does not send data by its own. Whenever the @c next method
* gets called, the source will send a certain amount of captured data to the connected sinks. Some
* nodes will send data to the connected sinks without the need to explicit triggering. The
* @c sdr::PortSource node, however, needs that explicit triggering. The "idle" event gets emitted
* once the queue gets empty, means whenever all data has been processes (here, played back).
*
* As mentioned aboce, the queue is a singleton class. Means that for every process, there is
* exactly one instance of the queue. This singleton instance is accessed by calling the static
* method @c sdr::Queue::get. By calling @c sdr::Queue::start, the queue is started in a separate
* thread. This threads is responsible for all the processing of the data which allows to perform
* other tasks in the main thread, i.e. GUI stuff. A call to @c sdr::Queue::wait, will wait for
* the processing thread to exit, which will never happen in that particular example.
*
* The queue can be stopped by calling the @c sdr::Queue::stop method. This can be implemented for
* this example by the means of process signals.
*/ */
#ifndef __SDR_HH__ #ifndef __SDR_HH__
@ -14,6 +88,7 @@
#include "queue.hh" #include "queue.hh"
#include "combine.hh" #include "combine.hh"
#include "logger.hh" #include "logger.hh"
#include "options.hh"
#include "utils.hh" #include "utils.hh"
#include "demod.hh" #include "demod.hh"

Loading…
Cancel
Save