-/// The AudioDevice class.
+/// \file audio_device.cpp
+/// Implementation of AudioDevice, which is the base class for all audio
+/// devices.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
#include <stdexcept>
+/// \file audio_in_default.cpp
+/// Used to configure the default audio input device in embedded systems.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
+
#include "drivers.h"
namespace FreeDV {
+ /// Open the default audio input.
+ /// This function is intended for use in embedded programs that don't use
+ /// the device driver manager.
AudioInput *
Driver::AudioInDefault()
{
-/// The AudioInput class.
+/// \file audio_input.cpp
+/// Implementation of the AudioInput class.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
+/// \file audio_out_default.cpp
+/// Used to configure the default audio output in embedded systems.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
+
#include "drivers.h"
namespace FreeDV {
+ /// Open the default audio output.
+ /// This function is intended for use in embedded programs that don't
+ /// use the device driver manager.
AudioOutput *
Driver::AudioOutDefault()
{
-/// The AudioOutput class.
+/// \file audio_output.cpp
+/// Implementation of the AudioOutput class.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
-/// The AudioSink driver, called as "sink", discards the audio, for testing.
+/// \file audio_sink.cpp Audio Sink Driver.
+/// The AudioSink driver, called as --loudspeaker="sink" or
+/// --transmitter="sink". It discards the audio, for testing.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
namespace FreeDV {
/// Audio output "sink", discards the audio, for testing.
+ ///
class AudioSink : public AudioOutput {
public:
/// Instantiate the audio sink.
+ ///
AudioSink(const char * parameters);
~AudioSink();
/// Return file descriptors for poll()
- /// \param size The address of a variable that will be written
- /// with the number of file descriptors in the array.
- /// \return The address of an array of integers containing the
- /// file descriptors.
+ /// \param array The address of an array that will be written
+ /// with a sequence of file descriptors.
+ /// \param space The maximum number of file descriptors that may be
+ /// stored in the array.
+ /// \return The number of file descriptors written to the array.
virtual int
poll_fds(PollType * array, int space);
{
}
- // Write audio into the "short" type.
std::size_t
AudioSink::write16(const std::int16_t *, std::size_t length)
{
return length;
}
+ //
int
AudioSink::poll_fds(PollType *, int)
{
return new ::FreeDV::AudioSink(parameter);
}
- std::ostream &
- Enumerator::AudioSink(std::ostream & stream)
+ /// Enumerate the AudioSink driver, for displaying the available device
+ /// drivers to the user.
+ /// This version is silent, because "sink" is for testing rather than
+ /// normal use.
+ static std::ostream &
+ AudioSinkEnumerator(std::ostream & stream)
{
return stream;
}
static bool
initializer()
{
- driver_manager()->register_audio_output("sink", Driver::AudioSink, Enumerator::AudioSink);
+ driver_manager()->register_audio_output(
+ "sink",
+ Driver::AudioSink,
+ AudioSinkEnumerator);
return true;
}
- static const bool initialized = initializer();
+ static const bool UNUSED initialized = initializer();
}
-/// The general base class for drivers.
+/// \file base.cpp
+/// Implementation of the general base class for drivers, both algorithm
+/// drivers like Modem and device drivers like AudioInput.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
-/// This is the main program for applications that are not space-limited.
-/// Any application that is space limited should have its own main that
-/// wires drivers to the Interfaces class without using DriverManager.
-/// Thus, you can get rid of all of the STL template use, etc.
+/// \file big_main.cpp
+/// Version of main for programs that are not space-limited.
+///
+/// To save space, any application that is space limited should have its own
+/// main() that wires drivers to the Interfaces class without using
+/// DriverManager.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
///
-/// For the sake of correctness and optimization, I have written whatever I
-/// can to be without side-effects, a style inherited from functional
-/// programming. Thus, the excessive use of "const". - Bruce
#include <stdlib.h>
#include <string.h>
using namespace std;
namespace FreeDV {
/// Run the main loop of the program, this is called after arguments are set.
+ ///
extern int run(struct Interfaces *);
}
using namespace FreeDV;
const char * program_name = 0;
}
+/// The main loop for large programs.
+/// This parses a long list of arguments using getopt_long().
+///
int
main(int argc, char * * argv)
{
+/// \file blank_panel.cpp
/// The "blank panel" GUI driver, for testing.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
namespace FreeDV {
- /// This is control-less GUI driver, for testing.
+ /// This is a control-less GUI driver, for testing.
+ ///
class BlankPanel : public UserInterface {
public:
virtual ~BlankPanel();
/// Return file descriptors for poll()
- /// \param size The address of a variable that will be written
- /// with the number of file descriptors in the array.
- /// \return The address of an array of integers containing the
- /// file descriptors.
+ /// \param array The address of an array that will be written
+ /// with a sequence of file descriptors.
+ /// \param space The maximum number of file descriptors that may be
+ /// stored in the array.
+ /// \return The number of file descriptors written to the array.
virtual int poll_fds(PollType * array, int space);
/// Return the amount of bytes ready for read. In this case, it always
return new ::FreeDV::BlankPanel(parameter, interfaces);
}
- std::ostream &
- Enumerator::BlankPanel(std::ostream & stream)
+ static std::ostream &
+ BlankPanelEnumerator(std::ostream & stream)
{
return stream;
}
static bool
initializer()
{
- driver_manager()->register_user_interface("blank-panel", Driver::BlankPanel, Enumerator::BlankPanel);
+ driver_manager()->register_user_interface(
+ "blank-panel",
+ Driver::BlankPanel,
+ BlankPanelEnumerator);
return true;
}
- static const bool initialized = initializer();
+ static const bool UNUSED initialized = initializer();
}
-/// The Codec base class.
+/// \file codec.cpp
+/// The base class for all codec drivers.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
+/// \file codec_noop.cpp
/// The No-Op Codec, for testing and plain SSB voice.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
#include <string.h>
namespace FreeDV {
- /// Codec "no-op", just copies its input to its output. For plain SSB voice, and for testing.
+ /// Codec "no-op", just copies its input to its output.a
+ /// For plain SSB voice, and for testing.
class CodecNoOp : public Codec {
static const std::size_t FrameDuration = 40;
static const std::size_t FrameSamples = SamplesPerMillisecond
return new ::FreeDV::CodecNoOp(parameter);
}
- std::ostream &
- Enumerator::CodecNoOp(std::ostream & stream)
+ static std::ostream &
+ CodecNoOpEnumerator(std::ostream & stream)
{
return stream;
}
static bool
initializer()
{
- driver_manager()->register_codec("no-op", Driver::CodecNoOp, Enumerator::CodecNoOp);
+ driver_manager()->register_codec("no-op", Driver::CodecNoOp, CodecNoOpEnumerator);
return true;
}
- static const bool initialized = initializer();
+ static const bool UNUSED initialized = initializer();
}
+/// \file driver_manager.cpp
/// Device driver manager.
/// Don't use DriverManager and big_main.cpp in space-limited applications.
-/// The STL templates it uses are too large.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include <iostream>
#include <string.h>
#include "drivers.h"
namespace FreeDV {
+ /// Creator functions passed to the various driver registration functions
+ /// will be cast to this value.
typedef Base * (*base_creator)(const char *);
- // Ad-hoc list management functions are much smaller, and indeed faster for
- // our tiny data sets, than the STL containers. Since this program is
- // embedded, it's worth some extra effort to avoid STL containers.
+ /// Internal structure which holds a list of device drivers.
+ ///
+ struct DriverList {
+ /// The name of the driver.
+ ///
+ const char * key;
+ union {
+ /// Instantiate a device driver.
+ ///
+ FreeDV::Base * (*creator)(const char *);
+ FreeDV::Base * (*creator_i)(const char *, Interfaces *);
+ };
+ /// Enumerate the available device drivers.
+ ///
+ std::ostream & (*enumerator)(std::ostream &);
+ };
static std::ostream &
enumerate(std::ostream & stream, const char * name, const DriverList * list)
return stream;
}
+ // Ad-hoc list management functions are much smaller, and indeed faster for
+ // our tiny data sets, than the STL containers. Since this program is
+ // embedded, it's worth some extra effort to avoid STL containers.
static FreeDV::Base *
pick(const char * key, const char * type, const char * const parameters, const DriverList * list, Interfaces * interfaces = 0)
{
+/// \file drivers.h
/// FreeDV driver interface definitions.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
+
+
#include <cstdint>
#include <iostream>
#include <assert.h>
#include "platform.h"
-/// Namespace used for all code in this program.
+/// Portable way to use the [[unused]] C++11 attribute before all compilers
+/// have caught up with C++11.
+///
+#ifndef UNUSED
+# if __cplusplus > 199711L
+# if __GNUC__ && ( __GNUC_MAJOR__ <= 4 || __GNUC_MINOR__ >= 8 )
+# define UNUSED __attribute__((unused))
+# else
+# define UNUSED [[unused]]
+# endif
+# else
+# define UNUSED
+# endif
+#endif
+
+/// Portable way to use the [[noreturn]] C++11 attribute before all compilers
+/// have caught up with C++11.
+///
+#ifndef NORETURN
+# if __cplusplus > 199711L
+# if __GNUC__ && ( __GNUC_MAJOR__ <= 4 || __GNUC_MINOR__ >= 8 )
+# define NORETURN __attribute__((noreturn))
+# else
+# define NORETURN [[noreturn]]
+# endif
+# else
+# define NORETURN
+# endif
+#endif
+
+/// \namespace FreeDV Namespace used for all code in this program.
+///
namespace FreeDV {
/// This propogates argv[0] so that it can be used in error messages.
+///
extern const char * program_name;
/// The sample rate used by all audio interfaces in the program.
const unsigned int SampleRate = 48000;
/// The number of audio samples per millisecond, at SampleRate.
+///
const unsigned int SamplesPerMillisecond = ((double)SampleRate / 1000.0);
-// The audio frame duration in milliseconds. The audio interfaces will
-// use this as a period size. It should be 1/2 of the smallest codec frame
-// size we expect to use.
+/// The audio frame duration in milliseconds. The audio interfaces will
+/// use this as a period size. It should be 1/2 of the smallest codec frame
+/// size we expect to use.
const unsigned int AudioFrameDuration = 10;
/// The number of audio samples in an audio frame.
+///
const unsigned int AudioFrameSamples = SamplesPerMillisecond
* AudioFrameDuration;
const unsigned int MaximumFrameDuration = 100;
/// The number of audio samples in the maximum-duration frame.
+///
const unsigned int MaximumFrameSamples = SamplesPerMillisecond
* MaximumFrameDuration;
}
/// Discard any buffered data.
+ ///
void reset();
};
void set_scheduler();
/// Check the user's privileges, and warn if they are inappropriate.
+///
void check_privileges();
/// Virtual base class for all driver classes.
+///
class Base {
private:
/// The copy constructor is private to prevent it from being used.
/// object information is to be rendered.
/// \return A reference to the provided stream, meant for the
/// usual successive call paradigm of ostream operator << .
- std::ostream & print(std::ostream &) const;
+ std::ostream & print(std::ostream & stream) const;
};
/// Write the driver information from the Base object onto a stream,
virtual std::size_t ready() = 0;
/// Type used by poll_fds(). For portability to Windows.
+ ///
typedef struct pollfd PollType;
/// Poll file descriptors for available I/O.
+ ///
static int poll(PollType * array, int length, int timeout);
/// Get the file descriptors to be used to poll for available I/O.
+ ///
virtual int poll_fds(PollType * array, int space) = 0;
virtual ~IODevice() = 0;
};
/// Virtual base class for AudioInput and AudioOutput.
+///
class AudioDevice : public ::FreeDV::IODevice {
protected:
/// The master volume control for the device.
+ ///
float master_amplitude;
/// Create an AudioDevice instance.
public:
/// Destroy an AudioInput device instance.
+ ///
virtual ~AudioInput() = 0;
/// Read audio into an array of the signed 16-bit integer type.
+ ///
virtual std::size_t
read16(std::int16_t * array, std::size_t length) = 0;
};
public:
/// Destroy an AudioOutput device instance.
+ ///
virtual ~AudioOutput() = 0;
/// Write audio from an array of the signed 16-bit integer type.
+ ///
virtual std::size_t
write16(const std::int16_t * array, std::size_t length) = 0;
};
public:
/// Destroy a codec instance.
+ ///
virtual ~Codec() = 0;
/// Decode from data bytes to audio samples.
public:
/// Destroy a framer instance.
+ ///
virtual ~Framer() = 0;
/// Return the minimum duration of a frame in milliseconds.
public:
/// Destroy the radio keying device instance.
+ ///
virtual ~KeyingOutput() = 0;
/// Key or un-key the transmitter.
virtual void key(bool value) = 0;
/// Return the amount of bytes ready to write.
+ ///
virtual std::size_t ready() = 0;
};
class TextInput : public ::FreeDV::IODevice {
protected:
/// The child class calls this member in its parent to set the text.
+ ///
void set(const char * text);
public:
/// Read the text data.
+ ///
virtual std::size_t read(char * buffer, std::size_t length) = 0;
virtual ~TextInput() = 0;
class UserInterface : public ::FreeDV::IODevice {
protected:
/// The external Interfaces object.
+ ///
Interfaces * interfaces;
/// Create an instance of the UserInterface object.
virtual ~UserInterface() = 0;
};
-/// Structure used to pass all of the drivers. Can be modified from
+/// Structure used to pass all of the drivers. Can be modified while the
+/// program is running.
class Interfaces {
public:
Interfaces() : codec(0),
virtual ~Interfaces() final;
/// The voice codec in use.
+ ///
Codec * codec;
/// The Framer handles the protocol which wraps the codec data.
/// It can decline to feed any audio on to the codec if the protocol says
/// that should not happen, for example if the data isn't addressed to us.
Framer * framer;
/// The output used to key the transmitter.
+ ///
KeyingOutput * keying_output;
/// The audio output which drives the loudspeaker or headphone.
+ ///
AudioOutput * loudspeaker;
/// The audio input from the microphone.
+ ///
AudioInput * microphone;
/// The softmodem.
+ ///
Modem * modem;
/// The PTT input that indicates the transmission is to be digital audio.
+ ///
PTTInput * ptt_input_digital;
/// The PTT input that indicates the transmission is to be SSB.
+ ///
PTTInput * ptt_input_ssb;
/// The audio input from the receiver.
+ ///
AudioInput * receiver;
/// The text to be transmitted in our text side-channel.
+ ///
TextInput * text_input;
/// The audio output that drives the transmitter.
+ ///
AudioOutput * transmitter;
/// The user interface driver. Used for GUIs.
+ ///
UserInterface * user_interface;
/// Fill in default drivers if the user or UserInterface hasn't set any.
+ ///
void fill_in();
/// Write the command-line flags necessary to configure the drivers as
/// they are presently configured to the stream. This is used to save
/// the configuration or debug the program.
/// \param stream A reference to an instance of ostream on which the
+ /// \param program_name The name of the executable file for this program.
/// \return A reference to the provided stream, meant for the
/// usual successive call paradigm of ostream operator << .
+ ///
virtual std::ostream &
print(std::ostream & stream, const char * program_name) const;
};
/// for debugging and dumping the configuration information.
/// \param stream A reference to an instance of ostream upon which the
/// object information is to be rendered.
-/// \param interfaces a reference to an Interfaces object providing the
-/// information.
+/// \param interfaces a reference to an Interfaces object providing
+/// information about the device and algorithm drivers to be used.
/// \return A reference to the provided stream, meant for the
/// usual successive call paradigm of ostream operator << .
+///
inline std::ostream &
operator << (std::ostream & stream, const Interfaces & interfaces) {
return interfaces.print(stream, 0);
}
-// Most of the functions in the Driver and Enumerator namespaces are
-// registered with the driver manager at run-time. There won't be many
-// reasons to reference them directly.
+/// Functions for opening device drivers.
+/// Most of the functions in the Driver and Enumerator namespaces are
+/// registered with the driver manager at run-time. Only embedded programs
+/// that do not use big_main.cpp and driver_manager.cpp will need to reference
+/// them.
namespace Driver {
+/// The "tone" audio input driver, which plays a combination of multiple sine
+/// waves at user-selected frequencies and amplitudes, for testing.
+/// \param parameter A list of frequencies and amplitudes which the driver
+/// shall synthesize. For example, "1000,0.5;60,0.5" would play a 1 kHz tone
+/// and a 60 Hz tone at equal levels. The frequency specified must be greater
+/// than zero and less than or equal to 1/2 of SampleRate. The amplitudes
+/// selected should add up to 1.0 or less.
+/// \return A pointer to the AudioInput instance for the tone generator.
+///
AudioInput * Tone(const char * parameter);
+
+/// An ALSA audio input driver for use on Linux.
+/// \param parameter The name of the sound device to open, in the form of
+/// "hw:*n*", "plughw:*n*" or a "longname" as returned by
+/// sound_pcm_card_get_longname() or a shortened version of that name
+/// anchored at the start and with an arbitrary portion of the end removed.
+/// In the case of shortened names, the first device with a longname that
+/// matches the shortened name provided (anchored at the start of the longname
+/// and proceeding for the length of the provided string but not beyond it)
+/// will be opened.
+/// \return A pointer to the AudioInput instance for the ALSA device selected.
+///
AudioInput * AudioInALSA(const char * parameter);
+
+/// Opens the default audio input interface of the operating system.
+/// \return A pointer to an AudioInput instance for the default audio input
+/// device.
+///
AudioInput * AudioInDefault();
+
+/// The "sink" audio output driver, which discards all audio sent to it,
+/// for testing.
+/// \param parameter Not used.
+/// \return A pointer to an AudioInput instance for the audio sink.
+///
AudioOutput * AudioSink(const char * parameter);
+
+/// An ALSA audio output driver for use on Linux.
+/// \param parameter The name of the sound device to open, in the form of
+/// "hw:*n*", "plughw:*n*" or a "longname" as returned by
+/// sound_pcm_card_get_longname() or a shortened version of that name
+/// anchored at the start and with an arbitrary portion of the end removed.
+/// In the case of shortened names, the first device with a longname that
+/// matches the shortened name provided (anchored at the start of the longname
+/// and proceeding for the length of the provided string but not beyond it)
+/// will be opened.
+/// \return A pointer to the AudioInput instance for the ALSA device selected.
+///
AudioOutput * AudioOutALSA(const char * parameter);
+
+/// Opens the default audio output interface of the operating system.
+///
AudioOutput * AudioOutDefault();
+
+/// Opens a no-op codec, which copies its input to its output unmodified,
+/// for testing.
+/// \param parameter Not used.
+/// \return A pointer to the Codec instance for the no-op codec.
+///
Codec * CodecNoOp(const char * parameter);
-Framer * FramerNoOp(const char * parameter);
+
+/// Opens a no-op protocol framer, which copies its input to its output
+/// unmodified, for testing.
+/// \param parameter Not used.
+/// \return A pointer to the Framer instance for the no-op codec.
+///
+Framer * FramerNoOp(const char * parameter);
+
+/// Opens a "sink" keying device, which doesn't key anything, for testing.
+/// \param parameter Not used.
+/// \return A pointer to the KeyingOutput instance for the device.
+///
KeyingOutput * KeyingSink(const char * parameter);
+
+/// Opens a no-op modem, which copies its input to its output unmodified,
+/// for testing.
+/// \param parameter Not used.
+/// \return A pointer to the Modem instance for the no-op modem.
+///
Modem * ModemNoOp(const char * parameter);
-PTTInput * PTTConstant(const char * parameter);
-TextInput * TextConstant(const char * parameter);
-UserInterface * BlankPanel(const char * parameter, Interfaces *);
-}
-namespace Enumerator {
-std::ostream & Tone(std::ostream &);
-std::ostream & AudioSink(std::ostream &);
-std::ostream & AudioInALSA(std::ostream &);
-std::ostream & AudioOutALSA(std::ostream &);
-std::ostream & CodecNoOp(std::ostream &);
-std::ostream & FramerNoOp(std::ostream &);
-std::ostream & KeyingSink(std::ostream &);
-std::ostream & LibEvent(std::ostream &);
-std::ostream & ModemNoOp(std::ostream &);
-std::ostream & PTTConstant(std::ostream &);
-std::ostream & TextConstant(std::ostream &);
-std::ostream & BlankPanel(std::ostream &);
-}
+/// Opens a "constant" push-to-talk device, which has a constant value of
+/// pushed or not pushed, for testing.
+/// \param parameter "1" if the device is to emit the "pushed" state, "0" if
+/// the device is to emit the not-pushed state.
+/// \return A pointer to the PTTInput instance for the device.
+///
+PTTInput * PTTConstant(const char * parameter);
+
+/// Opens a "constant" text ionput device, which has a constant text value
+/// which is to be transmitted as ancillary data.
+/// \param parameter The text to be transmitted.
+/// \return A pointer to the TextInput instance for the device.
+///
+TextInput * TextConstant(const char * parameter);
+
+/// Opens a "blank" user interface device, which has no displays or controls,
+/// for testing.
+/// \param parameter Not used.
+/// \param interfaces a reference to an Interfaces object providing
+/// information about the device and algorithm drivers to be used.
+/// \return A pointer to the UserInterface instance for the device.
+///
+UserInterface * BlankPanel(const char * parameter, Interfaces * interfaces);
}
-/// Namespace used for the entire program.
-namespace FreeDV {
/// Utility functions.
+///
/// Non-template version of min().
+///
inline std::size_t
min(std::size_t a, std::size_t b)
{
}
/// Non-template version of max().
+///
inline std::size_t
max(std::size_t a, std::size_t b)
{
return a > b ? a : b;
}
-struct DriverList {
- const char * key;
- union {
- FreeDV::Base * (*creator)(const char *);
- FreeDV::Base * (*creator_i)(const char *, Interfaces *);
- };
- std::ostream & (*enumerator)(std::ostream &);
-};
+/// Internal structure to DriverManager, used to keep a list of device
+/// or protocol drivers.
+struct DriverList;
/// Device driver manager. Allows for registration and enumeration of device
/// drivers. Instantiates device drivers on request.
public:
/// Initialize the driver manager.
+ ///
DriverManager();
~DriverManager();
/// Register an audio input driver.
/// \param driver The name of the driver.
/// \param creator The coroutine that will instantiate the driver.
+ /// \param enumerator The coroutine that will enumerate the available
+ /// driver interfaces for the user.
void register_audio_input(const char * driver, AudioInput * (*creator)(const char *), std::ostream & (*enumerator)(std::ostream &));
/// Register an audio input driver.
/// \param driver The name of the driver.
/// \param creator The coroutine that will instantiate the driver.
+ /// \param enumerator The coroutine that will enumerate the available
+ /// driver interfaces for the user.
void register_audio_output(const char * driver, AudioOutput * (*creator)(const char *), std::ostream & (*enumerator)(std::ostream &));
/// Register a codec.
/// \param driver The name of the driver.
/// \param creator The coroutine that will instantiate the driver.
+ /// \param enumerator The coroutine that will enumerate the available
+ /// driver interfaces for the user.
void register_codec(const char * driver, Codec * (*creator)(const char *), std::ostream & (*enumerator)(std::ostream &));
/// Register a protocol framer.
/// \param driver The name of the driver.
/// \param creator The coroutine that will instantiate the driver.
+ /// \param enumerator The coroutine that will enumerate the available
+ /// driver interfaces for the user.
void register_framer(const char * driver, Framer * (*creator)(const char *), std::ostream & (*enumerator)(std::ostream &));
/// Register a keying output driver.
/// \param driver The name of the driver.
/// \param creator The coroutine that will instantiate the driver.
+ /// \param enumerator The coroutine that will enumerate the available
+ /// driver interfaces for the user.
void register_keying_output(const char * driver, KeyingOutput * (*creator)(const char *), std::ostream & (*enumerator)(std::ostream &));
/// Register a modem driver.
/// \param driver The name of the driver.
/// \param creator The coroutine that will instantiate the driver.
+ /// \param enumerator The coroutine that will enumerate the available
+ /// driver interfaces for the user.
void register_modem(const char * driver, Modem * (*creator)(const char *), std::ostream & (*enumerator)(std::ostream &));
/// Register a PTT input driver.
/// \param driver The name of the driver.
/// \param creator The coroutine that will instantiate the driver.
+ /// \param enumerator The coroutine that will enumerate the available
+ /// driver interfaces for the user.
void register_ptt_input(const char * driver, PTTInput * (*creator)(const char *), std::ostream & (*enumerator)(std::ostream &));
/// Register a text input driver.
/// \param driver The name of the driver.
/// \param creator The coroutine that will instantiate the driver.
+ /// \param enumerator The coroutine that will enumerate the available
+ /// driver interfaces for the user.
void register_text_input(const char * driver, TextInput * (*creator)(const char *), std::ostream & (*enumerator)(std::ostream &));
/// Register a user interface driver.
/// \param driver The name of the driver.
/// \param creator The coroutine that will instantiate the driver.
+ /// \param enumerator The coroutine that will enumerate the available
+ /// driver interfaces for the user.
void register_user_interface(const char * driver, UserInterface * (*creator)(const char *, Interfaces *), std::ostream & (*enumerator)(std::ostream &));
};
}
/// Global reference to the driver manager.
+///
extern DriverManager * driver_manager();
}
+/// \file fifo.cpp
+/// Implementation of the FIFO class.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
+
#include "drivers.h"
#include <stdexcept>
#include <cstring>
+/// \file framer.cpp
/// The Protocol Framer base class.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
+/// \file framer_noop.cpp
/// The No-Op Framer, for digital voice that is not framed in a protocol.
-/// FreeDV would be the obvious example.
+/// FreeDV (as of this writing early 2014) would be the obvious example.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
#include <string.h>
namespace FreeDV {
/// Framer "no-op", just copies its input to its output.
+ ///
class FramerNoOp : public ::FreeDV::Framer {
public:
/// Create a framer instance.
- /// \param name Name of the driver. This is expected to be a single
- /// constant static string per driver class.
- /// \param parameters Driver-specific configuration parameters.
+ /// \param parameters Not used.
FramerNoOp(const char * parameters);
/// Destroy a framer instance.
+ ///
virtual ~FramerNoOp();
/// Return the minimum duration of a frame in milliseconds.
return new ::FreeDV::FramerNoOp(parameter);
}
- std::ostream &
- Enumerator::FramerNoOp(std::ostream & stream)
+ static std::ostream &
+ FramerNoOpEnumerator(std::ostream & stream)
{
return stream;
}
static bool
initializer()
{
- driver_manager()->register_framer("no-op", Driver::FramerNoOp, Enumerator::FramerNoOp);
+ driver_manager()->register_framer("no-op", Driver::FramerNoOp, FramerNoOpEnumerator);
return true;
}
- static const bool initialized = initializer();
+ static const bool UNUSED initialized = initializer();
}
-/// The Interfaces class.
+/// \file interfaces.cpp
+/// Implementation of the Interfaces class.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
-/// The I/O Device class.
+/// \file io_device.cpp
+/// Implementation of the I/O Device class.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
-/// KeyingOutput driver.
+/// \file keying.cpp
+/// Implementation of the KeyingOutput device driver class.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
+/// \file keying_sink.cpp
/// The KeyingSink class, called as "sink", doesn't key anything, for testing
/// or use with VOX.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
+
#include "drivers.h"
#include <iostream>
namespace FreeDV {
- /// KeyingOutput output "sink", doesn't key anything. For testing or use with VOX.
+ /// KeyingOutput output "sink", doesn't key anything.
+ /// For testing or use with VOX.
class KeyingSink : public KeyingOutput {
public:
/// Instantiate keying sink driver.
+ ///
KeyingSink(const char *);
virtual ~KeyingSink();
/// If the value is true, transmit. Otherwise receive.
+ ///
void key(bool value);
/// Return the amount of bytes ready for read. In this case, it always
return new ::FreeDV::KeyingSink(parameter);
}
- std::ostream &
- Enumerator::KeyingSink(std::ostream & stream)
+ static std::ostream &
+ KeyingSinkEnumerator(std::ostream & stream)
{
return stream;
}
static bool
initializer()
{
- driver_manager()->register_keying_output("sink", Driver::KeyingSink, Enumerator::KeyingSink);
+ driver_manager()->register_keying_output("sink", Driver::KeyingSink, KeyingSinkEnumerator);
return true;
}
- static const bool initialized = initializer();
+ static const bool UNUSED initialized = initializer();
}
-/// The virtual base class for modem drivers.
+/// \file modem.cpp
+/// Implementation of the virtual base class for modem algorithm drivers.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
+/// \file modem_noop.cpp
/// The no-op modem, for plain SSB voice and testing.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
#include <string.h>
public:
/// Instantiate the no-op modem.
+ ///
ModemNoOp(const char *);
virtual ~ModemNoOp();
return new ::FreeDV::ModemNoOp(parameter);
}
- std::ostream &
- Enumerator::ModemNoOp(std::ostream & stream)
+ static std::ostream &
+ ModemNoOpEnumerator(std::ostream & stream)
{
return stream;
}
static bool
initializer()
{
- driver_manager()->register_modem("no-op", Driver::ModemNoOp, Enumerator::ModemNoOp);
+ driver_manager()->register_modem("no-op", Driver::ModemNoOp, ModemNoOpEnumerator);
return true;
}
- static const bool initialized = initializer();
+ static const bool UNUSED initialized = initializer();
}
+/// \file platform/linux/alsa.cpp
+/// Functions to support the ALSA audio input and output device drivers on
+/// Linux.
+///
+/// There is at least one other operating systems that supports an ALSA-like
+// interfaces, Nucleus, but at this writing (early 2014) this driver is
+/// untested on that.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
+
+#include "drivers.h"
#include "alsa.h"
#include <iostream>
#include <sstream>
return stream;
}
+ /// Enumerate all of the ALSA device drivers available on the system for
+ /// the user.
+ /// \param stream The stream upon which information will be rendered.
+ /// \param mode The access mode of the stream, either SND_PCM_STREAM_CAPTURE
+ /// or SND_PCM_STREAM_PLAYBACK.
+ /// \return The stream that was passed as an argument, as is the convention
+ /// for iostreams inserters.
std::ostream &
ALSAEnumerate(std::ostream & stream, snd_pcm_stream_t mode)
{
return -ENODEV;
}
- static void
+ NORETURN static void
do_throw(
const int error,
const char * name,
throw std::runtime_error(str.str().c_str());
}
+ /// Open an ALSA device and set all of the configuration parameters on that
+ /// device. This version opens by ALSA name (hw:*n* or plughw:*n*), or
+ /// "longname", which is a possibly-shortened version of the name returned
+ /// by snd_card_get_longname() that has previously been rendered to the user
+ /// using ALSAEnumerate().
+ ///
+ /// All of the parameters are passed to ALSA functions, and are documented
+ /// in the documentation for the ALSA functions mentioned below.
+ ///
+ /// \param name The name of the ALSA device to open, or its *longname* in
+ /// a form previously rendered to the user using ALSAEnumerate(). This will
+ /// be passed to snd_pcm_open().
+ ///
+ /// \param stream One of SND_PCM_STREAM_CAPTURE or SND_PCM_STREAM_PLAYBACK,
+ /// indicates whether to capture or play the audio stream. This will be
+ /// passed to snd_pcm_open().
+ ///
+ /// \param mode One of SND_PCM_NONBLOCK or SND_PCM_ASYNC, or 0.
+ /// 0 indicates to use conventional blocking I/O. SND_PCM_NONBLOCK
+ /// indicates to use POSIX non-blocking I/O, and SND_PCM_ASYNC indicates
+ /// to use non-blocking I/O with completion notification. This value will
+ /// be passed to snd_pcm_open().
+ ///
+ /// \param format The format of the audio stream, selected from a large set
+ /// of date type and width selections defined for the ALSA snd_pcm_format_t
+ /// type. This will be passed to snd_pcm_set_hw_params_format().
+ ///
+ /// \param access Selected from the set of values defined for
+ /// snd_pcm_access_t. This designates if access to the device will be through
+ /// mapped memory, or through read and write functions, and whether the
+ /// arrangement of the data will be interleaved by channel, sequential arrays
+ /// of values per channel (non-interleaved), or "complex". This will be
+ /// passed to snd_pcm_set_hw_params_access().
+ ///
+ /// \param channels The number of channels desired in the audio stream. Note
+ /// that ALSA provides a channel-map API which can be used to determine the
+ /// expected loudspeaker placement (relative to the listener) for each
+ /// channel. This value is passed to snd_pcm_hw_params_set_channels().
+ ///
+ /// \param rate The number of audio frames per second. An ALSA audio frame
+ /// consists of one sample for each channel that is in use. This value is
+ /// passed to snd_pcm_hw_params_set_rate().
+ ///
+ /// \param period_size The number of ALSA frames to capture or play between
+ /// each hardware interrupt. This facilitates the use of poll() for
+ /// event-driven operation. This value will be passed to
+ /// snd_pcm_hw_params_set_period_*near*(). We aren't guaranteed the exact
+ /// value passed in, because the hardware only supports a specific set of
+ /// period and buffer-size combinations.
+ ///
+ /// \param buffer_size The number of ALSA frames to buffer for playback
+ /// before the program must write more. The effect of this value on capture
+ /// is uncertain, the programmer's system seems to be able to buffer a
+ /// long duration of ALSA frames regardless of this value.
+ ///
+ /// \return A sound_pcm_t pointer containing context for the selected audio
+ /// device, as returned by snd_pcm_open(), or 0 in case the device name
+ /// passed can't be found in the system or the device can not be opened due
+ /// to privilege or contention.
+ ///
snd_pcm_t *
ALSASetup(
const char * name,
snd_pcm_uframes_t period_size,
snd_pcm_uframes_t buffer_size)
{
- int error;
- snd_pcm_t * handle = 0;
+ int error;
+ snd_pcm_t * handle = 0;
snd_pcm_hw_params_t * hw_params = 0;
error = open_by_longname(&handle, name, stream, mode);
-// The ALSA audio input driver.
+/// \file platform/linux/audio_in_alsa.cpp
+/// ALSA audio input device driver, for use on Linux.
+///
+/// There is at least one other operating systems that supports an ALSA-like
+/// interfaces, Nucleus, but at this writing (early 2014) this driver is
+/// untested on that.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
#include "alsa.h"
std::ostream & ALSAEnumerate(std::ostream & stream, snd_pcm_stream_t mode);
/// Audio input "ALSA", Uses the Linux ALSA Audio API.
+ ///
class AudioInALSA : public AudioInput {
private:
static const int overlong_delay = AudioFrameSamples * 4;
snd_pcm_t * handle;
bool started;
- void
+ NORETURN void
do_throw(const int error, const char * message = 0)
{
std::ostringstream str;
~AudioInALSA();
/// Return file descriptors for poll()
- /// \param size The address of a variable that will be written
- /// with the number of file descriptors in the array.
- /// \return The address of an array of integers containing the
- /// file descriptors.
+ /// \param array The address of an array that will be written
+ /// with a sequence of file descriptors.
+ /// \param space The maximum number of file descriptors that may be
+ /// stored in the array.
+ /// \return The number of file descriptors written to the array.
virtual int
poll_fds(PollType * array, int space);
if ( result >= 0 ) {
return result;
}
- else {
+ else
do_throw(result, "Read");
- return 0; // do_throw doesn't return.
- }
}
AudioInput *
return new ::FreeDV::AudioInALSA(parameter);
}
- std::ostream &
- Enumerator::AudioInALSA(std::ostream & stream)
+ static std::ostream &
+ AudioInALSAEnumerator(std::ostream & stream)
{
return ALSAEnumerate(stream, SND_PCM_STREAM_CAPTURE);
}
if ( error >= 0 )
return available;
- else {
+ else
do_throw(error, "Get Frames Available for Read");
- return 0; // do_throw doesn't return.
- }
}
static bool
driver_manager()->register_audio_input(
"alsa",
Driver::AudioInALSA,
- Enumerator::AudioInALSA);
+ AudioInALSAEnumerator);
return true;
}
static const bool initialized = initializer();
-// The ALSA audio output driver.
+/// \file platform/linux/audio_out_alsa.cpp
+/// ALSA audio output device driver, for use on Linux.
+///
+/// There is at least one other operating system that supports an ALSA-like
+/// interfaces, Nucleus, but at this writing (early 2014) this driver is
+/// untested on that.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "alsa.h"
#include "drivers.h"
std::ostream & ALSAEnumerate(std::ostream & stream, snd_pcm_stream_t mode);
/// Audio output "ALSA", Uses the Linux ALSA Audio API.
+ ///
class AudioOutALSA : public AudioOutput {
private:
char * const parameters;
snd_pcm_t * handle;
bool started;
- void
+ NORETURN void
do_throw(const int error, const char * message = 0)
{
std::ostringstream str;
~AudioOutALSA();
/// Return file descriptors for poll()
- /// \param size The address of a variable that will be written
- /// with the number of file descriptors in the array.
- /// \return The address of an array of integers containing the
- /// file descriptors.
+ /// \param array The address of an array that will be written
+ /// with a sequence of file descriptors.
+ /// \param space The maximum number of file descriptors that may be
+ /// stored in the array.
+ /// \return The number of file descriptors written to the array.
virtual int
poll_fds(PollType * array, int space);
if ( error >= 0 )
return error;
- else {
+ else
do_throw(error, "Write");
- return 0; // do_throw doesn't return.
- }
}
AudioOutput *
return new ::FreeDV::AudioOutALSA(parameter);
}
- std::ostream &
- Enumerator::AudioOutALSA(std::ostream & stream)
+ static std::ostream &
+ AudioOutALSAEnumerator(std::ostream & stream)
{
return ALSAEnumerate(stream, SND_PCM_STREAM_PLAYBACK);
}
if ( error == 0 )
return available;
- else {
+ else
do_throw(error, "Get Frames Available for Write");
- return 0; // do_throw doesn't return.
- }
}
static bool
driver_manager()->register_audio_output(
"alsa",
Driver::AudioOutALSA,
- Enumerator::AudioOutALSA);
+ AudioOutALSAEnumerator);
return true;
}
static const bool initialized = initializer();
+/// \file platform/posix/platform.h
+/// Platform-specific definitions for POSIX systems.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
+
#include <poll.h>
namespace FreeDV {
/// Type used by poll_fds(). For portability to Windows.
+ ///
typedef struct pollfd PollType;
}
+/// \file platform/posix/privilege.cpp
+/// Privilege tests and warnings on POSIX.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
+
#include <iostream>
#include <unistd.h>
#include <limits.h>
+/// \file platform/posix/scheduler.cpp
+/// Implementation of real-time scheduler tuning and memory locking on POSIX.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
+
#include "drivers.h"
#include <string>
#include <cstring>
#include <sys/mman.h>
#endif
-
-
namespace FreeDV {
static const char privilege_message_a[] =
"Warning: Insufficient privilege to set a real-time scheduling priority,\n"
-/// The constant PTT driver, for testing.
+/// \file ptt_constant.cpp
+/// Implementation of the constant PTT driver, for testing.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
#include <iostream>
#include <stdexcept>
namespace FreeDV {
- /// PTT driver that is constant transmit or constant receive. For testing.
+ /// PTT driver that is constant transmit or constant receive. For testing.
+ ///
class PTTConstant : public PTTInput {
private:
/// This is true if ready has not yet been sent.
+ ///
bool ready_one_shot;
bool pressed;
public:
/// Instantiate push-to-talk source with constant input, for testing.
+ ///
PTTConstant(const char * parameters);
virtual ~PTTConstant();
/// Return file descriptors for poll()
- /// \param size The address of a variable that will be written
- /// with the number of file descriptors in the array.
- /// \return The address of an array of integers containing the
- /// file descriptors.
+ /// \param array The address of an array that will be written
+ /// with a sequence of file descriptors.
+ /// \param space The maximum number of file descriptors that may be
+ /// stored in the array.
+ /// \return The number of file descriptors written to the array.
virtual int poll_fds(PollType * array, int space);
/// Return the amount of bytes ready for read.
+ ///
std::size_t ready();
/// Return true if the PTT input is pressed.
+ ///
bool state();
};
return new ::FreeDV::PTTConstant(parameter);
}
- std::ostream &
- Enumerator::PTTConstant(std::ostream & stream)
+ static std::ostream &
+ PTTConstantEnumerator(std::ostream & stream)
{
return stream;
}
static bool
initializer()
{
- driver_manager()->register_ptt_input("constant", Driver::PTTConstant, Enumerator::PTTConstant);
+ driver_manager()->register_ptt_input("constant", Driver::PTTConstant, PTTConstantEnumerator);
return true;
}
- static const bool initialized = initializer();
+ static const bool UNUSED initialized = initializer();
}
-/// The virtual base class of PTT input drivers.
+/// \file ptt_input.cpp
+/// Implement the virtual base class of PTT input device drivers.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
+/// \file run.cpp
/// The main loop of the program.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
#include <iostream>
///
namespace FreeDV {
+ /// This class implements the main loop of the FreeDV program.
+ ///
class Run {
private:
const std::size_t FIFOSize = MaximumFrameSamples * sizeof(int16_t) * 2;
PollType poll_fds[100];
bool add_poll_device(IODevice * device);
- void do_throw(int error, const char * message);
+ NORETURN void do_throw(int error, const char * message);
void key_down();
void key_up();
void receive();
void transmit_digital();
void transmit_ssb();
public:
- Run(Interfaces *);
+ /// Construct the context for the main loop of FreeDV.
+ /// \param interfaces the address of an Interfaces instance containing
+ /// information on all of the selected device and algorithm drivers.
+ Run(Interfaces * interfaces);
~Run();
+ /// Run the main loop of FreeDV.
+ ///
void run();
};
poll_fd_count = new_size;
return new_size > 0;
}
- else {
+ else
do_throw(0, "Too many file descriptors for poll");
- return false; // do_throw() does not return.
- }
}
else {
std::ostringstream str;
device->print(str);
do_throw(result, str.str().c_str());
- return false; // do_throw() does not return.
}
}
- void
+ NORETURN void
Run::do_throw(const int error, const char * message = 0)
{
std::ostringstream str;
+/// \file text_constant.cpp
/// The constant text driver, just outputs the same text over and over.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
#include <stdexcept>
namespace FreeDV {
/// This driver provides constant text.
+ ///
class TextConstant : public TextInput {
private:
std::size_t index;
virtual ~TextConstant();
/// Return file descriptors for poll()
- /// \param size The address of a variable that will be written
- /// with the number of file descriptors in the array.
- /// \return The address of an array of integers containing the
- /// file descriptors.
+ /// \param array The address of an array that will be written
+ /// with a sequence of file descriptors.
+ /// \param space The maximum number of file descriptors that may be
+ /// stored in the array.
+ /// \return The number of file descriptors written to the array.
virtual int poll_fds(PollType * array, int space);
/// Read the text data.
return new ::FreeDV::TextConstant(parameter);
}
- std::ostream &
- Enumerator::TextConstant(std::ostream & stream)
+ static std::ostream &
+ TextConstantEnumerator(std::ostream & stream)
{
return stream;
}
static bool
initializer()
{
- driver_manager()->register_text_input("constant", Driver::TextConstant, Enumerator::TextConstant);
+ driver_manager()->register_text_input("constant", Driver::TextConstant, TextConstantEnumerator);
return true;
}
- static const bool initialized = initializer();
+ static const bool UNUSED initialized = initializer();
}
-/// The virtual base class for text input drivers.
+/// \file
+/// Implement the virtual base class for text input drivers.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
+/// \file tiny_main.cpp
/// The tiny main program for embedded use.
-
-/*
- * Main program for embedded use.
- */
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
+/// \file tone.cpp
/// The tone audio input driver, for testing.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
+
#include "drivers.h"
#include <sstream>
namespace FreeDV {
/// This is a test driver that provides tones.
+ ///
class Tone : public AudioInput {
private:
unsigned int clock;
return new ::FreeDV::Tone(parameter);
}
- std::ostream &
- Enumerator::Tone(std::ostream & stream)
+ static std::ostream &
+ ToneEnumerator(std::ostream & stream)
{
return stream;
}
static bool
initializer()
{
- driver_manager()->register_audio_input("tone", Driver::Tone, Enumerator::Tone);
+ driver_manager()->register_audio_input("tone", Driver::Tone, ToneEnumerator);
return true;
}
- static const bool initialized = initializer();
+ static const bool UNUSED initialized = initializer();
}
+/// \file user_interface.cpp
/// The virtual base class for user interface drivers.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
#include "drivers.h"
+/// \file utility.cpp
+/// Catch-all for utility functions.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
+
#include "drivers.h"
#include <string.h>