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:
Andreas Eversberg 2017-01-07 10:33:13 +01:00
parent 57993e3e48
commit 8b9277615d
15 changed files with 238 additions and 197 deletions

View File

@ -536,7 +536,7 @@ The actual level is not yet relevant.
...
bnetz.c:316 info : Entering IDLE state, sending 'Gruppenfreisignal' 2 on channel 1.
Base station ready, please tune transmitter to 153.010 MHz and receiver to 148.410 MHz.
To call phone, switch transmitter (using pilot signal) to 153.370 MHz.
To call phone, switch transmitter (using paging signal) to 153.370 MHz.
on-hook: ..... (enter 0..9 or d=dial)
</pre>
@ -555,7 +555,7 @@ Set the selector for the base station ID ("Gruppenfreisignal") to 0.
bnetz.c:351 info : Entering IDLE state, sending 'Gruppenfreisignal' 2.
Base station for channel 1 ready, please tune transmitter to 153.010 MHz and receiver to 148.410 MHz.
To call phone, switch transmitter (using pilot signal) to 153.370 MHz.
To call phone, switch transmitter (using paging signal) to 153.370 MHz.
mncc_sock.c:137 notice : MNCC socket connected.
dsp.c:159 info : Detecting continous tone: 2070:Level= 80% Quality=100%
bnetz.c:470 info : Received signal 'Kanalbelegung' from mobile station, sending signal 'Wahlabruf'.

View File

