int command;
while ((command = getopt_long(argc, argv, "c:Cdf:hi:k:l:m:M:p:P:r:t:x:", options, NULL)) != -1 ) {
switch (command) {
+ case 0:
+ break;
+ case 'd':
+ drivers();
+ exit(0);
+ default:
+ case 'h':
+ help(argv[0]);
+ exit(1);
+ case 'C':
+ // FIX: Operator overload doesn't work here.
+ i.print(cout, argv[0]) << endl;
+ exit(0);
case 'c':
case 'f':
case 'i':
Base * set = (Base *)1;
+
switch (command) {
case 'c':
set = i.codec = m->codec(driver, parameter);
break;
- case 'd':
- drivers();
- exit(0);
case 'f':
set = i.framer = m->framer(driver, parameter);
break;
- default:
- case 'h':
- help(argv[0]);
- exit(1);
case 'i':
set = i.user_interface = m->user_interface(driver, parameter, &i);
break;
case 'x':
set = i.text_input = m->text_input(driver, parameter);
break;
- case 'C':
- // FIX: Operator overload doesn't work here.
- i.print(cout) << endl;
- exit(0);
- case 0:
- break;
}
if ( set == 0 )
exit(1);
uint8_t * in;
const uint8_t * out;
- void out_overrun() const;
+ void get_overrun() const;
uint8_t * reorder(std::size_t length);
public:
~FIFO();
+ /// Returns the amount of data available to read.
+ /// \return The amount of data, in bytes, available to read.
+ inline std::size_t get_available() const {
+ return in - out;
+ }
+
+ /// Return the address of output data of the requested length.
+ /// \param length The amount of data requested. This must be smaller
+ /// than or equal to the amount returned by get_available().
+ /// \return The address of the data to be read.
+ inline const uint8_t * get(std::size_t length) {
+ if ( length > (std::size_t)(in - out) )
+ get_overrun();
+ return out;
+ }
+
+ /// Finish the I/O after get().
+ /// \param length The amount of data, in bytes, actually read.
+ /// This must be smaller than or equal to the amount passed to
+ /// get().
+ inline void get_done(std::size_t length) {
+ out += length;
+ assert(out >= buffer && out <= buffer_end);
+ if ( out == in )
+ out = in = buffer;
+ }
+
/// Returns the amount of space available for incoming data.
/// \return The amount of space, in bytes, available for incoming data.
- inline std::size_t incoming_available() const {
+ inline std::size_t put_space() const {
return (buffer_end) - in + (out - buffer);
}
/// Throws an error if we run the buffer out of space. Well-behaved code
/// won't allocate a size that can't be drained before it is further
/// written.
- /// You must call incoming_done(length) when the I/O is completed.
- /// The length passed to incoming_done() must be smaller than or equal
- /// to the length passed to incoming_buffer().
+ /// You must call put_done(length) when the I/O is completed.
+ /// The length passed to put_done() must be smaller than or equal
+ /// to the length passed to put().
/// \param io_length The size of buffer in chars requested.
/// \return The address of the buffer for incoming data.
- inline uint8_t * incoming_buffer(std::size_t io_length) {
+ inline uint8_t * put(std::size_t io_length) {
const uint8_t * io_end = in + io_length;
if ( io_end > buffer_end )
return in;
}
- /// Complete the I/O after incoming_buffer().
+ /// Complete the I/O after put().
/// \param length The amount of data actually written. This must be
- /// smaller than or equal to the length passed to incoming_buffer().
- inline void incoming_done(std::size_t length) {
+ /// smaller than or equal to the length passed to put().
+ inline void put_done(std::size_t length) {
in += length;
assert(in >= buffer && in <= buffer_end);
}
- /// Returns the amount of data available to read.
- /// \return The amount of data, in bytes, available to read.
- inline std::size_t outgoing_available() const {
- return in - out;
- }
-
- /// Return the address of output data of the requested length.
- /// \param length The amount of data requested. This must be smaller
- /// than or equal to the amount returned by outgoing_available().
- /// \return The address of the data to be read.
- inline const uint8_t * outgoing_buffer(std::size_t length) {
- if ( length > (std::size_t)(in - out) )
- out_overrun();
- return out;
- }
-
- /// Finish the I/O after outgoing_buffer().
- /// \param length The amount of data, in bytes, actually read.
- /// This must be smaller than or equal to the amount passed to
- /// outgoing_buffer().
- inline void outgoing_done(std::size_t length) {
- out += length;
- assert(out >= buffer && out <= buffer_end);
- }
-
/// Discard any buffered data.
void reset();
};
/// \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;
+ print(std::ostream & stream, const char * program_name) const;
};
/// Write the driver information from the Interfaces object onto a stream,
/// usual successive call paradigm of ostream operator << .
inline std::ostream &
operator << (std::ostream & stream, const Interfaces & interfaces) {
- return interfaces.print(stream);
+ return interfaces.print(stream, 0);
}
// Most of the functions in the Driver and Enumerator namespaces are
}
void
- FIFO::out_overrun() const
+ FIFO::get_overrun() const
{
throw std::runtime_error("FIFO outgoing data overrun.");
}
// memmove() is specified to handle overlap properly.
memmove(buffer, out, bytes);
-#ifdef DEBUG
- std::cerr << "FIFO reorder with copy. Size = " << size
- << ", buffer = " << (void *)buffer << ", buffer_end = "
- << (void *)buffer_end << ", in = " << (void *)in
- << ", out = " << (void *)out
- << std::endl;
-#endif
}
out = buffer;
in = buffer + bytes;
transmitter = Driver::AudioSink(empty);
if ( !receiver )
- receiver = Driver::Tone(empty);
+ receiver = Driver::Tone("1000,1.0");
if ( !user_interface )
user_interface = Driver::BlankPanel(empty, this);
}
std::ostream &
- Interfaces::print(std::ostream & stream) const
+ Interfaces::print(std::ostream & stream, const char * program_name) const
{
- stream << "--codec=" << *codec << std::endl;
- stream << "--gui=" << *user_interface << std::endl;
- stream << "--keying=" << *keying_output << std::endl;
- stream << "--loudspeaker=" << *loudspeaker << std::endl;
- stream << "--microphone=" << *microphone << std::endl;
- stream << "--modem=" << *modem << std::endl;
- stream << "--ptt-digital=" << *ptt_input_digital << std::endl;
- stream << "--ptt-ssb=" << *ptt_input_ssb << std::endl;
- stream << "--receiver=" << *receiver << std::endl;
- stream << "--text=" << *text_input << std::endl;
- stream << "--transmitter=" << *transmitter << std::endl;
+ if ( program_name ) {
+ stream << program_name << " \\" << std::endl;
+ }
+ stream << "--codec=\"" << *codec << "\" \\" << std::endl;
+ stream << "--gui=\"" << *user_interface << "\" \\" << std::endl;
+ stream << "--keying=\"" << *keying_output << "\" \\" << std::endl;
+ stream << "--loudspeaker=\"" << *loudspeaker << "\" \\" << std::endl;
+ stream << "--microphone=\"" << *microphone << "\" \\" << std::endl;
+ stream << "--modem=\"" << *modem << "\" \\" << std::endl;
+ stream << "--ptt-digital=\"" << *ptt_input_digital << "\" \\" << std::endl;
+ stream << "--ptt-ssb=\"" << *ptt_input_ssb << "\" \\" << std::endl;
+ stream << "--receiver=\"" << *receiver << "\" \\" << std::endl;
+ stream << "--text=\"" << *text_input << "\" \\" << std::endl;
+ stream << "--transmitter=\"" << *transmitter << "\"" << std::endl;
return stream;
}
std::size_t data_length)
{
const std::size_t length = min(data_length / 2, *sample_length);
+
memcpy(o, i, length * 2);
*sample_length = length;
return length;
/// The ALSA audio output driver.
#include <stdlib.h>
+#include <errno.h>
#include "drivers.h"
#include <alsa/asoundlib.h>
#include <sys/ioctl.h>
std::size_t
AudioOutALSA::write16(const std::int16_t * array, std::size_t length)
{
- const int result = snd_pcm_writei(handle, array, length);
+ // for ( std::size_t i = 0 ; i < length ; i++ )
+ // std::cerr << array[i] << ' ';
+
+ int result = snd_pcm_writei(handle, array, length);
+ if ( result == -EPIPE ) {
+ snd_pcm_recover(handle, result, 1);
+ result = snd_pcm_writei(handle, array, length);
+ std::cerr << "ALSA write underrun." << std::endl;
+ if ( result == -EPIPE )
+ return 0;
+ }
if ( result >= 0 )
return result;
else {
{
snd_pcm_sframes_t available = 0;
- if ( (available = snd_pcm_avail(handle)) >= 0 )
+ available = snd_pcm_avail(handle);
+ if ( available == -EPIPE ) {
+ snd_pcm_recover(handle, available, 1);
+ available = snd_pcm_avail(handle);
+ std::cerr << "ALSA write underrun." << std::endl;
+ }
+ if ( available >= 0 )
return available;
+ else if ( available == -EPIPE )
+ return 0;
else {
- do_throw(available, "Get Available Frames");
+ do_throw(available, "Get Frames Available for Write");
return 0; // do_throw doesn't return.
}
}
bool begin_receive;
bool begin_transmit;
FIFO codec_fifo;
- FIFO input_fifo;
- FIFO output_fifo;
+ FIFO in_fifo;
+ FIFO out_fifo;
bool ptt_digital;
bool ptt_ssb;
Run::Run(Interfaces * interfaces)
: i(interfaces), begin_receive(true), begin_transmit(false),
- codec_fifo(TempSize * 2), input_fifo(TempSize * 2),
- output_fifo(TempSize * 2), ptt_digital(false), ptt_ssb(false)
+ codec_fifo(TempSize * 2), in_fifo(TempSize * 2),
+ out_fifo(TempSize * 2), ptt_digital(false), ptt_ssb(false)
{
}
void
Run::reset_fifos()
{
- input_fifo.reset();
+ in_fifo.reset();
codec_fifo.reset();
- output_fifo.reset();
+ out_fifo.reset();
}
void
Run::receive()
{
// Drain any data that the loudspeaker can take.
- const std::size_t output_samples = min(
+ const std::size_t out_samples = min(
i->loudspeaker->ready(),
- (output_fifo.outgoing_available() / 2));
+ (out_fifo.get_available() / 2));
- if ( output_samples ) {
+ if ( out_samples ) {
+ std::int16_t * s = (std::int16_t *)out_fifo.get(out_samples * 2);
+
+ for ( std::size_t i = 0; i < out_samples; i++ ) {
+ std::cerr << (double)s[i] / 32767.0 << ' ';
+ }
const std::size_t result = i->loudspeaker->write16(
- (std::int16_t *)output_fifo.outgoing_buffer(
- output_samples * 2),
- output_samples);
+ (std::int16_t *)out_fifo.get(
+ out_samples * 2),
+ out_samples);
if ( result > 0 )
- output_fifo.outgoing_done(result * 2);
+ out_fifo.get_done(result * 2);
else
std::cerr << "Loudspeaker I/O error: " << strerror(errno) << std::endl;
}
// Fill any data that the receiver can provide.
- const std::size_t input_samples = min(
+ const std::size_t in_samples = min(
i->receiver->ready(),
- (input_fifo.incoming_available() / 2));
+ (in_fifo.put_space() / 2));
- if ( input_samples ) {
+ if ( in_samples ) {
const std::size_t result = i->receiver->read16(
- (std::int16_t *)input_fifo.incoming_buffer(input_samples * 2),
- input_samples);
+ (std::int16_t *)in_fifo.put(in_samples * 2),
+ in_samples);
if ( result > 0 )
- input_fifo.incoming_done(result * 2);
+ in_fifo.put_done(result * 2);
else
- std::cerr << "Loudspeaker I/O error: " << strerror(errno) << std::endl;
+ std::cerr << "Receiver I/O error: " << strerror(errno) << std::endl;
}
- const std::size_t frames_to_demodulate = (codec_fifo.incoming_available()
- / i->modem->bytes_per_frame());
-
- if ( frames_to_demodulate && input_fifo.outgoing_available() > i->modem->bytes_per_frame()) {
- std::size_t samples_to_demodulate = input_fifo.outgoing_available()
- / 2;
- const std::size_t bytes_to_demodulate = frames_to_demodulate
- * i->modem->bytes_per_frame();
+ if ( in_fifo.get_available() > 0 ) {
+ std::size_t samples_to_demodulate = in_fifo.get_available() / 2;
+ const std::size_t bytes_to_demodulate = codec_fifo.put_space();
std::size_t result = i->modem->demodulate16(
- (const std::int16_t *)input_fifo.outgoing_buffer(
+ (const std::int16_t *)in_fifo.get(
samples_to_demodulate * 2),
- codec_fifo.incoming_buffer(bytes_to_demodulate),
+ codec_fifo.put(bytes_to_demodulate),
&samples_to_demodulate,
bytes_to_demodulate);
if ( samples_to_demodulate > 0 )
- input_fifo.outgoing_done(samples_to_demodulate * 2);
+ in_fifo.get_done(samples_to_demodulate * 2);
if ( result > 0 )
- codec_fifo.incoming_done(result);
+ codec_fifo.put_done(result);
}
- const std::size_t frames_to_decode =
- (output_fifo.incoming_available() / 2)
- / i->codec->samples_per_frame();
-
- if ( frames_to_decode > 0
- && codec_fifo.outgoing_available() > i->codec->bytes_per_frame() ) {
- std::size_t bytes_to_decode = codec_fifo.outgoing_available();
+ if ( codec_fifo.get_available() > 0 ) {
+ std::size_t bytes_to_decode = codec_fifo.get_available();
- const std::size_t samples_to_decode = frames_to_decode \
- * i->codec->samples_per_frame();
+ const std::size_t samples_to_decode = out_fifo.put_space() / 2;
const std::size_t result = i->codec->decode16(
- codec_fifo.outgoing_buffer(bytes_to_decode),
- (std::int16_t *)output_fifo.incoming_buffer(
+ codec_fifo.get(bytes_to_decode),
+ (std::int16_t *)out_fifo.put(
samples_to_decode * 2),
&bytes_to_decode,
samples_to_decode);
if ( bytes_to_decode > 0 )
- codec_fifo.outgoing_done(bytes_to_decode);
+ codec_fifo.get_done(bytes_to_decode);
if ( result > 0 )
- output_fifo.incoming_done(result * 2);
+ out_fifo.put_done(result * 2);
}
}
};
TEST_F(FIFOTest, CanFillAndDrain) {
- ASSERT_EQ(100U, f->incoming_available());
- memset(f->incoming_buffer(100), 255, 100);
- ASSERT_EQ(0U, f->outgoing_available());
- f->incoming_done(100);
- ASSERT_EQ(100U, f->outgoing_available());
- ASSERT_EQ(0U, f->incoming_available());
- EXPECT_THROW(f->incoming_buffer(1), std::runtime_error);
- ASSERT_EQ(100U, f->outgoing_available());
- ASSERT_NE((uint8_t *)0, f->outgoing_buffer(100));
- f->outgoing_done(100);
- ASSERT_EQ(0U, f->outgoing_available());
- ASSERT_EQ(100U, f->incoming_available());
- ASSERT_EQ(100U, f->incoming_available());
- memset(f->incoming_buffer(100), 255, 100);
- ASSERT_EQ(0U, f->outgoing_available());
- f->incoming_done(100);
- ASSERT_EQ(100U, f->outgoing_available());
- ASSERT_EQ(0U, f->incoming_available());
+ ASSERT_EQ(100U, f->put_space());
+ memset(f->put(100), 255, 100);
+ ASSERT_EQ(0U, f->get_available());
+ f->put_done(100);
+ ASSERT_EQ(100U, f->get_available());
+ ASSERT_EQ(0U, f->put_space());
+ EXPECT_THROW(f->put(1), std::runtime_error);
+ ASSERT_EQ(100U, f->get_available());
+ ASSERT_NE((uint8_t *)0, f->get(100));
+ f->get_done(100);
+ ASSERT_EQ(0U, f->get_available());
+ ASSERT_EQ(100U, f->put_space());
+ ASSERT_EQ(100U, f->put_space());
+ memset(f->put(100), 255, 100);
+ ASSERT_EQ(0U, f->get_available());
+ f->put_done(100);
+ ASSERT_EQ(100U, f->get_available());
+ ASSERT_EQ(0U, f->put_space());
}
TEST_F(FIFOTest, Reorder) {
uint8_t * b;
const uint8_t * r;
- ASSERT_EQ(100U, f->incoming_available());
- ASSERT_NE((uint8_t *)0, b = f->incoming_buffer(99));
+ ASSERT_EQ(100U, f->put_space());
+ ASSERT_NE((uint8_t *)0, b = f->put(99));
memset(b, 0, 98);
b[98] = 'b';
- f->incoming_done(99);
- ASSERT_EQ(1U, f->incoming_available());
- ASSERT_EQ(99U, f->outgoing_available());
- ASSERT_NE((uint8_t *)0, f->outgoing_buffer(98));
- f->outgoing_done(98);
- ASSERT_EQ(1U, f->outgoing_available());
- ASSERT_EQ(99U, f->incoming_available());
+ f->put_done(99);
+ ASSERT_EQ(1U, f->put_space());
+ ASSERT_EQ(99U, f->get_available());
+ ASSERT_NE((uint8_t *)0, f->get(98));
+ f->get_done(98);
+ ASSERT_EQ(1U, f->get_available());
+ ASSERT_EQ(99U, f->put_space());
// This should cause reorder().
- ASSERT_NE((uint8_t *)0, b = f->incoming_buffer(2));
- f->incoming_done(0);
- ASSERT_EQ(99U, f->incoming_available());
- ASSERT_EQ(1U, f->outgoing_available());
- ASSERT_NE((uint8_t *)0, r = f->outgoing_buffer(1));
+ ASSERT_NE((uint8_t *)0, b = f->put(2));
+ f->put_done(0);
+ ASSERT_EQ(99U, f->put_space());
+ ASSERT_EQ(1U, f->get_available());
+ ASSERT_NE((uint8_t *)0, r = f->get(1));
ASSERT_EQ('b', *r);
- f->outgoing_done(1);
+ f->get_done(1);
}
TEST_F(FIFOTest, CanReset) {
- ASSERT_EQ(100U, f->incoming_available());
- ASSERT_EQ(0U, f->outgoing_available());
- f->incoming_done(100);
- ASSERT_EQ(100U, f->outgoing_available());
- ASSERT_EQ(0U, f->incoming_available());
+ ASSERT_EQ(100U, f->put_space());
+ ASSERT_EQ(0U, f->get_available());
+ f->put_done(100);
+ ASSERT_EQ(100U, f->get_available());
+ ASSERT_EQ(0U, f->put_space());
f->reset();
- ASSERT_EQ(0U, f->outgoing_available());
- ASSERT_EQ(100U, f->incoming_available());
+ ASSERT_EQ(0U, f->get_available());
+ ASSERT_EQ(100U, f->put_space());
}