Added some comments.

master
Hannes Matuschek 11 years ago
parent b18da61188
commit e6a9aa6c02

@ -2,12 +2,12 @@
set(LIBSDR_SOURCES
buffer.cc node.cc queue.cc traits.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
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
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)
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).
*
* 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__
@ -14,6 +88,7 @@
#include "queue.hh"
#include "combine.hh"
#include "logger.hh"
#include "options.hh"
#include "utils.hh"
#include "demod.hh"

Loading…
Cancel
Save