@ -442,7 +442,7 @@ int amps_create(int channel, enum amps_chan_type chan_type, const char *audiodev
PDEBUG(DAMPS, DEBUG_DEBUG, "Creating 'AMPS' instance for channel = %d (sample rate %d).\n", channel, samplerate);
/* init general part of transceiver */
rc = sender_create(&amps->sender, channel, amps_channel2freq(channel, 0), amps_channel2freq(channel, 1), audiodev, samplerate, rx_gain, 0, 0, write_rx_wave, write_tx_wave, read_rx_wave, loopback, 0, PILOT_SIGNAL_NONE);
rc = sender_create(&amps->sender, channel, amps_channel2freq(channel, 0), amps_channel2freq(channel, 1), audiodev, samplerate, rx_gain, 0, 0, write_rx_wave, write_tx_wave, read_rx_wave, loopback, 0, PAGING_SIGNAL_NONE);
if (rc < 0) {
PDEBUG(DAMPS, DEBUG_ERROR, "Failed to init transceiver process!\n");
goto error;

View File

@ -187,7 +187,7 @@ int anetz_create(int kanal, const char *audiodev, int samplerate, double rx_gain
PDEBUG(DANETZ, DEBUG_DEBUG, "Creating 'A-Netz' instance for 'Kanal' = %d (sample rate %d).\n", kanal, samplerate);
/* init general part of transceiver */
rc = sender_create(&anetz->sender, kanal, anetz_kanal2freq(kanal, 0), anetz_kanal2freq(kanal, 1), audiodev, samplerate, rx_gain, pre_emphasis, de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, loopback, loss_volume, PILOT_SIGNAL_NONE);
rc = sender_create(&anetz->sender, kanal, anetz_kanal2freq(kanal, 0), anetz_kanal2freq(kanal, 1), audiodev, samplerate, rx_gain, pre_emphasis, de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, loopback, loss_volume, PAGING_SIGNAL_NONE);
if (rc < 0) {
PDEBUG(DANETZ, DEBUG_ERROR, "Failed to init 'Sender' processing!\n");
goto error;

View File

@ -109,23 +109,23 @@ double bnetz_kanal2freq(int kanal, int unterband)
return freq * 1e6;
}
/* switch pilot signal (tone or file) */
/* switch paging signal (tone or file) */
static void switch_channel_19(bnetz_t *bnetz, int on)
{
/* affects only if pilot signal is used */
sender_pilot(&bnetz->sender, on);
/* affects only if paging signal is used */
sender_paging(&bnetz->sender, on);
if (bnetz->pilot_file[0] && bnetz->pilot_is_on != on) {
if (bnetz->paging_file[0] && bnetz->paging_is_on != on) {
FILE *fp;
fp = fopen(bnetz->pilot_file, "w");
fp = fopen(bnetz->paging_file, "w");
if (!fp) {
PDEBUG(DBNETZ, DEBUG_ERROR, "Failed to open file '%s' to switch channel 19!\n", bnetz->pilot_file);
PDEBUG(DBNETZ, DEBUG_ERROR, "Failed to open file '%s' to switch channel 19!\n", bnetz->paging_file);
return;
}
fprintf(fp, "%s\n", (on) ? bnetz->pilot_on : bnetz->pilot_off);
fprintf(fp, "%s\n", (on) ? bnetz->paging_on : bnetz->paging_off);
fclose(fp);
bnetz->pilot_is_on = on;
bnetz->paging_is_on = on;
}
}
@ -141,11 +141,11 @@ static void bnetz_timeout(struct timer *timer);
static void bnetz_go_idle(bnetz_t *bnetz);
/* Create transceiver instance and link to a list. */
int bnetz_create(int kanal, const char *audiodev, int samplerate, double rx_gain, int gfs, 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_factor, const char *pilot)
int bnetz_create(int kanal, const char *audiodev, int samplerate, double rx_gain, int gfs, 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_factor, const char *paging)
{
bnetz_t *bnetz;
enum pilot_signal pilot_signal = PILOT_SIGNAL_NONE;
char pilot_file[256] = "", pilot_on[256] = "", pilot_off[256] = "";
enum paging_signal paging_signal = PAGING_SIGNAL_NONE;
char paging_file[256] = "", paging_on[256] = "", paging_off[256] = "";
int rc;
if (!(kanal >= 1 && kanal <= 39) && !(kanal >= 50 && kanal <= 86)) {
@ -163,34 +163,34 @@ int bnetz_create(int kanal, const char *audiodev, int samplerate, double rx_gain
return -EINVAL;
}
if (!strcmp(pilot, "notone"))
pilot_signal = PILOT_SIGNAL_NOTONE;
if (!strcmp(paging, "notone"))
paging_signal = PAGING_SIGNAL_NOTONE;
else
if (!strcmp(pilot, "tone"))
pilot_signal = PILOT_SIGNAL_TONE;
if (!strcmp(paging, "tone"))
paging_signal = PAGING_SIGNAL_TONE;
else
if (!strcmp(pilot, "positive"))
pilot_signal = PILOT_SIGNAL_POSITIVE;
if (!strcmp(paging, "positive"))
paging_signal = PAGING_SIGNAL_POSITIVE;
else
if (!strcmp(pilot, "negative"))
pilot_signal = PILOT_SIGNAL_NEGATIVE;
if (!strcmp(paging, "negative"))
paging_signal = PAGING_SIGNAL_NEGATIVE;
else {
char *p;
strncpy(pilot_file, pilot, sizeof(pilot_file) - 1);
p = strchr(pilot_file, '=');
strncpy(paging_file, paging, sizeof(paging_file) - 1);
p = strchr(paging_file, '=');
if (!p) {
error_pilot:
PDEBUG(DBNETZ, DEBUG_ERROR, "Given pilot file (to switch to channel 19) is missing parameters. Use <file>=<on>:<off> format!\n");
error_paging:
PDEBUG(DBNETZ, DEBUG_ERROR, "Given paging file (to switch to channel 19) is missing parameters. Use <file>=<on>:<off> format!\n");
return -EINVAL;
}
*p++ = '\0';
strncpy(pilot_on, p, sizeof(pilot_on) - 1);
p = strchr(pilot_file, ':');
strncpy(paging_on, p, sizeof(paging_on) - 1);
p = strchr(paging_on, ':');
if (!p)
goto error_pilot;
goto error_paging;
*p++ = '\0';
strncpy(pilot_off, p, sizeof(pilot_off) - 1);
strncpy(paging_off, p, sizeof(paging_off) - 1);
}
bnetz = calloc(1, sizeof(bnetz_t));
@ -202,11 +202,12 @@ error_pilot:
PDEBUG(DBNETZ, DEBUG_DEBUG, "Creating 'B-Netz' instance for 'Kanal' = %d 'Gruppenfreisignal' = %d (sample rate %d).\n", kanal, gfs, samplerate);
/* init general part of transceiver */
rc = sender_create(&bnetz->sender, kanal, bnetz_kanal2freq(kanal, 0), bnetz_kanal2freq(kanal, 1), audiodev, samplerate, rx_gain, pre_emphasis, de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, loopback, loss_factor, pilot_signal);
rc = sender_create(&bnetz->sender, kanal, bnetz_kanal2freq(kanal, 0), bnetz_kanal2freq(kanal, 1), audiodev, samplerate, rx_gain, pre_emphasis, de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, loopback, loss_factor, paging_signal);
if (rc < 0) {
PDEBUG(DBNETZ, DEBUG_ERROR, "Failed to init transceiver process!\n");
goto error;
}
bnetz->sender.ruffrequenz = bnetz_kanal2freq(19, 0);
/* init audio processing */
rc = dsp_init_sender(bnetz);
@ -216,9 +217,9 @@ error_pilot:
}
bnetz->gfs = gfs;
strncpy(bnetz->pilot_file, pilot_file, sizeof(bnetz->pilot_file) - 1);
strncpy(bnetz->pilot_on, pilot_on, sizeof(bnetz->pilot_on) - 1);
strncpy(bnetz->pilot_off, pilot_off, sizeof(bnetz->pilot_off) - 1);
strncpy(bnetz->paging_file, paging_file, sizeof(bnetz->paging_file) - 1);
strncpy(bnetz->paging_on, paging_on, sizeof(bnetz->paging_on) - 1);
strncpy(bnetz->paging_off, paging_off, sizeof(bnetz->paging_off) - 1);
timer_init(&bnetz->timer, bnetz_timeout, bnetz);
/* go into idle state */

View File

@ -53,10 +53,10 @@ typedef struct bnetz {
int gfs; /* 'Gruppenfreisignal' */
/* switch sender to channel 19 */
char pilot_file[256]; /* if set, write to given file to switch to channel 19 or back */
char pilot_on[256]; /* what to write to switch to channel 19 */
char pilot_off[256]; /* what to write to switch back */
int pilot_is_on; /* set, if we are on channel 19. also used to switch back on exit */
char paging_file[256]; /* if set, write to given file to switch to channel 19 or back */
char paging_on[256]; /* what to write to switch to channel 19 */
char paging_off[256]; /* what to write to switch back */
int paging_is_on; /* set, if we are on channel 19. also used to switch back on exit */
/* all bnetz states */
enum bnetz_state state; /* main state of sender */
@ -100,7 +100,7 @@ typedef struct bnetz {
double bnetz_kanal2freq(int kanal, int unterband);
int bnetz_init(void);
int bnetz_create(int kanal, const char *audiodev, int samplerate, double rx_gain, int gfs, 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_factor, const char *pilot);
int bnetz_create(int kanal, const char *audiodev, int samplerate, double rx_gain, int gfs, 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_factor, const char *paging);
void bnetz_destroy(sender_t *sender);
void bnetz_loss_indication(bnetz_t *bnetz);
void bnetz_receive_tone(bnetz_t *bnetz, int bit);

View File

@ -36,8 +36,8 @@
#include "ansage.h"
int gfs = 2;
int num_pilot = 0;
const char *pilot[MAX_SENDER] = { "tone" };
int num_paging = 0;
const char *paging[MAX_SENDER] = { "tone" };
double lossdetect = 0;
void print_help(const char *arg0)
@ -53,7 +53,7 @@ void print_help(const char *arg0)
printf(" Set to 19 in order to make the phone transmit at 100 mW instead of\n");
printf(" full 15 Watts. If supported, the phone uses the channel with low power\n");
printf(" (Kanal kleiner Leistung).\n");
printf(" -P --pilot tone | notone | positive | negative | <file>=<on>:<off>\n");
printf(" -P --paging tone | notone | positive | negative | <file>=<on>:<off>\n");
printf(" Send a tone, give a signal or write to a file when switching to\n");
printf(" channel 19. (paging the phone).\n");
printf(" 'tone', 'positive', 'negative' is sent on second audio channel.\n");
@ -63,7 +63,7 @@ void print_help(const char *arg0)
printf(" 'negative' sends a negative signal for channel 19, else positive.\n");
printf(" Example: /sys/class/gpio/gpio17/value=1:0 writes a '1' to\n");
printf(" /sys/class/gpio/gpio17/value to switching to channel 19 and a '0' to\n");
printf(" switch back. (default = %s)\n", pilot[0]);
printf(" switch back. (default = %s)\n", paging[0]);
printf(" -L --loss <volume>\n");
printf(" Detect loss of carrier by detecting steady noise above given volume in\n");
printf(" percent. (disabled by default)\n");
@ -79,7 +79,7 @@ static int handle_options(int argc, char **argv)
static struct option long_options_special[] = {
{"gfs", 1, 0, 'G'},
{"pilot", 1, 0, 'P'},
{"paging", 1, 0, 'P'},
{"loss", 1, 0, 'L'},
{0, 0, 0, 0},
};
@ -109,7 +109,7 @@ static int handle_options(int argc, char **argv)
skip_args += 2;
break;
case 'P':
OPT_ARRAY(num_pilot, pilot, strdup(optarg))
OPT_ARRAY(num_paging, paging, strdup(optarg))
skip_args += 2;
break;
case 'L':
@ -159,10 +159,10 @@ int main(int argc, char *argv[])
fprintf(stderr, "You need to specify as many sound devices as you have channels.\n");
exit(0);
}
if (num_kanal == 1 && num_pilot == 0)
num_pilot = 1; /* use defualt */
if (num_kanal != num_pilot) {
fprintf(stderr, "You need to specify as many pilot tone settings as you have channels.\n");
if (num_kanal == 1 && num_paging == 0)
num_paging = 1; /* use defualt */
if (num_kanal != num_paging) {
fprintf(stderr, "You need to specify as many paging tone settings as you have channels.\n");
exit(0);
}
@ -187,13 +187,13 @@ int main(int argc, char *argv[])
/* create transceiver instance */
for (i = 0; i < num_kanal; i++) {
rc = bnetz_create(kanal[i], audiodev[i], samplerate, rx_gain, gfs, do_pre_emphasis, do_de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, loopback, (double)lossdetect / 100.0, pilot[i]);
rc = bnetz_create(kanal[i], audiodev[i], samplerate, rx_gain, gfs, do_pre_emphasis, do_de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, loopback, (double)lossdetect / 100.0, paging[i]);
if (rc < 0) {
fprintf(stderr, "Failed to create \"Sender\" instance. Quitting!\n");
goto fail;
}
printf("Base station for channel %d ready, please tune transmitter to %.3f MHz and receiver " "to %.3f MHz.\n", kanal[i], bnetz_kanal2freq(kanal[i], 0) / 1e6, bnetz_kanal2freq(kanal[i], 1) / 1e6);
printf("To call phone, switch transmitter (using pilot signal) to %.3f MHz.\n", bnetz_kanal2freq(19, 0) / 1e6);
printf("To call phone, switch transmitter (using paging signal) to %.3f MHz.\n", bnetz_kanal2freq(19, 0) / 1e6);
}
main_common(&quit, latency, interval, NULL);

View File

@ -274,7 +274,7 @@ int cnetz_create(int kanal, enum cnetz_chan_type chan_type, const char *audiodev
/* init general part of transceiver */
/* do not enable emphasis, since it is done by cnetz code, not by common sender code */
rc = sender_create(&cnetz->sender, kanal, cnetz_kanal2freq(kanal, 0), cnetz_kanal2freq(kanal, 1), audiodev, samplerate, rx_gain, 0, 0, write_rx_wave, write_tx_wave, read_rx_wave, loopback, 0, PILOT_SIGNAL_NONE);
rc = sender_create(&cnetz->sender, kanal, cnetz_kanal2freq(kanal, 0), cnetz_kanal2freq(kanal, 1), audiodev, samplerate, rx_gain, 0, 0, write_rx_wave, write_tx_wave, read_rx_wave, loopback, 0, PAGING_SIGNAL_NONE);
if (rc < 0) {
PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to init transceiver process!\n");
goto error;

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -334,7 +334,7 @@ int nmt_create(int channel, enum nmt_chan_type chan_type, const char *audiodev,
PDEBUG(DNMT, DEBUG_DEBUG, "Creating 'NMT' instance for channel = %d (sample rate %d).\n", channel, samplerate);
/* init general part of transceiver */
rc = sender_create(&nmt->sender, channel, nmt_channel2freq(channel, 0), nmt_channel2freq(channel, 1), audiodev, samplerate, rx_gain, pre_emphasis, de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, loopback, 0, PILOT_SIGNAL_NONE);
rc = sender_create(&nmt->sender, channel, nmt_channel2freq(channel, 0), nmt_channel2freq(channel, 1), audiodev, samplerate, rx_gain, pre_emphasis, de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, loopback, 0, PAGING_SIGNAL_NONE);
if (rc < 0) {
PDEBUG(DNMT, DEBUG_ERROR, "Failed to init transceiver process!\n");
goto error;