Neu structure for the paging process (B-Netz)
Paging tones are not created within sound_alsa.c The audio API is now responsible to switch to paging channel. In case of SDR, the sdr.c will switch frequency offset.
This commit is contained in:
@@ -473,7 +473,7 @@ int call_init(const char *station_id, const char *audiodev, int samplerate, int
|
||||
return 0;
|
||||
|
||||
/* open sound device for call control */
|
||||
call.sound = sound_open(audiodev, NULL, NULL, 1, samplerate, 3700.0, 0.0);
|
||||
call.sound = sound_open(audiodev, NULL, NULL, 1, 0.0, samplerate, 3700.0, 0.0);
|
||||
if (!call.sound) {
|
||||
PDEBUG(DSENDER, DEBUG_ERROR, "No sound device!\n");
|
||||
|
||||
@@ -671,7 +671,7 @@ void process_call(int c)
|
||||
jitter_load(&call.dejitter, up, count);
|
||||
}
|
||||
spl_list[0] = up;
|
||||
rc = sound_write(call.sound, spl_list, count, 1);
|
||||
rc = sound_write(call.sound, spl_list, count, NULL, NULL, 1);
|
||||
if (rc < 0) {
|
||||
PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to sound device (rc = %d)\n", rc);
|
||||
if (rc == -EPIPE)
|
||||
|
116
src/common/sdr.c
116
src/common/sdr.c
@@ -17,12 +17,13 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "filter.h"
|
||||
#include "sdr.h"
|
||||
#include "sender.h"
|
||||
#ifdef HAVE_UHD
|
||||
#include "uhd.h"
|
||||
#endif
|
||||
@@ -42,7 +43,9 @@ typedef struct sdr_chan {
|
||||
} sdr_chan_t;
|
||||
|
||||
typedef struct sdr {
|
||||
sdr_chan_t *chan;
|
||||
sdr_chan_t *chan; /* settings for all channels */
|
||||
int paging_channel; /* if set, points to paging channel */
|
||||
sdr_chan_t paging_chan; /* settings for extra paging channel */
|
||||
double spl_deviation; /* how to convert a sample step into deviation (Hz) */
|
||||
int channels; /* number of frequencies */
|
||||
double samplerate; /* IQ rate */
|
||||
@@ -73,10 +76,10 @@ int sdr_init(const char *device_args, double rx_gain, double tx_gain)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *sdr_open(const char __attribute__((__unused__)) *audiodev, double *tx_frequency, double *rx_frequency, int channels, int samplerate, double bandwidth, double sample_deviation)
|
||||
void *sdr_open(const char __attribute__((__unused__)) *audiodev, double *tx_frequency, double *rx_frequency, int channels, double paging_frequency, int samplerate, double bandwidth, double sample_deviation)
|
||||
{
|
||||
sdr_t *sdr;
|
||||
double center_frequency;
|
||||
double tx_center_frequency, rx_center_frequency;
|
||||
int rc;
|
||||
int c;
|
||||
|
||||
@@ -95,8 +98,14 @@ void *sdr_open(const char __attribute__((__unused__)) *audiodev, double *tx_freq
|
||||
sdr->spl_deviation = sample_deviation;
|
||||
sdr->amplitude = 0.4 / (double)channels; // FIXME: actual amplitude 0.1?
|
||||
|
||||
/* special case where we use a paging frequency */
|
||||
if (paging_frequency) {
|
||||
/* add extra paging channel */
|
||||
sdr->paging_channel = channels;
|
||||
}
|
||||
|
||||
/* create list of channel states */
|
||||
sdr->chan = calloc(sizeof(*sdr->chan), channels);
|
||||
sdr->chan = calloc(sizeof(*sdr->chan), channels + (sdr->paging_channel != 0));
|
||||
if (!sdr->chan) {
|
||||
PDEBUG(DSDR, DEBUG_ERROR, "NO MEM!\n");
|
||||
goto error;
|
||||
@@ -105,43 +114,74 @@ void *sdr_open(const char __attribute__((__unused__)) *audiodev, double *tx_freq
|
||||
PDEBUG(DSDR, DEBUG_INFO, "Frequency #%d: TX = %.6f MHz, RX = %.6f MHz\n", c, tx_frequency[c] / 1e6, rx_frequency[c] / 1e6);
|
||||
sdr->chan[c].tx_frequency = tx_frequency[c];
|
||||
sdr->chan[c].rx_frequency = rx_frequency[c];
|
||||
#warning check rx frequency is in range
|
||||
filter_lowpass_init(&sdr->chan[c].rx_lp[0], bandwidth, samplerate);
|
||||
filter_lowpass_init(&sdr->chan[c].rx_lp[1], bandwidth, samplerate);
|
||||
}
|
||||
if (sdr->paging_channel) {
|
||||
PDEBUG(DSDR, DEBUG_INFO, "Paging Frequency: TX = %.6f MHz\n", paging_frequency / 1e6);
|
||||
sdr->chan[sdr->paging_channel].tx_frequency = paging_frequency;
|
||||
}
|
||||
|
||||
/* calculate required bandwidth (IQ rate) */
|
||||
if (channels == 1) {
|
||||
PDEBUG(DSDR, DEBUG_INFO, "Single frequency, so we use sample rate as IQ bandwidth: %.6f MHz\n", sdr->samplerate / 1e6);
|
||||
center_frequency = sdr->chan[0].tx_frequency;
|
||||
} else {
|
||||
double low_frequency = sdr->chan[0].tx_frequency, high_frequency = sdr->chan[0].tx_frequency, range;
|
||||
for (c = 1; c < channels; c++) {
|
||||
if (sdr->chan[c].tx_frequency < low_frequency)
|
||||
low_frequency = sdr->chan[c].tx_frequency;
|
||||
if (sdr->chan[c].tx_frequency > high_frequency)
|
||||
high_frequency = sdr->chan[c].tx_frequency;
|
||||
}
|
||||
range = high_frequency - low_frequency;
|
||||
PDEBUG(DSDR, DEBUG_INFO, "Range between frequencies: %.6f MHz\n", range / 1e6);
|
||||
if (range * 2 > sdr->samplerate) {
|
||||
// why that? actually i don't know. i just want to be safe....
|
||||
PDEBUG(DSDR, DEBUG_NOTICE, "The sample rate must be at least twice the range between frequencies. Please increment samplerate!\n");
|
||||
goto error;
|
||||
}
|
||||
center_frequency = (high_frequency + low_frequency) / 2.0;
|
||||
double tx_low_frequency = sdr->chan[0].tx_frequency, tx_high_frequency = sdr->chan[0].tx_frequency;
|
||||
double rx_low_frequency = sdr->chan[0].rx_frequency, rx_high_frequency = sdr->chan[0].rx_frequency;
|
||||
double range;
|
||||
for (c = 1; c < channels; c++) {
|
||||
if (sdr->chan[c].tx_frequency < tx_low_frequency)
|
||||
tx_low_frequency = sdr->chan[c].tx_frequency;
|
||||
if (sdr->chan[c].tx_frequency > tx_high_frequency)
|
||||
tx_high_frequency = sdr->chan[c].tx_frequency;
|
||||
if (sdr->chan[c].rx_frequency < rx_low_frequency)
|
||||
rx_low_frequency = sdr->chan[c].rx_frequency;
|
||||
if (sdr->chan[c].rx_frequency > rx_high_frequency)
|
||||
rx_high_frequency = sdr->chan[c].rx_frequency;
|
||||
}
|
||||
PDEBUG(DSDR, DEBUG_INFO, "Using center frequency: %.6f MHz\n", center_frequency / 1e6);
|
||||
if (sdr->paging_channel) {
|
||||
if (sdr->chan[sdr->paging_channel].tx_frequency < tx_low_frequency)
|
||||
tx_low_frequency = sdr->chan[sdr->paging_channel].tx_frequency;
|
||||
if (sdr->chan[sdr->paging_channel].tx_frequency > tx_high_frequency)
|
||||
tx_high_frequency = sdr->chan[sdr->paging_channel].tx_frequency;
|
||||
}
|
||||
/* range of TX */
|
||||
range = tx_high_frequency - tx_low_frequency;
|
||||
if (range)
|
||||
PDEBUG(DSDR, DEBUG_INFO, "Range between all TX Frequencies: %.6f MHz\n", range / 1e6);
|
||||
if (range * 2 > sdr->samplerate) {
|
||||
// why that? actually i don't know. i just want to be safe....
|
||||
PDEBUG(DSDR, DEBUG_NOTICE, "The sample rate must be at least twice the range between frequencies.\n");
|
||||
PDEBUG(DSDR, DEBUG_NOTICE, "The given rate is %.6f MHz, but required rate must be >= %.6f MHz\n", sdr->samplerate / 1e6, range * 2.0 / 1e6);
|
||||
PDEBUG(DSDR, DEBUG_NOTICE, "Please increase samplerate!\n");
|
||||
goto error;
|
||||
}
|
||||
tx_center_frequency = (tx_high_frequency + tx_low_frequency) / 2.0;
|
||||
PDEBUG(DSDR, DEBUG_INFO, "Using TX center frequency: %.6f MHz\n", tx_center_frequency / 1e6);
|
||||
/* range of RX */
|
||||
range = rx_high_frequency - rx_low_frequency;
|
||||
if (range)
|
||||
PDEBUG(DSDR, DEBUG_INFO, "Range between all RX Frequencies: %.6f MHz\n", range / 1e6);
|
||||
if (range * 2.0 > sdr->samplerate) {
|
||||
// why that? actually i don't know. i just want to be safe....
|
||||
PDEBUG(DSDR, DEBUG_NOTICE, "The sample rate must be at least twice the range between frequencies. Please increment samplerate!\n");
|
||||
goto error;
|
||||
}
|
||||
rx_center_frequency = (rx_high_frequency + rx_low_frequency) / 2.0;
|
||||
PDEBUG(DSDR, DEBUG_INFO, "Using RX center frequency: %.6f MHz\n", rx_center_frequency / 1e6);
|
||||
/* set offsets to center frequency */
|
||||
for (c = 0; c < channels; c++) {
|
||||
sdr->chan[c].offset = sdr->chan[c].tx_frequency - center_frequency;
|
||||
sdr->chan[c].rx_rot = 2 * M_PI * -sdr->chan[c].offset / sdr->samplerate;
|
||||
PDEBUG(DSDR, DEBUG_INFO, "Frequency #%d offset: %.6f MHz\n", c, sdr->chan[c].offset / 1e6);
|
||||
double rx_offset;
|
||||
sdr->chan[c].offset = sdr->chan[c].tx_frequency - tx_center_frequency;
|
||||
rx_offset = sdr->chan[c].rx_frequency - rx_center_frequency;
|
||||
sdr->chan[c].rx_rot = 2 * M_PI * -rx_offset / sdr->samplerate;
|
||||
PDEBUG(DSDR, DEBUG_INFO, "Frequency #%d: TX offset: %.6f MHz, RX offset: %.6f MHz\n", c, sdr->chan[c].offset / 1e6, rx_offset / 1e6);
|
||||
}
|
||||
if (sdr->paging_channel) {
|
||||
sdr->chan[sdr->paging_channel].offset = sdr->chan[sdr->paging_channel].tx_frequency - tx_center_frequency;
|
||||
PDEBUG(DSDR, DEBUG_INFO, "Paging Frequency: TX offset: %.6f MHz\n", sdr->chan[sdr->paging_channel].offset / 1e6);
|
||||
}
|
||||
PDEBUG(DSDR, DEBUG_INFO, "Using gain: TX %.1f dB, RX %.1f dB\n", sdr_tx_gain, sdr_rx_gain);
|
||||
|
||||
#ifdef HAVE_UHD
|
||||
#warning hack
|
||||
rc = uhd_open(sdr_device_args, center_frequency, center_frequency - sdr->chan[0].tx_frequency + sdr->chan[0].rx_frequency, sdr->samplerate, sdr_rx_gain, sdr_tx_gain);
|
||||
rc = uhd_open(sdr_device_args, tx_center_frequency, rx_center_frequency, sdr->samplerate, sdr_rx_gain, sdr_tx_gain);
|
||||
if (rc)
|
||||
goto error;
|
||||
#endif
|
||||
@@ -168,12 +208,12 @@ void sdr_close(void *inst)
|
||||
}
|
||||
}
|
||||
|
||||
int sdr_write(void *inst, int16_t **samples, int num, int channels)
|
||||
int sdr_write(void *inst, int16_t **samples, int num, enum paging_signal __attribute__((unused)) *paging_signal, int *on, int channels)
|
||||
{
|
||||
sdr_t *sdr = (sdr_t *)inst;
|
||||
float buff[num * 2];
|
||||
int c, s, ss;
|
||||
double rate, phase, amplitude, dev;
|
||||
double rate, offset, phase, amplitude, dev;
|
||||
int sent;
|
||||
|
||||
if (channels != sdr->channels) {
|
||||
@@ -186,11 +226,16 @@ int sdr_write(void *inst, int16_t **samples, int num, int channels)
|
||||
amplitude = sdr->amplitude;
|
||||
memset(buff, 0, sizeof(buff));
|
||||
for (c = 0; c < channels; c++) {
|
||||
/* modulate */
|
||||
phase = sdr->chan[c].tx_phase;
|
||||
/* switch offset to paging channel, if requested */
|
||||
if (on[c] && sdr->paging_channel)
|
||||
offset = sdr->chan[sdr->paging_channel].offset;
|
||||
else
|
||||
offset = sdr->chan[c].offset;
|
||||
/* modulate */
|
||||
for (s = 0, ss = 0; s < num; s++) {
|
||||
/* deviation is defined by the sample value and the offset */
|
||||
dev = sdr->chan[c].offset + (double)samples[c][s] * sdr->spl_deviation;
|
||||
dev = offset + (double)samples[c][s] * sdr->spl_deviation;
|
||||
#ifdef FAST_SINE
|
||||
phase += 256.0 * dev / rate;
|
||||
if (phase < 0.0)
|
||||
@@ -249,7 +294,6 @@ int sdr_read(void *inst, int16_t **samples, int num, int channels)
|
||||
Q[s] = i * sin(phase) + q * cos(phase);
|
||||
}
|
||||
sdr->chan[c].rx_phase = phase;
|
||||
#warning eine interation von 2 f<>hrt zu m<>ll (2. kanal gespiegeltes audio), muss man genauer mal analysieren
|
||||
filter_lowpass_process(&sdr->chan[c].rx_lp[0], I, count, 1);
|
||||
filter_lowpass_process(&sdr->chan[c].rx_lp[1], Q, count, 1);
|
||||
last_phase = sdr->chan[c].rx_last_phase;
|
||||
|
@@ -1,8 +1,8 @@
|
||||
|
||||
int sdr_init(const char *device_args, double rx_gain, double tx_gain);
|
||||
void *sdr_open(const char *audiodev, double *tx_frequency, double *rx_frequency, int channels, int samplerate, double bandwidth, double sample_deviation);
|
||||
void *sdr_open(const char *audiodev, double *tx_frequency, double *rx_frequency, int channels, double paging_frequency, int samplerate, double bandwidth, double sample_deviation);
|
||||
void sdr_close(void *inst);
|
||||
int sdr_write(void *inst, int16_t **samples, int num, int channels);
|
||||
int sdr_write(void *inst, int16_t **samples, int num, enum paging_signal *paging_signal, int *on, int channels);
|
||||
int sdr_read(void *inst, int16_t **samples, int num, int channels);
|
||||
int sdr_get_inbuffer(void *inst);
|
||||
|
||||
|
@@ -32,7 +32,7 @@ static sender_t **sender_tailp = &sender_head;
|
||||
int cant_recover = 0;
|
||||
|
||||
/* Init transceiver instance and link to list of transceivers. */
|
||||
int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empfangsfrequenz, const char *audiodev, int samplerate, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, int loopback, double loss_volume, enum pilot_signal pilot_signal)
|
||||
int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empfangsfrequenz, const char *audiodev, int samplerate, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, int loopback, double loss_volume, enum paging_signal paging_signal)
|
||||
{
|
||||
sender_t *master, *slave;
|
||||
int rc = 0;
|
||||
@@ -49,12 +49,7 @@ int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empf
|
||||
sender->de_emphasis = de_emphasis;
|
||||
sender->loopback = loopback;
|
||||
sender->loss_volume = loss_volume;
|
||||
#ifdef HAVE_SDR
|
||||
if (!strcmp(audiodev, "sdr"))
|
||||
pilot_signal = PILOT_SIGNAL_NONE;
|
||||
#endif
|
||||
sender->pilot_signal = pilot_signal;
|
||||
sender->pilotton_phaseshift = 1.0 / ((double)samplerate / 1000.0);
|
||||
sender->paging_signal = paging_signal;
|
||||
|
||||
PDEBUG_CHAN(DSENDER, DEBUG_DEBUG, "Creating 'Sender' instance\n");
|
||||
|
||||
@@ -73,13 +68,13 @@ int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empf
|
||||
break;
|
||||
}
|
||||
if (master) {
|
||||
if (master->pilot_signal != PILOT_SIGNAL_NONE) {
|
||||
PDEBUG(DSENDER, DEBUG_ERROR, "Cannot share audio device with channel %d, because second channel is used for pilot signal!\n", master->kanal);
|
||||
if (master->paging_signal != PAGING_SIGNAL_NONE && !!strcmp(master->audiodev, "sdr")) {
|
||||
PDEBUG(DSENDER, DEBUG_ERROR, "Cannot share audio device with channel %d, because its second audio channel is used for paging signal! Use different audio device.\n", master->kanal);
|
||||
rc = -EBUSY;
|
||||
goto error;
|
||||
}
|
||||
if (pilot_signal != PILOT_SIGNAL_NONE) {
|
||||
PDEBUG(DSENDER, DEBUG_ERROR, "Cannot share audio device with channel %d, because we need a stereo channel for pilot signal!\n", master->kanal);
|
||||
if (paging_signal != PAGING_SIGNAL_NONE && !!strcmp(audiodev, "sdr")) {
|
||||
PDEBUG(DSENDER, DEBUG_ERROR, "Cannot share audio device with channel %d, because we need a second audio channel for paging signal! Use different audio device.\n", master->kanal);
|
||||
rc = -EBUSY;
|
||||
goto error;
|
||||
}
|
||||
@@ -95,10 +90,6 @@ int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empf
|
||||
/* link audio device */
|
||||
#ifdef HAVE_SDR
|
||||
if (!strcmp(audiodev, "sdr")) {
|
||||
if (pilot_signal != PILOT_SIGNAL_NONE) {
|
||||
PDEBUG(DSENDER, DEBUG_ERROR, "No pilot signal allowed with SDR, please fix!\n");
|
||||
abort();
|
||||
}
|
||||
sender->audio_open = sdr_open;
|
||||
sender->audio_close = sdr_close;
|
||||
sender->audio_read = sdr_read;
|
||||
@@ -169,6 +160,7 @@ int sender_open_audio(void)
|
||||
{
|
||||
sender_t *master, *inst;
|
||||
int channels;
|
||||
double paging_frequency = 0.0;
|
||||
int i;
|
||||
|
||||
for (master = sender_head; master; master = master->next) {
|
||||
@@ -188,10 +180,12 @@ int sender_open_audio(void)
|
||||
rx_f[i] = inst->sendefrequenz;
|
||||
else
|
||||
rx_f[i] = inst->empfangsfrequenz;
|
||||
if (inst->ruffrequenz)
|
||||
paging_frequency = inst->ruffrequenz;
|
||||
}
|
||||
|
||||
/* open device */
|
||||
master->audio = master->audio_open(master->audiodev, tx_f, rx_f, channels, master->samplerate, master->bandwidth, master->sample_deviation);
|
||||
master->audio = master->audio_open(master->audiodev, tx_f, rx_f, channels, paging_frequency, master->samplerate, master->bandwidth, master->sample_deviation);
|
||||
if (!master->audio) {
|
||||
PDEBUG(DSENDER, DEBUG_ERROR, "No audio device!\n");
|
||||
return -EIO;
|
||||
@@ -226,27 +220,6 @@ void sender_destroy(sender_t *sender)
|
||||
jitter_destroy(&sender->dejitter);
|
||||
}
|
||||
|
||||
static void gen_pilotton(sender_t *sender, int16_t *samples, int length)
|
||||
{
|
||||
double phaseshift, phase;
|
||||
int i;
|
||||
|
||||
phaseshift = sender->pilotton_phaseshift;
|
||||
phase = sender->pilotton_phase;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (phase < 0.5)
|
||||
*samples++ = 30000;
|
||||
else
|
||||
*samples++ = -30000;
|
||||
phase += phaseshift;
|
||||
if (phase >= 1.0)
|
||||
phase -= 1.0;
|
||||
}
|
||||
|
||||
sender->pilotton_phase = phase;
|
||||
}
|
||||
|
||||
static void gain_samples(int16_t *samples, int length, double gain)
|
||||
{
|
||||
int i;
|
||||
@@ -271,16 +244,12 @@ void process_sender_audio(sender_t *sender, int *quit, int latspl)
|
||||
|
||||
/* count instances for audio channel */
|
||||
for (num_chan = 0, inst = sender; inst; num_chan++, inst = inst->slave);
|
||||
if (sender->pilot_signal != PILOT_SIGNAL_NONE) {
|
||||
if (num_chan != 1) {
|
||||
PDEBUG(DSENDER, DEBUG_ERROR, "Software error, please fix!\n");
|
||||
abort();
|
||||
}
|
||||
num_chan = 2;
|
||||
}
|
||||
int16_t buff[num_chan][latspl], *samples[num_chan];
|
||||
for (i = 0; i < num_chan; i++)
|
||||
enum paging_signal paging_signal[num_chan];
|
||||
int on[num_chan];
|
||||
for (i = 0; i < num_chan; i++) {
|
||||
samples[i] = buff[i];
|
||||
}
|
||||
|
||||
count = sender->audio_get_inbuffer(sender->audio);
|
||||
if (count < 0) {
|
||||
@@ -321,41 +290,12 @@ cant_recover:
|
||||
/* do pre emphasis towards radio, not wave_write */
|
||||
if (inst->pre_emphasis)
|
||||
pre_emphasis(&inst->estate, samples[i], count);
|
||||
}
|
||||
switch (sender->pilot_signal) {
|
||||
case PILOT_SIGNAL_TONE:
|
||||
/* tone if pilot signal is on */
|
||||
if (sender->pilot_on)
|
||||
gen_pilotton(sender, samples[1], count);
|
||||
else
|
||||
memset(samples[1], 0, count << 1);
|
||||
break;
|
||||
case PILOT_SIGNAL_NOTONE:
|
||||
/* tone if pilot signal is off */
|
||||
if (!sender->pilot_on)
|
||||
gen_pilotton(sender, samples[1], count);
|
||||
else
|
||||
memset(samples[1], 0, count << 1);
|
||||
break;
|
||||
case PILOT_SIGNAL_POSITIVE:
|
||||
/* positive signal if pilot signal is on */
|
||||
if (sender->pilot_on)
|
||||
memset(samples[1], 127, count << 1);
|
||||
else
|
||||
memset(samples[1], 128, count << 1);
|
||||
break;
|
||||
case PILOT_SIGNAL_NEGATIVE:
|
||||
/* negative signal if pilot signal is on */
|
||||
if (sender->pilot_on)
|
||||
memset(samples[1], 128, count << 1);
|
||||
else
|
||||
memset(samples[1], 127, count << 1);
|
||||
break;
|
||||
case PILOT_SIGNAL_NONE:
|
||||
break;
|
||||
/* set paging signal */
|
||||
paging_signal[i] = sender->paging_signal;
|
||||
on[i] = sender->paging_on;
|
||||
}
|
||||
|
||||
rc = sender->audio_write(sender->audio, samples, count, num_chan);
|
||||
rc = sender->audio_write(sender->audio, samples, count, paging_signal, on, num_chan);
|
||||
if (rc < 0) {
|
||||
PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to audio device (rc = %d)\n", rc);
|
||||
if (rc == -EPIPE) {
|
||||
@@ -406,8 +346,8 @@ transmit_later:
|
||||
}
|
||||
}
|
||||
|
||||
void sender_pilot(sender_t *sender, int on)
|
||||
void sender_paging(sender_t *sender, int on)
|
||||
{
|
||||
sender->pilot_on = on;
|
||||
sender->paging_on = on;
|
||||
}
|
||||
|
||||
|
@@ -11,13 +11,13 @@
|
||||
|
||||
#define MAX_SENDER 16
|
||||
|
||||
/* how to send a 'pilot' signal (trigger transmitter) */
|
||||
enum pilot_signal {
|
||||
PILOT_SIGNAL_NONE = 0,
|
||||
PILOT_SIGNAL_TONE,
|
||||
PILOT_SIGNAL_NOTONE,
|
||||
PILOT_SIGNAL_POSITIVE,
|
||||
PILOT_SIGNAL_NEGATIVE,
|
||||
/* how to send a 'paging' signal (trigger transmitter) */
|
||||
enum paging_signal {
|
||||
PAGING_SIGNAL_NONE = 0,
|
||||
PAGING_SIGNAL_TONE,
|
||||
PAGING_SIGNAL_NOTONE,
|
||||
PAGING_SIGNAL_POSITIVE,
|
||||
PAGING_SIGNAL_NEGATIVE,
|
||||
};
|
||||
|
||||
/* common structure of each transmitter */
|
||||
@@ -30,15 +30,16 @@ typedef struct sender {
|
||||
int kanal; /* channel number */
|
||||
double sendefrequenz; /* transmitter frequency */
|
||||
double empfangsfrequenz; /* receiver frequency */
|
||||
double ruffrequenz; /* special paging frequency used for B-Netz */
|
||||
double bandwidth; /* max NF frequency to be transmitted unaffected by filtering */
|
||||
double sample_deviation; /* frequency deviation of one sample step (after pre-emphasis) */
|
||||
|
||||
/* audio */
|
||||
void *audio;
|
||||
char audiodev[64]; /* audio device name (alsa or sdr) */
|
||||
void *(*audio_open)(const char *, double *, double *, int, int, double, double);
|
||||
void *(*audio_open)(const char *, double *, double *, int, double, int, double, double);
|
||||
void (*audio_close)(void *);
|
||||
int (*audio_write)(void *, int16_t **, int, int);
|
||||
int (*audio_write)(void *, int16_t **, int, enum paging_signal *, int *, int);
|
||||
int (*audio_read)(void *, int16_t **, int, int);
|
||||
int (*audio_get_inbuffer)(void *);
|
||||
int samplerate;
|
||||
@@ -67,11 +68,9 @@ typedef struct sender {
|
||||
double loss_volume;
|
||||
loss_t loss;
|
||||
|
||||
/* pilot tone */
|
||||
enum pilot_signal pilot_signal; /* if pilot signal is used and how it is performed */
|
||||
int pilot_on; /* 1 or 0 for on or off */
|
||||
double pilotton_phaseshift; /* phase to shift every sample */
|
||||
double pilotton_phase; /* current phase */
|
||||
/* paging tone */
|
||||
enum paging_signal paging_signal; /* if paging signal is used and how it is performed */
|
||||
int paging_on; /* 1 or 0 for on or off */
|
||||
|
||||
/* display wave */
|
||||
dispwav_t dispwav; /* display wave form */
|
||||
@@ -81,11 +80,11 @@ typedef struct sender {
|
||||
extern sender_t *sender_head;
|
||||
extern int cant_recover;
|
||||
|
||||
int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empfangsfrequenz, const char *audiodev, int samplerate, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, int loopback, double loss_volume, enum pilot_signal pilot_signal);
|
||||
int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empfangsfrequenz, const char *audiodev, int samplerate, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, int loopback, double loss_volume, enum paging_signal paging_signal);
|
||||
void sender_destroy(sender_t *sender);
|
||||
int sender_open_audio(void);
|
||||
void process_sender_audio(sender_t *sender, int *quit, int latspl);
|
||||
void sender_send(sender_t *sender, int16_t *samples, int count);
|
||||
void sender_receive(sender_t *sender, int16_t *samples, int count);
|
||||
void sender_pilot(sender_t *sender, int on);
|
||||
void sender_paging(sender_t *sender, int on);
|
||||
|
||||
|
@@ -1,7 +1,9 @@
|
||||
|
||||
void *sound_open(const char *audiodev, double *tx_frequency, double *rx_frequency, int channels, int samplerate, double bandwidth, double sample_deviation);
|
||||
enum paging_signal;
|
||||
|
||||
void *sound_open(const char *audiodev, double *tx_frequency, double *rx_frequency, int channels, double paging_frequency, int samplerate, double bandwidth, double sample_deviation);
|
||||
void sound_close(void *inst);
|
||||
int sound_write(void *inst, int16_t **samples, int num, int channels);
|
||||
int sound_write(void *inst, int16_t **samples, int num, enum paging_signal *paging_signal, int *on, int channels);
|
||||
int sound_read(void *inst, int16_t **samples, int num, int channels);
|
||||
int sound_get_inbuffer(void *inst);
|
||||
|
||||
|
@@ -21,11 +21,13 @@
|
||||
#include <stdint.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include "debug.h"
|
||||
#include "sound.h"
|
||||
#include "sender.h"
|
||||
|
||||
typedef struct sound {
|
||||
snd_pcm_t *phandle, *chandle;
|
||||
int pchannels, cchannels;
|
||||
double paging_phaseshift; /* phase to shift every sample */
|
||||
double paging_phase; /* current phase */
|
||||
} sound_t;
|
||||
|
||||
static int set_hw_params(snd_pcm_t *handle, int samplerate, int *channels)
|
||||
@@ -128,7 +130,7 @@ static int sound_prepare(sound_t *sound)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *sound_open(const char *audiodev, double __attribute__((unused)) *tx_frequency, double __attribute__((unused)) *rx_frequency, int channels, int samplerate, double __attribute__((unused)) bandwidth, double __attribute__((unused)) sample_deviation)
|
||||
void *sound_open(const char *audiodev, double __attribute__((unused)) *tx_frequency, double __attribute__((unused)) *rx_frequency, int channels, double __attribute__((unused)) paging_frequency, int samplerate, double __attribute__((unused)) bandwidth, double __attribute__((unused)) sample_deviation)
|
||||
{
|
||||
sound_t *sound;
|
||||
int rc;
|
||||
@@ -144,6 +146,8 @@ void *sound_open(const char *audiodev, double __attribute__((unused)) *tx_freque
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sound->paging_phaseshift = 1.0 / ((double)samplerate / 1000.0);
|
||||
|
||||
rc = snd_pcm_open(&sound->phandle, audiodev, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
||||
if (rc < 0) {
|
||||
PDEBUG(DSOUND, DEBUG_ERROR, "Failed to open '%s' for playback! (%s)\n", audiodev, snd_strerror(rc));
|
||||
@@ -200,7 +204,51 @@ void sound_close(void *inst)
|
||||
free(sound);
|
||||
}
|
||||
|
||||
int sound_write(void *inst, int16_t **samples, int num, int channels)
|
||||
static void gen_paging_tone(sound_t *sound, int16_t *samples, int length, enum paging_signal paging_signal, int on)
|
||||
{
|
||||
double phaseshift, phase;
|
||||
int i;
|
||||
|
||||
switch (paging_signal) {
|
||||
case PAGING_SIGNAL_NOTONE:
|
||||
/* no tone if paging signal is on */
|
||||
on = !on;
|
||||
// fall through
|
||||
case PAGING_SIGNAL_TONE:
|
||||
/* tone if paging signal is on */
|
||||
if (on) {
|
||||
phaseshift = sound->paging_phaseshift;
|
||||
phase = sound->paging_phase;
|
||||
for (i = 0; i < length; i++) {
|
||||
if (phase < 0.5)
|
||||
*samples++ = 30000;
|
||||
else
|
||||
*samples++ = -30000;
|
||||
phase += phaseshift;
|
||||
if (phase >= 1.0)
|
||||
phase -= 1.0;
|
||||
}
|
||||
sound->paging_phase = phase;
|
||||
} else
|
||||
memset(samples, 0, length << 1);
|
||||
break;
|
||||
case PAGING_SIGNAL_NEGATIVE:
|
||||
/* negative signal if paging signal is on */
|
||||
on = !on;
|
||||
// fall through
|
||||
case PAGING_SIGNAL_POSITIVE:
|
||||
/* positive signal if paging signal is on */
|
||||
if (on)
|
||||
memset(samples, 127, length << 1);
|
||||
else
|
||||
memset(samples, 128, length << 1);
|
||||
break;
|
||||
case PAGING_SIGNAL_NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int sound_write(void *inst, int16_t **samples, int num, enum paging_signal *paging_signal, int *on, int channels)
|
||||
{
|
||||
sound_t *sound = (sound_t *)inst;
|
||||
int16_t buff[num << 1];
|
||||
@@ -208,15 +256,22 @@ int sound_write(void *inst, int16_t **samples, int num, int channels)
|
||||
int i, ii;
|
||||
|
||||
if (sound->pchannels == 2) {
|
||||
if (channels < 2) {
|
||||
if (paging_signal && on && paging_signal[0] != PAGING_SIGNAL_NONE) {
|
||||
int16_t paging[num << 1];
|
||||
gen_paging_tone(sound, paging, num, paging_signal[0], on[0]);
|
||||
for (i = 0, ii = 0; i < num; i++) {
|
||||
buff[ii++] = samples[0][i];
|
||||
buff[ii++] = paging[i];
|
||||
}
|
||||
} else if (channels == 2) {
|
||||
for (i = 0, ii = 0; i < num; i++) {
|
||||
buff[ii++] = samples[0][i];
|
||||
buff[ii++] = samples[1][i];
|
||||
}
|
||||
} else {
|
||||
for (i = 0, ii = 0; i < num; i++) {
|
||||
buff[ii++] = samples[0][i];
|
||||
buff[ii++] = samples[1][i];
|
||||
buff[ii++] = samples[0][i];
|
||||
}
|
||||
}
|
||||
rc = snd_pcm_writei(sound->phandle, buff, num);
|
||||
|
Reference in New Issue
Block a user